summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--.gitattributes14
-rw-r--r--makefile7
-rw-r--r--src/emu/cpu/cpu.mak66
-rw-r--r--src/emu/cpu/drcbec.c1806
-rw-r--r--src/emu/cpu/drcbeut.c673
-rw-r--r--src/emu/cpu/drcbeut.h192
-rw-r--r--src/emu/cpu/drcbex64.c7680
-rw-r--r--src/emu/cpu/drcbex86.c7418
-rw-r--r--src/emu/cpu/drccache.c418
-rw-r--r--src/emu/cpu/drccache.h107
-rw-r--r--src/emu/cpu/drcfe.c4
-rw-r--r--src/emu/cpu/drcfe.h19
-rw-r--r--src/emu/cpu/drcuml.c858
-rw-r--r--src/emu/cpu/drcuml.h418
-rw-r--r--src/emu/cpu/drcumld.c453
-rw-r--r--src/emu/cpu/drcumld.h30
-rw-r--r--src/emu/cpu/drcumlsh.h409
-rw-r--r--src/emu/cpu/mips/mdrc64.c5730
-rw-r--r--src/emu/cpu/mips/mdrcold.c4872
-rw-r--r--src/emu/cpu/mips/mips3.c9
-rw-r--r--src/emu/cpu/mips/mips3.h65
-rw-r--r--src/emu/cpu/mips/mips3com.c78
-rw-r--r--src/emu/cpu/mips/mips3drc.c3720
-rw-r--r--src/emu/cpu/mips/mips3dsm.c2
-rw-r--r--src/emu/cpu/mips/mips3fe.c9
-rw-r--r--src/emu/cpu/mips/mips3fe.h2
-rw-r--r--src/emu/cpu/mips/r3000.c1
-rw-r--r--src/emu/cpu/x86emit.h39
-rw-r--r--src/emu/video/voodoo.c5
29 files changed, 23886 insertions, 11218 deletions
diff --git a/.gitattributes b/.gitattributes
index e2e00f22e37..00d5bb9874e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -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
diff --git a/makefile b/makefile
index b664c4a1623..5b162f5a2da 100644
--- a/makefile
+++ b/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
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak
index cabf78f27dc..589169f9238 100644
--- a/src/emu/cpu/cpu.mak
+++ b/src/emu/cpu/cpu.mak
@@ -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 \
+DRCDEPS += \
+ $(CPUSRC)/x86emit.h \
+ $(CPUSRC)/x86drc.c \
+ $(CPUSRC)/x86drc.h \
-$(DRCOBJ): $(DRCDEPS)
+DEFS += -DNATIVE_DRC=drcbe_x86_be_interface
endif
+endif
+
+
+$(DRCOBJ): $(DRCDEPS)
+
#-------------------------------------------------
@@ -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 \
diff --git a/src/emu/cpu/drcbec.c b/src/emu/cpu/drcbec.c
new file mode 100644
index 00000000000..930bb2b9c30
--- /dev/null
+++ b/src/emu/cpu/drcbec.c
@@ -0,0 +1,1806 @@
+/***************************************************************************
+
+ drcbec.c
+
+ Interpreted C core back-end 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.
+
+***************************************************************************/
+
+#include "drcuml.h"
+#include "drcbeut.h"
+#include "eminline.h"
+#include "debugger.h"
+#include <math.h>
+
+#ifdef _MSC_VER
+#include <float.h>
+#endif
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* define a bit to match each possible condition, starting at bit 12 */
+#define ZBIT (0x1000 << (DRCUML_COND_Z & 15))
+#define NZBIT (0x1000 << (DRCUML_COND_NZ & 15))
+#define SBIT (0x1000 << (DRCUML_COND_S & 15))
+#define NSBIT (0x1000 << (DRCUML_COND_NS & 15))
+#define CBIT (0x1000 << (DRCUML_COND_C & 15))
+#define NCBIT (0x1000 << (DRCUML_COND_NC & 15))
+#define VBIT (0x1000 << (DRCUML_COND_V & 15))
+#define NVBIT (0x1000 << (DRCUML_COND_NV & 15))
+#define UBIT (0x1000 << (DRCUML_COND_U & 15))
+#define NUBIT (0x1000 << (DRCUML_COND_NU & 15))
+#define ABIT (0x1000 << (DRCUML_COND_A & 15))
+#define AEBIT (0x1000 << (DRCUML_COND_AE & 15))
+#define BBIT (0x1000 << (DRCUML_COND_B & 15))
+#define BEBIT (0x1000 << (DRCUML_COND_BE & 15))
+#define GBIT (0x1000 << (DRCUML_COND_G & 15))
+#define GEBIT (0x1000 << (DRCUML_COND_GE & 15))
+#define LBIT (0x1000 << (DRCUML_COND_L & 15))
+#define LEBIT (0x1000 << (DRCUML_COND_LE & 15))
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* opcode format:
+
+ bits 31..28 == number of words following the opcode itself (0-15)
+ bits 27..12 == bitmask specify which condition code we care about
+ bits 11.. 2 == opcode
+ bit 1 == flags/condition summary (0 if no condition/flags, 1 otherwise)
+ bit 0 == operation size (0=32-bit, 1=64-bit)
+*/
+
+/* build a short opcode from the raw opcode and size */
+#define MAKE_OPCODE_SHORT(op, size, condflags) \
+ ((((size) == 8) << 0) | (((condflags) != 0) << 1) | ((op) << 2))
+
+/* build a full opcode from the raw opcode, size, condition/flags, and immediate count */
+#define MAKE_OPCODE_FULL(op, size, condflags, pwords) \
+ (MAKE_OPCODE_SHORT(op, size, condflags) | ((condflags & 0x80) ? (0x1000 << ((condflags) & 15)) : 0) | ((pwords) << 28))
+
+/* extract various parts of the opcode */
+#define OPCODE_GET_SHORT(op) ((op) & 0xfff)
+#define OPCODE_PASS_CONDITION(op,f) (((op) & condition_map[f]) != 0)
+#define OPCODE_FAIL_CONDITION(op,f) (((op) & condition_map[f]) == 0)
+#define OPCODE_GET_PWORDS(op) ((op) >> 28)
+
+/* shorthand for accessing parameters in the instruction stream */
+#define PARAM0 (*inst[0].puint32)
+#define PARAM1 (*inst[1].puint32)
+#define PARAM2 (*inst[2].puint32)
+#define PARAM3 (*inst[3].puint32)
+
+#define DPARAM0 (*inst[0].puint64)
+#define DPARAM1 (*inst[1].puint64)
+#define DPARAM2 (*inst[2].puint64)
+#define DPARAM3 (*inst[3].puint64)
+
+#define FSPARAM0 (*inst[0].pfloat)
+#define FSPARAM1 (*inst[1].pfloat)
+#define FSPARAM2 (*inst[2].pfloat)
+#define FSPARAM3 (*inst[3].pfloat)
+
+#define FDPARAM0 (*inst[0].pdouble)
+#define FDPARAM1 (*inst[1].pdouble)
+#define FDPARAM2 (*inst[2].pdouble)
+#define FDPARAM3 (*inst[3].pdouble)
+
+/* compute C and V flags for 32-bit add/subtract */
+#define FLAGS32_C_ADD(a,b) ((UINT32)~(a) < (UINT32)(b))
+#define FLAGS32_C_SUB(a,b) ((UINT32)(b) > (UINT32)(a))
+#define FLAGS32_V_SUB(r,a,b) (((((a) ^ (b)) & ((a) ^ (r))) >> 30) & DRCUML_FLAG_V)
+#define FLAGS32_V_ADD(r,a,b) (((~((a) ^ (b)) & ((a) ^ (r))) >> 30) & DRCUML_FLAG_V)
+
+/* compute N and Z flags for 32-bit operations */
+#define FLAGS32_NZ(v) ((((v) >> 28) & DRCUML_FLAG_S) | (((UINT32)(v) == 0) << 2))
+#define FLAGS32_NZCV_ADD(r,a,b) (FLAGS32_NZ(r) | FLAGS32_C_ADD(a,b) | FLAGS32_V_ADD(r,a,b))
+#define FLAGS32_NZCV_SUB(r,a,b) (FLAGS32_NZ(r) | FLAGS32_C_SUB(a,b) | FLAGS32_V_SUB(r,a,b))
+
+/* compute C and V flags for 64-bit add/subtract */
+#define FLAGS64_C_ADD(a,b) ((UINT64)~(a) < (UINT64)(b))
+#define FLAGS64_C_SUB(a,b) ((UINT64)(b) > (UINT64)(a))
+#define FLAGS64_V_SUB(r,a,b) (((((a) ^ (b)) & ((a) ^ (r))) >> 62) & DRCUML_FLAG_V)
+#define FLAGS64_V_ADD(r,a,b) (((~((a) ^ (b)) & ((a) ^ (r))) >> 62) & DRCUML_FLAG_V)
+
+/* compute N and Z flags for 64-bit operations */
+#define FLAGS64_NZ(v) ((((v) >> 60) & DRCUML_FLAG_S) | (((UINT64)(v) == 0) << 2))
+#define FLAGS64_NZCV_ADD(r,a,b) (FLAGS64_NZ(r) | FLAGS64_C_ADD(a,b) | FLAGS64_V_ADD(r,a,b))
+#define FLAGS64_NZCV_SUB(r,a,b) (FLAGS64_NZ(r) | FLAGS64_C_SUB(a,b) | FLAGS64_V_SUB(r,a,b))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* internal backend-specific state */
+struct _drcbe_state
+{
+ drcuml_state * drcuml; /* pointer back to our owner */
+ drccache * cache; /* pointer to the cache */
+ drcuml_machine_state state; /* state of the machine */
+ drchash_state * hash; /* hash table state */
+ drcmap_state * map; /* code map */
+ drclabel_list * labels; /* label list */
+};
+
+
+/* union to simplify accessing data via the instruction stream */
+typedef union _drcbec_instruction drcbec_instruction;
+union _drcbec_instruction
+{
+ UINT32 i;
+ void * v;
+ char * c;
+ UINT8 * puint8;
+ INT8 * pint8;
+ UINT16 * puint16;
+ INT16 * pint16;
+ UINT32 * puint32;
+ INT32 * pint32;
+ UINT64 * puint64;
+ INT64 * pint64;
+ float * pfloat;
+ double * pdouble;
+ void (*cfunc)(void *);
+ const drcuml_codehandle *handle;
+ const drcbec_instruction *inst;
+ const drcbec_instruction **pinst;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* primary back-end callbacks */
+static drcbe_state *drcbec_alloc(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
+static void drcbec_free(drcbe_state *drcbe);
+static void drcbec_reset(drcbe_state *drcbe);
+static int drcbec_execute(drcbe_state *state, drcuml_codehandle *entry);
+static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
+static int drcbec_hash_exists(drcbe_state *state, UINT32 mode, UINT32 pc);
+
+/* private helper functions */
+static void output_parameter(drcbe_state *drcbe, drcbec_instruction **dstptr, void **immedptr, int size, int immedsize, const drcuml_parameter *param);
+static void fixup_label(void *parameter, drccodeptr labelcodeptr);
+static int dmulu(UINT64 *dstlo, UINT64 *dsthi, UINT64 src1, UINT64 src2, int flags);
+static int dmuls(UINT64 *dstlo, UINT64 *dsthi, INT64 src1, INT64 src2, int flags);
+
+
+
+/***************************************************************************
+ TABLES
+***************************************************************************/
+
+static const UINT32 condition_map[] =
+{
+ /* ..... */ NCBIT | NVBIT | NZBIT | NSBIT | NUBIT | ABIT | AEBIT | GBIT | GEBIT,
+ /* ....C */ CBIT | NVBIT | NZBIT | NSBIT | NUBIT | BEBIT | BBIT | GBIT | GEBIT,
+ /* ...V. */ NCBIT | VBIT | NZBIT | NSBIT | NUBIT | ABIT | AEBIT | LEBIT | LBIT,
+ /* ...VC */ CBIT | VBIT | NZBIT | NSBIT | NUBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* ..Z.. */ NCBIT | NVBIT | ZBIT | NSBIT | NUBIT | BEBIT | AEBIT | LEBIT | GEBIT,
+ /* ..Z.C */ CBIT | NVBIT | ZBIT | NSBIT | NUBIT | BEBIT | BBIT | LEBIT | GEBIT,
+ /* ..ZV. */ NCBIT | VBIT | ZBIT | NSBIT | NUBIT | BEBIT | AEBIT | LEBIT | LBIT,
+ /* ..ZVC */ CBIT | VBIT | ZBIT | NSBIT | NUBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* .S... */ NCBIT | NVBIT | NZBIT | SBIT | NUBIT | ABIT | AEBIT | LEBIT | LBIT,
+ /* .S..C */ CBIT | NVBIT | NZBIT | SBIT | NUBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* .S.V. */ NCBIT | VBIT | NZBIT | SBIT | NUBIT | ABIT | AEBIT | GBIT | GEBIT,
+ /* .S.VC */ CBIT | VBIT | NZBIT | SBIT | NUBIT | BEBIT | BBIT | GBIT | GEBIT,
+ /* .SZ.. */ NCBIT | NVBIT | ZBIT | SBIT | NUBIT | BEBIT | AEBIT | LEBIT | LBIT,
+ /* .SZ.C */ CBIT | NVBIT | ZBIT | SBIT | NUBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* .SZV. */ NCBIT | VBIT | ZBIT | SBIT | NUBIT | BEBIT | AEBIT | LEBIT | GEBIT,
+ /* .SZVC */ CBIT | VBIT | ZBIT | SBIT | NUBIT | BEBIT | BBIT | LEBIT | GEBIT,
+ /* U.... */ NCBIT | NVBIT | NZBIT | NSBIT | UBIT | ABIT | AEBIT | GBIT | GEBIT,
+ /* U...C */ CBIT | NVBIT | NZBIT | NSBIT | UBIT | BEBIT | BBIT | GBIT | GEBIT,
+ /* U..V. */ NCBIT | VBIT | NZBIT | NSBIT | UBIT | ABIT | AEBIT | LEBIT | LBIT,
+ /* U..VC */ CBIT | VBIT | NZBIT | NSBIT | UBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* U.Z.. */ NCBIT | NVBIT | ZBIT | NSBIT | UBIT | BEBIT | AEBIT | LEBIT | GEBIT,
+ /* U.Z.C */ CBIT | NVBIT | ZBIT | NSBIT | UBIT | BEBIT | BBIT | LEBIT | GEBIT,
+ /* U.ZV. */ NCBIT | VBIT | ZBIT | NSBIT | UBIT | BEBIT | AEBIT | LEBIT | LBIT,
+ /* U.ZVC */ CBIT | VBIT | ZBIT | NSBIT | UBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* US... */ NCBIT | NVBIT | NZBIT | SBIT | UBIT | ABIT | AEBIT | LEBIT | LBIT,
+ /* US..C */ CBIT | NVBIT | NZBIT | SBIT | UBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* US.V. */ NCBIT | VBIT | NZBIT | SBIT | UBIT | ABIT | AEBIT | GBIT | GEBIT,
+ /* US.VC */ CBIT | VBIT | NZBIT | SBIT | UBIT | BEBIT | BBIT | GBIT | GEBIT,
+ /* USZ.. */ NCBIT | NVBIT | ZBIT | SBIT | UBIT | BEBIT | AEBIT | LEBIT | LBIT,
+ /* USZ.C */ CBIT | NVBIT | ZBIT | SBIT | UBIT | BEBIT | BBIT | LEBIT | LBIT,
+ /* USZV. */ NCBIT | VBIT | ZBIT | SBIT | UBIT | BEBIT | AEBIT | LEBIT | GEBIT,
+ /* USZVC */ CBIT | VBIT | ZBIT | SBIT | UBIT | BEBIT | BBIT | LEBIT | GEBIT
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static UINT64 immediate_zero = 0;
+
+const drcbe_interface drcbe_c_be_interface =
+{
+ drcbec_alloc,
+ drcbec_free,
+ drcbec_reset,
+ drcbec_execute,
+ drcbec_generate,
+ drcbec_hash_exists
+};
+
+
+
+/***************************************************************************
+ BACKEND CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ drcbec_alloc - allocate back-end-specific
+ state
+-------------------------------------------------*/
+
+static drcbe_state *drcbec_alloc(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits)
+{
+ /* allocate space in the cache for our state */
+ drcbe_state *drcbe = drccache_memory_alloc(cache, sizeof(*drcbe));
+ if (drcbe == NULL)
+ return NULL;
+ memset(drcbe, 0, sizeof(*drcbe));
+
+ /* remember our pointers */
+ drcbe->drcuml = drcuml;
+ drcbe->cache = cache;
+
+ /* allocate hash tables */
+ drcbe->hash = drchash_alloc(cache, modes, addrbits, ignorebits);
+ if (drcbe->hash == NULL)
+ return NULL;
+
+ /* allocate code map */
+ drcbe->map = drcmap_alloc(cache, 0);
+ if (drcbe->map == NULL)
+ return NULL;
+
+ /* allocate a label tracker */
+ drcbe->labels = drclabel_list_alloc(cache);
+ if (drcbe->labels == NULL)
+ return NULL;
+
+ return drcbe;
+}
+
+
+/*-------------------------------------------------
+ drcbec_free - free back-end specific state
+-------------------------------------------------*/
+
+static void drcbec_free(drcbe_state *drcbe)
+{
+}
+
+
+/*-------------------------------------------------
+ drcbec_reset - reset back-end specific state
+-------------------------------------------------*/
+
+static void drcbec_reset(drcbe_state *drcbe)
+{
+ /* reset our hash tables */
+ drchash_reset(drcbe->hash);
+ drchash_set_default_codeptr(drcbe->hash, NULL);
+}
+
+
+/*-------------------------------------------------
+ drcbec_generate - generate code
+-------------------------------------------------*/
+
+static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst)
+{
+ drccodeptr *cachetop;
+ drcbec_instruction *base;
+ drcbec_instruction *dst;
+ int inum;
+
+ /* tell all of our utility objects that a block is beginning */
+ drchash_block_begin(drcbe->hash, block, instlist, numinst);
+ drclabel_block_begin(drcbe->labels, block);
+ drcmap_block_begin(drcbe->map, block);
+
+ /* begin codegen; fail if we can't */
+ cachetop = drccache_begin_codegen(drcbe->cache, numinst * sizeof(drcbec_instruction) * 4);
+ if (cachetop == NULL)
+ drcuml_block_abort(block);
+
+ /* compute the base by aligning the cache top to an even multiple of drcbec_instruction */
+ base = (drcbec_instruction *)(((FPTR)*cachetop + sizeof(drcbec_instruction) - 1) & ~(sizeof(drcbec_instruction) - 1));
+ dst = base;
+
+ /* generate code by copying the instructions and extracting immediates */
+ for (inum = 0; inum < numinst; inum++)
+ {
+ const drcuml_instruction *inst = &instlist[inum];
+ drcuml_instruction modified_inst;
+ int immedsize, immedbytes, immedwords, pnum;
+ void *immed;
+
+ /* handle most instructions generally, but a few special cases */
+ switch (inst->opcode)
+ {
+ /* when we hit a HANDLE opcode, register the current pointer for the handle */
+ case DRCUML_OP_HANDLE:
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_MEMORY);
+ drcuml_handle_set_codeptr((drcuml_codehandle *)(FPTR)inst->param[0].value, (drccodeptr)dst);
+ break;
+
+ /* when we hit a HASH opcode, register the current pointer for the mode/PC */
+ case DRCUML_OP_HASH:
+ /* we already verified the parameter count and types above */
+ drchash_set_codeptr(drcbe->hash, inst->param[0].value, inst->param[1].value, (drccodeptr)dst);
+ break;
+
+ /* when we hit a LABEL opcode, register the current pointer for the label */
+ case DRCUML_OP_LABEL:
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
+ drclabel_set_codeptr(drcbe->labels, inst->param[0].value, (drccodeptr)dst);
+ break;
+
+ /* ignore COMMENT opcodes */
+ case DRCUML_OP_COMMENT:
+ break;
+
+ /* when we hit a MAPVAR opcode, log the change for the current PC */
+ case DRCUML_OP_MAPVAR:
+ assert(inst->numparams == 2);
+ assert(inst->param[0].type == DRCUML_PTYPE_MAPVAR);
+ assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
+ drcmap_set_value(drcbe->map, (drccodeptr)dst, inst->param[0].value, inst->param[1].value);
+ break;
+
+ /* JMP instructions need to resolve their labels */
+ case DRCUML_OP_JMP:
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
+ (dst++)->i = MAKE_OPCODE_FULL(inst->opcode, inst->size, inst->condflags, 1);
+ dst->inst = (drcbec_instruction *)drclabel_get_codeptr(drcbe->labels, inst->param[0].value, fixup_label, dst);
+ dst++;
+ break;
+
+ /* generically handle everything else */
+ default:
+
+ /* for RECOVER opcodes, we need to fixup the second parameter into an immediate */
+ if (inst->opcode == DRCUML_OP_RECOVER)
+ {
+ assert(inst->param[1].type == DRCUML_PTYPE_MAPVAR);
+ modified_inst = *inst;
+ modified_inst.param[1].type = DRCUML_PTYPE_IMMEDIATE;
+ inst = &modified_inst;
+ }
+
+ /* determine the maximum size of an immediate; mostly this is just the instruction size */
+ immedsize = inst->size;
+ if (inst->opcode == DRCUML_OP_FFRFD || inst->opcode == DRCUML_OP_FFRI8)
+ immedsize = 8;
+
+ /* count how many bytes of immediates we need */
+ immedbytes = 0;
+ for (pnum = 0; pnum < inst->numparams; pnum++)
+ if (inst->param[pnum].type == DRCUML_PTYPE_MAPVAR ||
+ (inst->param[pnum].type == DRCUML_PTYPE_IMMEDIATE && inst->param[pnum].value != 0))
+ immedbytes += immedsize;
+
+ /* compute how many instruction words we need for that */
+ immedwords = (immedbytes + sizeof(drcbec_instruction) - 1) / sizeof(drcbec_instruction);
+
+ /* first item is the opcode, size, condition flags and length */
+ (dst++)->i = MAKE_OPCODE_FULL(inst->opcode, inst->size, inst->condflags, inst->numparams + immedwords);
+
+ /* immediates start after parameters */
+ immed = dst + inst->numparams;
+
+ /* output each of the parameters */
+ for (pnum = 0; pnum < inst->numparams; pnum++)
+ output_parameter(drcbe, &dst, &immed, inst->size, immedsize, &inst->param[pnum]);
+
+ /* point past the end of the immediates */
+ dst += immedwords;
+ break;
+ }
+ }
+
+ /* complete codegen */
+ *cachetop = (drccodeptr)dst;
+ drccache_end_codegen(drcbe->cache);
+
+ /* tell all of our utility objects that the block is finished */
+ drchash_block_end(drcbe->hash, block);
+ drclabel_block_end(drcbe->labels, block);
+ drcmap_block_end(drcbe->map, block);
+}
+
+
+/*-------------------------------------------------
+ drcbec_hash_exists - return true if the
+ given mode/pc exists in the hash table
+-------------------------------------------------*/
+
+static int drcbec_hash_exists(drcbe_state *state, UINT32 mode, UINT32 pc)
+{
+ return drchash_code_exists(state->hash, mode, pc);
+}
+
+
+
+/***************************************************************************
+ BACK-END EXECUTION
+***************************************************************************/
+
+/*-------------------------------------------------
+ drcbec_execute - execute a block of code
+ registered at the given mode/pc
+-------------------------------------------------*/
+
+static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
+{
+ const drcbec_instruction *callstack[32];
+ const drcbec_instruction *newinst;
+ const drcbec_instruction *inst;
+ UINT32 temp32;
+ UINT64 temp64;
+ int shift;
+ UINT8 flags = 0;
+ UINT8 sp = 0;
+
+ /* get the entry point */
+ inst = (const drcbec_instruction *)drcuml_handle_codeptr(entry);
+ assert_in_cache(drcbe->cache, inst);
+
+ /* loop while we have cycles */
+ while (TRUE)
+ {
+ UINT32 opcode = (inst++)->i;
+ switch (OPCODE_GET_SHORT(opcode))
+ {
+ /* ----------------------- Control Flow Operations ----------------------- */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_HANDLE, 4, 0): /* HANDLE handle */
+ case MAKE_OPCODE_SHORT(DRCUML_OP_HASH, 4, 0): /* HASH mode,pc */
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LABEL, 4, 0): /* LABEL imm */
+ case MAKE_OPCODE_SHORT(DRCUML_OP_COMMENT, 4, 0): /* COMMENT string */
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MAPVAR, 4, 0): /* MAPVAR mapvar,value */
+
+ /* these opcodes should be processed at compile-time only */
+ fatalerror("Unexpected opcode");
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DEBUG, 4, 0): /* DEBUG pc */
+ CALL_DEBUGGER(PARAM0);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_HASHJMP, 4, 0): /* HASHJMP mode,pc,handle */
+ sp = 0;
+ newinst = (const drcbec_instruction *)drchash_get_codeptr(drcbe->hash, PARAM0, PARAM1);
+ if (newinst == NULL)
+ {
+ assert(sp < ARRAY_LENGTH(callstack));
+ drcbe->state.exp.l = PARAM1;
+ newinst = (const drcbec_instruction *)drcuml_handle_codeptr(inst[2].handle);
+ callstack[sp++] = inst;
+ }
+ assert_in_cache(drcbe->cache, newinst);
+ inst = newinst;
+ continue;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_EXIT, 4, 1): /* EXIT src1[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_EXIT, 4, 0):
+ return PARAM0;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_JMP, 4, 1): /* JMP imm[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_JMP, 4, 0):
+ newinst = inst[0].inst;
+ assert_in_cache(drcbe->cache, newinst);
+ inst = newinst;
+ continue;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_CALLH, 4, 1): /* CALLH handle[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_CALLH, 4, 0):
+ assert(sp < ARRAY_LENGTH(callstack));
+ newinst = (const drcbec_instruction *)drcuml_handle_codeptr(inst[0].handle);
+ assert_in_cache(drcbe->cache, newinst);
+ callstack[sp++] = inst + OPCODE_GET_PWORDS(opcode);
+ inst = newinst;
+ continue;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RET, 4, 1): /* RET [c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RET, 4, 0):
+ assert(sp > 0);
+ newinst = callstack[--sp];
+ assert_in_cache(drcbe->cache, newinst);
+ inst = newinst;
+ continue;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_EXH, 4, 1): /* EXH handle,param[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_EXH, 4, 0):
+ assert(sp < ARRAY_LENGTH(callstack));
+ newinst = (const drcbec_instruction *)drcuml_handle_codeptr(inst[0].handle);
+ assert_in_cache(drcbe->cache, newinst);
+ drcbe->state.exp.l = PARAM1;
+ callstack[sp++] = inst;
+ inst = newinst;
+ continue;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_CALLC, 4, 1): /* CALLC func,ptr[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_CALLC, 4, 0):
+ (*inst[0].cfunc)(inst[1].v);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RECOVER, 4, 0): /* RECOVER dst,mapvar */
+ assert(sp > 0);
+ PARAM0 = drcmap_get_value(drcbe->map, (drccodeptr)callstack[0], PARAM1);
+ break;
+
+
+ /* ----------------------- Internal Register Operations ----------------------- */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SETFMOD, 4, 0): /* SETFMOD src */
+ drcbe->state.fmod = PARAM0;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_GETFMOD, 4, 0): /* GETFMOD dst */
+ PARAM0 = drcbe->state.fmod;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_GETEXP, 4, 0): /* GETEXP dst */
+ PARAM0 = drcbe->state.exp.l;
+ break;
+
+
+ /* ----------------------- 32-Bit Integer Operations ----------------------- */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1U, 4, 0): /* LOAD1U dst,base,index */
+ PARAM0 = inst[1].puint8[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1S, 4, 0): /* LOAD1S dst,base,index */
+ PARAM0 = inst[1].pint8[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2U, 4, 0): /* LOAD2U dst,base,index */
+ PARAM0 = inst[1].puint16[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2S, 4, 0): /* LOAD2S dst,base,index */
+ PARAM0 = inst[1].pint16[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4U, 4, 0): /* LOAD4U dst,base,index */
+ PARAM0 = inst[1].puint32[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE1, 4, 0): /* STORE1 dst,base,index */
+ inst[0].puint8[PARAM1] = PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE2, 4, 0): /* STORE2 dst,base,index */
+ inst[0].puint16[PARAM1] = PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE4, 4, 0): /* STORE4 dst,base,index */
+ inst[0].puint32[PARAM1] = PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ1U, 4, 0): /* READ1U dst,space,src1 */
+ PARAM0 = (UINT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ1S, 4, 0): /* READ1S dst,space,src1 */
+ PARAM0 = (INT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ2U, 4, 0): /* READ2U dst,space,src1 */
+ PARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ2S, 4, 0): /* READ2S dst,space,src1 */
+ PARAM0 = (INT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ2M, 4, 0): /* READ2M dst,space,src1,mask */
+ PARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word_masked)(PARAM2, PARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ4U, 4, 0): /* READ4U dst,space,src1 */
+ PARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ4M, 4, 0): /* READ4M dst,space,src1,mask */
+ PARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword_masked)(PARAM2, PARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE1, 4, 0): /* WRITE1 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_byte)(PARAM1, PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE2, 4, 0): /* WRITE2 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_word)(PARAM1, PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT2M, 4, 0): /* WRIT2M space,dst,mask,src1 */
+ (*active_address_space[PARAM0].accessors->write_word_masked)(PARAM1, PARAM2, PARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE4, 4, 0): /* WRITE4 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_dword)(PARAM1, PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT4M, 4, 0): /* WRIT4M space,dst,mask,src1 */
+ (*active_address_space[PARAM0].accessors->write_dword_masked)(PARAM1, PARAM2, PARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FLAGS, 4, 0): /* FLAGS dst,mask,table */
+ PARAM0 = (PARAM0 & ~PARAM1) | (inst[2].puint32[flags & 0x1f] & PARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MOV, 4, 1): /* MOV dst,src[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MOV, 4, 0):
+ PARAM0 = PARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT1, 4, 0): /* ZEXT1 dst,src */
+ PARAM0 = (UINT8)PARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT2, 4, 0): /* ZEXT2 dst,src */
+ PARAM0 = (UINT16)PARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT1, 4, 0): /* SEXT1 dst,src */
+ PARAM0 = (INT8)PARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT2, 4, 0): /* SEXT2 dst,src */
+ PARAM0 = (INT16)PARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADD, 4, 0): /* ADD dst,src1,src2[,f] */
+ PARAM0 = PARAM1 + PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADD, 4, 1):
+ temp32 = PARAM1 + PARAM2;
+ flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADDC, 4, 0): /* ADDC dst,src1,src2[,f] */
+ PARAM0 = PARAM1 + PARAM2 + (flags & DRCUML_FLAG_C);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADDC, 4, 1):
+ temp32 = PARAM1 + PARAM2 + (flags & DRCUML_FLAG_C);
+ flags = FLAGS32_NZCV_ADD(temp32, PARAM1, PARAM2);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUB, 4, 0): /* SUB dst,src1,src2[,f] */
+ PARAM0 = PARAM1 - PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUB, 4, 1):
+ temp32 = PARAM1 - PARAM2;
+ flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUBB, 4, 0): /* SUBB dst,src1,src2[,f] */
+ PARAM0 = PARAM1 - PARAM2 - (flags & DRCUML_FLAG_C);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUBB, 4, 1):
+ temp32 = PARAM1 - PARAM2 - (flags & DRCUML_FLAG_C);
+ flags = FLAGS32_NZCV_SUB(temp32, PARAM1, PARAM2);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_CMP, 4, 1): /* CMP src1,src2[,f] */
+ temp32 = PARAM0 - PARAM1;
+ flags = FLAGS32_NZCV_SUB(temp32, PARAM0, PARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULU, 4, 0): /* MULU dst,edst,src1,src2[,f] */
+ temp64 = (UINT64)(UINT32)PARAM2 * (UINT64)(UINT32)PARAM3;
+ PARAM1 = temp64 >> 32;
+ PARAM0 = (UINT32)temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULU, 4, 1):
+ temp64 = (UINT64)(UINT32)PARAM2 * (UINT64)(UINT32)PARAM3;
+ flags = FLAGS64_NZ(temp64);
+ PARAM1 = temp64 >> 32;
+ PARAM0 = (UINT32)temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULS, 4, 0): /* MULS dst,edst,src1,src2[,f] */
+ temp64 = (INT64)(INT32)PARAM2 * (INT64)(INT32)PARAM3;
+ PARAM1 = temp64 >> 32;
+ PARAM0 = (UINT32)temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULS, 4, 1):
+ temp64 = (INT64)(INT32)PARAM2 * (INT64)(INT32)PARAM3;
+ flags = FLAGS64_NZ(temp64);
+ PARAM1 = temp64 >> 32;
+ PARAM0 = (UINT32)temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVU, 4, 0): /* DIVU dst,edst,src1,src2[,f] */
+ if (PARAM3 != 0)
+ {
+ temp32 = (UINT32)PARAM2 / (UINT32)PARAM3;
+ PARAM1 = (UINT32)PARAM2 % (UINT32)PARAM3;
+ PARAM0 = temp32;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVU, 4, 1):
+ if (PARAM3 != 0)
+ {
+ temp32 = (UINT32)PARAM2 / (UINT32)PARAM3;
+ PARAM1 = (UINT32)PARAM2 % (UINT32)PARAM3;
+ flags = FLAGS32_NZ(temp32);
+ PARAM0 = temp32;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVS, 4, 0): /* DIVS dst,edst,src1,src2[,f] */
+ if (PARAM3 != 0)
+ {
+ temp32 = (INT32)PARAM2 / (INT32)PARAM3;
+ PARAM1 = (INT32)PARAM2 % (INT32)PARAM3;
+ PARAM0 = temp32;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVS, 4, 1):
+ if (PARAM3 != 0)
+ {
+ temp32 = (INT32)PARAM2 / (INT32)PARAM3;
+ PARAM1 = (INT32)PARAM2 % (INT32)PARAM3;
+ flags = FLAGS32_NZ(temp32);
+ PARAM0 = temp32;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_AND, 4, 0): /* AND dst,src1,src2[,f] */
+ PARAM0 = PARAM1 & PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_AND, 4, 1):
+ temp32 = PARAM1 & PARAM2;
+ flags = FLAGS32_NZ(temp32);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_TEST, 4, 1): /* TEST src1,src2[,f] */
+ temp32 = PARAM0 & PARAM1;
+ flags = FLAGS32_NZ(temp32);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_OR, 4, 0): /* OR dst,src1,src2[,f] */
+ PARAM0 = PARAM1 | PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_OR, 4, 1):
+ temp32 = PARAM1 | PARAM2;
+ flags = FLAGS32_NZ(temp32);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_XOR, 4, 0): /* XOR dst,src1,src2[,f] */
+ PARAM0 = PARAM1 ^ PARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_XOR, 4, 1):
+ temp32 = PARAM1 ^ PARAM2;
+ flags = FLAGS32_NZ(temp32);
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHL, 4, 0): /* SHL dst,src,count[,f] */
+ PARAM0 = PARAM1 << (PARAM2 & 31);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHL, 4, 1):
+ shift = PARAM2 & 31;
+ temp32 = PARAM1 << shift;
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHR, 4, 0): /* SHR dst,src,count[,f] */
+ PARAM0 = PARAM1 >> (PARAM2 & 31);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHR, 4, 1):
+ shift = PARAM2 & 31;
+ temp32 = PARAM1 >> shift;
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SAR, 4, 0): /* SAR dst,src,count[,f] */
+ PARAM0 = (INT32)PARAM1 >> (PARAM2 & 31);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SAR, 4, 1):
+ shift = PARAM2 & 31;
+ temp32 = (INT32)PARAM1 >> shift;
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROL, 4, 0): /* ROL dst,src,count[,f] */
+ shift = PARAM2 & 31;
+ PARAM0 = (PARAM1 << shift) | (PARAM1 >> ((32 - shift) & 31));
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROL, 4, 1):
+ shift = PARAM2 & 31;
+ temp32 = (PARAM1 << shift) | (PARAM1 >> ((32 - shift) & 31));
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROLC, 4, 0): /* ROLC dst,src,count[,f] */
+ shift = PARAM2 & 31;
+ if (shift > 1)
+ PARAM0 = (PARAM1 << shift) | ((flags & DRCUML_FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift));
+ else if (shift == 1)
+ PARAM0 = (PARAM1 << shift) | (flags & DRCUML_FLAG_C);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROLC, 4, 1):
+ shift = PARAM2 & 31;
+ if (shift > 1)
+ temp32 = (PARAM1 << shift) | ((flags & DRCUML_FLAG_C) << (shift - 1)) | (PARAM1 >> (33 - shift));
+ else if (shift == 1)
+ temp32 = (PARAM1 << shift) | (flags & DRCUML_FLAG_C);
+ else
+ temp32 = PARAM1;
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= ((PARAM1 << (shift - 1)) >> 31) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROR, 4, 0): /* ROR dst,src,count[,f] */
+ shift = PARAM2 & 31;
+ PARAM0 = (PARAM1 >> shift) | (PARAM1 << ((32 - shift) & 31));
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROR, 4, 1):
+ shift = PARAM2 & 31;
+ temp32 = (PARAM1 >> shift) | (PARAM1 << ((32 - shift) & 31));
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RORC, 4, 0): /* RORC dst,src,count[,f] */
+ shift = PARAM2 & 31;
+ if (shift > 1)
+ PARAM0 = (PARAM1 >> shift) | (((flags & DRCUML_FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift));
+ else if (shift == 1)
+ PARAM0 = (PARAM1 >> shift) | ((flags & DRCUML_FLAG_C) << 31);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RORC, 4, 1):
+ shift = PARAM2 & 31;
+ if (shift > 1)
+ temp32 = (PARAM1 >> shift) | (((flags & DRCUML_FLAG_C) << 31) >> (shift - 1)) | (PARAM1 << (33 - shift));
+ else if (shift == 1)
+ temp32 = (PARAM1 >> shift) | ((flags & DRCUML_FLAG_C) << 31);
+ else
+ temp32 = PARAM1;
+ flags = FLAGS32_NZ(temp32);
+ if (shift != 0) flags |= (PARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ PARAM0 = temp32;
+ break;
+
+
+ /* ----------------------- 64-Bit Integer Operations ----------------------- */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1U, 8, 0): /* DLOAD1U dst,base,index */
+ DPARAM0 = inst[1].puint8[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1S, 8, 0): /* DLOAD1S dst,base,index */
+ DPARAM0 = inst[1].pint8[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2U, 8, 0): /* DLOAD2U dst,base,index */
+ DPARAM0 = inst[1].puint16[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2S, 8, 0): /* DLOAD2S dst,base,index */
+ DPARAM0 = inst[1].pint16[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4U, 8, 0): /* DLOAD4U dst,base,index */
+ DPARAM0 = inst[1].puint32[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4S, 8, 0): /* DLOAD4S dst,base,index */
+ DPARAM0 = inst[1].pint32[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD8U, 8, 0): /* DLOAD8U dst,base,index */
+ DPARAM0 = inst[1].puint64[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE1, 8, 0): /* DSTORE1 dst,base,index */
+ inst[0].puint8[PARAM1] = DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE2, 8, 0): /* DSTORE2 dst,base,index */
+ inst[0].puint16[PARAM1] = DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE4, 8, 0): /* DSTORE4 dst,base,index */
+ inst[0].puint32[PARAM1] = DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_STORE8, 8, 0): /* DSTORE8 dst,base,index */
+ inst[0].puint64[PARAM1] = DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ1U, 8, 0): /* DREAD1U dst,space,src1 */
+ DPARAM0 = (UINT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ1S, 8, 0): /* DREAD1S dst,space,src1 */
+ DPARAM0 = (INT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ2U, 8, 0): /* DREAD2U dst,space,src1 */
+ DPARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ2S, 8, 0): /* DREAD2S dst,space,src1 */
+ DPARAM0 = (INT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ2M, 8, 0): /* DREAD2M dst,space,src1,mask */
+ DPARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word_masked)(PARAM2, DPARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ4U, 8, 0): /* DREAD4U dst,space,src1 */
+ DPARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ4S, 8, 0): /* DREAD4S dst,space,src1 */
+ DPARAM0 = (INT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ4M, 8, 0): /* DREAD4M dst,space,src1,mask */
+ DPARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword_masked)(PARAM2, DPARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ8U, 8, 0): /* DREAD8U dst,space,src1 */
+ DPARAM0 = (UINT64)(*active_address_space[PARAM1].accessors->read_qword)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_READ8M, 8, 0): /* DREAD8M dst,space,src1,mask */
+ DPARAM0 = (UINT64)(*active_address_space[PARAM1].accessors->read_qword_masked)(PARAM2, DPARAM3);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE1, 8, 0): /* DWRITE1 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_byte)(PARAM1, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE2, 8, 0): /* DWRITE2 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_word)(PARAM1, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT2M, 8, 0): /* DWRIT2M space,dst,mask,src1 */
+ (*active_address_space[PARAM0].accessors->write_word_masked)(PARAM1, DPARAM3, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE4, 8, 0): /* DWRITE4 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_dword)(PARAM1, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT4M, 8, 0): /* DWRIT4M space,dst,mask,src1 */
+ (*active_address_space[PARAM0].accessors->write_dword_masked)(PARAM1, DPARAM3, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE8, 8, 0): /* DWRITE8 space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_qword)(PARAM1, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT8M, 8, 0): /* DWRIT8M space,dst,mask,src1 */
+ (*active_address_space[PARAM0].accessors->write_qword_masked)(PARAM1, DPARAM3, DPARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FLAGS, 8, 0): /* DFLAGS dst,mask,table */
+ DPARAM0 = (DPARAM0 & ~DPARAM1) | (inst[2].puint64[flags & 0x0f] & DPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MOV, 8, 1): /* DMOV dst,src[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MOV, 8, 0):
+ DPARAM0 = DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT1, 8, 0): /* DZEXT1 dst,src */
+ DPARAM0 = (UINT8)DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT2, 8, 0): /* DZEXT2 dst,src */
+ DPARAM0 = (UINT16)DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT4, 8, 0): /* DZEXT4 dst,src */
+ DPARAM0 = (UINT32)DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT1, 8, 0): /* DSEXT1 dst,src */
+ DPARAM0 = (INT8)DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT2, 8, 0): /* DSEXT2 dst,src */
+ DPARAM0 = (INT16)DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT4, 8, 0): /* DSEXT4 dst,src */
+ DPARAM0 = (INT32)DPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADD, 8, 0): /* DADD dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 + DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADD, 8, 1):
+ temp64 = DPARAM1 + DPARAM2;
+ flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADDC, 8, 0): /* DADDC dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 + DPARAM2 + (flags & DRCUML_FLAG_C);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ADDC, 8, 1):
+ temp64 = DPARAM1 + DPARAM2 + (flags & DRCUML_FLAG_C);
+ flags = FLAGS64_NZCV_ADD(temp64, DPARAM1, DPARAM2);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUB, 8, 0): /* DSUB dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 - DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUB, 8, 1):
+ temp64 = DPARAM1 - DPARAM2;
+ flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUBB, 8, 0): /* DSUBB dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 - DPARAM2 - (flags & DRCUML_FLAG_C);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SUBB, 8, 1):
+ temp64 = DPARAM1 - DPARAM2 - (flags & DRCUML_FLAG_C);
+ flags = FLAGS64_NZCV_SUB(temp64, DPARAM1, DPARAM2);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_CMP, 8, 1): /* DCMP src1,src2[,f] */
+ temp64 = DPARAM0 - DPARAM1;
+ flags = FLAGS64_NZCV_SUB(temp64, DPARAM0, DPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULU, 8, 0): /* DMULU dst,edst,src1,src2[,f] */
+ dmulu(inst[0].puint64, inst[1].puint64, DPARAM2, DPARAM3, FALSE);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULU, 8, 1):
+ flags = dmulu(inst[0].puint64, inst[1].puint64, DPARAM2, DPARAM3, TRUE);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULS, 8, 0): /* DMULS dst,edst,src1,src2[,f] */
+ dmuls(inst[0].puint64, inst[1].puint64, DPARAM2, DPARAM3, FALSE);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_MULS, 8, 1):
+ flags = dmuls(inst[0].puint64, inst[1].puint64, DPARAM2, DPARAM3, TRUE);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVU, 8, 0): /* DDIVU dst,edst,src1,src2[,f] */
+ if (DPARAM3 != 0)
+ {
+ temp64 = (UINT64)DPARAM2 / (UINT64)DPARAM3;
+ DPARAM1 = (UINT64)DPARAM2 % (UINT64)DPARAM3;
+ DPARAM0 = temp64;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVU, 8, 1):
+ if (DPARAM3 != 0)
+ {
+ temp64 = (UINT64)DPARAM2 / (UINT64)DPARAM3;
+ DPARAM1 = (UINT64)DPARAM2 % (UINT64)DPARAM3;
+ flags = FLAGS64_NZ(temp64);
+ DPARAM0 = temp64;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVS, 8, 0): /* DDIVS dst,edst,src1,src2[,f] */
+ if (DPARAM3 != 0)
+ {
+ temp64 = (INT64)DPARAM2 / (INT64)DPARAM3;
+ DPARAM1 = (INT64)DPARAM2 % (INT64)DPARAM3;
+ DPARAM0 = temp64;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_DIVS, 8, 1):
+ if (DPARAM3 != 0)
+ {
+ temp64 = (INT64)DPARAM2 / (INT64)DPARAM3;
+ DPARAM1 = (INT64)DPARAM2 % (INT64)DPARAM3;
+ flags = FLAGS64_NZ(temp64);
+ DPARAM0 = temp64;
+ }
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_AND, 8, 0): /* DAND dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 & DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_AND, 8, 1):
+ temp64 = DPARAM1 & DPARAM2;
+ flags = FLAGS64_NZ(temp64);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_TEST, 8, 1): /* DTEST src1,src2[,f] */
+ temp64 = DPARAM1 & DPARAM2;
+ flags = FLAGS64_NZ(temp64);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_OR, 8, 0): /* DOR dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 | DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_OR, 8, 1):
+ temp64 = DPARAM1 | DPARAM2;
+ flags = FLAGS64_NZ(temp64);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_XOR, 8, 0): /* DXOR dst,src1,src2[,f] */
+ DPARAM0 = DPARAM1 ^ DPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_XOR, 8, 1):
+ temp64 = DPARAM1 ^ DPARAM2;
+ flags = FLAGS64_NZ(temp64);
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHL, 8, 0): /* DSHL dst,src,count[,f] */
+ DPARAM0 = DPARAM1 << (DPARAM2 & 63);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHL, 8, 1):
+ shift = DPARAM2 & 63;
+ temp64 = DPARAM1 << shift;
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHR, 8, 0): /* DSHR dst,src,count[,f] */
+ DPARAM0 = DPARAM1 >> (DPARAM2 & 63);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SHR, 8, 1):
+ shift = DPARAM2 & 63;
+ temp64 = DPARAM1 >> shift;
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SAR, 8, 0): /* DSAR dst,src,count[,f] */
+ DPARAM0 = (INT64)DPARAM1 >> (DPARAM2 & 63);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_SAR, 8, 1):
+ shift = DPARAM2 & 63;
+ temp64 = (INT32)DPARAM1 >> shift;
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROL, 8, 0): /* DROL dst,src,count[,f] */
+ shift = DPARAM2 & 31;
+ DPARAM0 = (DPARAM1 << shift) | (DPARAM1 >> ((64 - shift) & 63));
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROL, 8, 1):
+ shift = DPARAM2 & 63;
+ temp64 = (DPARAM1 << shift) | (DPARAM1 >> ((64 - shift) & 63));
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROLC, 8, 0): /* DROLC dst,src,count[,f] */
+ shift = DPARAM2 & 63;
+ if (shift > 1)
+ DPARAM0 = (DPARAM1 << shift) | ((flags & DRCUML_FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift));
+ else if (shift == 1)
+ DPARAM0 = (DPARAM1 << shift) | (flags & DRCUML_FLAG_C);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROLC, 8, 1):
+ shift = DPARAM2 & 63;
+ if (shift > 1)
+ temp64 = (DPARAM1 << shift) | ((flags & DRCUML_FLAG_C) << (shift - 1)) | (DPARAM1 >> (65 - shift));
+ else if (shift == 1)
+ temp64 = (DPARAM1 << shift) | (flags & DRCUML_FLAG_C);
+ else
+ temp64 = DPARAM1;
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= ((DPARAM1 << (shift - 1)) >> 63) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROR, 8, 0): /* DROR dst,src,count[,f] */
+ shift = DPARAM2 & 63;
+ DPARAM0 = (DPARAM1 >> shift) | (DPARAM1 << ((64 - shift) & 63));
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_ROR, 8, 1):
+ shift = DPARAM2 & 63;
+ temp64 = (DPARAM1 >> shift) | (DPARAM1 << ((64 - shift) & 63));
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RORC, 8, 0): /* DRORC dst,src,count[,f] */
+ shift = DPARAM2 & 63;
+ if (shift > 1)
+ DPARAM0 = (DPARAM1 >> shift) | ((((UINT64)flags & DRCUML_FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift));
+ else if (shift == 1)
+ DPARAM0 = (DPARAM1 >> shift) | (((UINT64)flags & DRCUML_FLAG_C) << 63);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_RORC, 8, 1):
+ shift = DPARAM2 & 63;
+ if (shift > 1)
+ temp64 = (DPARAM1 >> shift) | ((((UINT64)flags & DRCUML_FLAG_C) << 63) >> (shift - 1)) | (DPARAM1 << (65 - shift));
+ else if (shift == 1)
+ temp64 = (DPARAM1 >> shift) | (((UINT64)flags & DRCUML_FLAG_C) << 63);
+ else
+ temp64 = DPARAM1;
+ flags = FLAGS64_NZ(temp64);
+ if (shift != 0) flags |= (DPARAM1 >> (shift - 1)) & DRCUML_FLAG_C;
+ DPARAM0 = temp64;
+ break;
+
+
+ /* ----------------------- 32-Bit Floating Point Operations ----------------------- */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FLOAD, 4, 0): /* FSLOAD dst,base,index */
+ FSPARAM0 = inst[1].pfloat[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FSTORE, 4, 0): /* FSSTORE dst,base,index */
+ inst[0].pfloat[PARAM1] = FSPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FREAD, 4, 0): /* FSREAD dst,space,src1 */
+ PARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FWRITE, 4, 0): /* FSWRITE space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_dword)(PARAM1, PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FMOV, 4, 1): /* FSMOV dst,src[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FMOV, 4, 0):
+ FSPARAM0 = FSPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4, 4, 0): /* FSTOI4 dst,src1 */
+ *inst[0].pint32 = FSPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4T, 4, 0): /* FSTOI4T dst,src1 */
+ if (FSPARAM1 >= 0)
+ *inst[0].pint32 = floor(FSPARAM1);
+ else
+ *inst[0].pint32 = ceil(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4R, 4, 0): /* FSTOI4R dst,src1 */
+ if (FSPARAM1 >= 0)
+ *inst[0].pint32 = floor(FSPARAM1 + 0.5f);
+ else
+ *inst[0].pint32 = ceil(FSPARAM1 - 0.5f);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4F, 4, 0): /* FSTOI4F dst,src1 */
+ *inst[0].pint32 = floor(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4C, 4, 0): /* FSTOI4C dst,src1 */
+ *inst[0].pint32 = ceil(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8, 4, 0): /* FSTOI8 dst,src1 */
+ *inst[0].pint64 = FSPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8T, 4, 0): /* FSTOI8T dst,src1 */
+ if (FSPARAM1 >= 0)
+ *inst[0].pint64 = floor(FSPARAM1);
+ else
+ *inst[0].pint64 = ceil(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8R, 4, 0): /* FSTOI8R dst,src1 */
+ if (FSPARAM1 >= 0)
+ *inst[0].pint64 = floor(FSPARAM1 + 0.5f);
+ else
+ *inst[0].pint64 = ceil(FSPARAM1 - 0.5f);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8F, 4, 0): /* FSTOI8F dst,src1 */
+ *inst[0].pint64 = floor(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8C, 4, 0): /* FSTOI8C dst,src1 */
+ *inst[0].pint64 = ceil(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FFRFD, 4, 0): /* FSFRFD dst,src1 */
+ FSPARAM0 = FDPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FFRI4, 4, 0): /* FSFRI4 dst,src1 */
+ FSPARAM0 = *inst[1].pint32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FFRI8, 4, 0): /* FSFRI8 dst,src1 */
+ FSPARAM0 = *inst[1].pint64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FADD, 4, 0): /* FSADD dst,src1,src2 */
+ FSPARAM0 = FSPARAM1 + FSPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FSUB, 4, 0): /* FSSUB dst,src1,src2 */
+ FSPARAM0 = FSPARAM1 - FSPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FCMP, 4, 1): /* FSCMP src1,src2 */
+ if (_isnan(FSPARAM0) || _isnan(FSPARAM1))
+ flags = DRCUML_FLAG_U;
+ else
+ flags = (FSPARAM0 < FSPARAM1) | ((FSPARAM0 == FSPARAM1) << 2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FMUL, 4, 0): /* FSMUL dst,src1,src2 */
+ FSPARAM0 = FSPARAM1 * FSPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FDIV, 4, 0): /* FSDIV dst,src1,src2 */
+ FSPARAM0 = FSPARAM1 / FSPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FNEG, 4, 0): /* FSNEG dst,src1 */
+ FSPARAM0 = -FSPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FABS, 4, 0): /* FSABS dst,src1 */
+ FSPARAM0 = fabs(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FSQRT, 4, 0): /* FSSQRT dst,src1 */
+ FSPARAM0 = sqrt(FSPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FRECIP, 4, 0): /* FSRECIP dst,src1 */
+ FSPARAM0 = 1.0f / FSPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FRSQRT, 4, 0): /* FSRSQRT dst,src1 */
+ FSPARAM0 = 1.0f / sqrt(FSPARAM1);
+ break;
+
+
+ /* ----------------------- 64-Bit Floating Point Operations ----------------------- */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FLOAD, 8, 0): /* FDLOAD dst,base,index */
+ FDPARAM0 = inst[1].pdouble[PARAM2];
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FSTORE, 8, 0): /* FDSTORE dst,base,index */
+ inst[0].pdouble[PARAM1] = FDPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FREAD, 8, 0): /* FDREAD dst,space,src1 */
+ PARAM0 = (UINT64)(*active_address_space[PARAM1].accessors->read_qword)(PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FWRITE, 8, 0): /* FDWRITE space,dst,src1 */
+ (*active_address_space[PARAM0].accessors->write_qword)(PARAM1, PARAM2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FMOV, 8, 1): /* FDMOV dst,src[,c] */
+ if (OPCODE_FAIL_CONDITION(opcode, flags))
+ break;
+ /* fall through... */
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FMOV, 8, 0):
+ FDPARAM0 = FDPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4, 8, 0): /* FDTOI4 dst,src1 */
+ *inst[0].pint32 = FDPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4T, 8, 0): /* FDTOI4T dst,src1 */
+ if (FDPARAM1 >= 0)
+ *inst[0].pint32 = floor(FDPARAM1);
+ else
+ *inst[0].pint32 = ceil(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4R, 8, 0): /* FDTOI4R dst,src1 */
+ if (FDPARAM1 >= 0)
+ *inst[0].pint32 = floor(FDPARAM1 + 0.5);
+ else
+ *inst[0].pint32 = ceil(FDPARAM1 - 0.5);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4F, 8, 0): /* FDTOI4F dst,src1 */
+ *inst[0].pint32 = floor(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4C, 8, 0): /* FDTOI4C dst,src1 */
+ *inst[0].pint32 = ceil(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8, 8, 0): /* FDTOI8 dst,src1 */
+ *inst[0].pint64 = FDPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8T, 8, 0): /* FDTOI8T dst,src1 */
+ if (FDPARAM1 >= 0)
+ *inst[0].pint64 = floor(FDPARAM1);
+ else
+ *inst[0].pint64 = ceil(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8R, 8, 0): /* FDTOI8R dst,src1 */
+ if (FDPARAM1 >= 0)
+ *inst[0].pint64 = floor(FDPARAM1 + 0.5);
+ else
+ *inst[0].pint64 = ceil(FDPARAM1 - 0.5);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8F, 8, 0): /* FDTOI8F dst,src1 */
+ *inst[0].pint64 = floor(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8C, 8, 0): /* FDTOI8C dst,src1 */
+ *inst[0].pint64 = ceil(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FFRFS, 8, 0): /* FDFRFS dst,src1 */
+ FDPARAM0 = FSPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FFRI4, 8, 0): /* FDFRI4 dst,src1 */
+ FDPARAM0 = *inst[1].pint32;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FFRI8, 8, 0): /* FDFRI8 dst,src1 */
+ FDPARAM0 = *inst[1].pint64;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FADD, 8, 0): /* FDADD dst,src1,src2 */
+ FDPARAM0 = FDPARAM1 + FDPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FSUB, 8, 0): /* FDSUB dst,src1,src2 */
+ FDPARAM0 = FDPARAM1 - FDPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FCMP, 8, 1): /* FDCMP src1,src2 */
+ if (_isnan(FDPARAM0) || _isnan(FDPARAM1))
+ flags = DRCUML_FLAG_U;
+ else
+ flags = (FDPARAM0 < FDPARAM1) | ((FDPARAM0 == FDPARAM1) << 2);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FMUL, 8, 0): /* FDMUL dst,src1,src2 */
+ FDPARAM0 = FDPARAM1 * FDPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FDIV, 8, 0): /* FDDIV dst,src1,src2 */
+ FDPARAM0 = FDPARAM1 / FDPARAM2;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FNEG, 8, 0): /* FDNEG dst,src1 */
+ FDPARAM0 = -FDPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FABS, 8, 0): /* FDABS dst,src1 */
+ FDPARAM0 = fabs(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FSQRT, 8, 0): /* FDSQRT dst,src1 */
+ FDPARAM0 = sqrt(FDPARAM1);
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FRECIP, 8, 0): /* FDRECIP dst,src1 */
+ FDPARAM0 = 1.0 / FDPARAM1;
+ break;
+
+ case MAKE_OPCODE_SHORT(DRCUML_OP_FRSQRT, 8, 0): /* FDRSQRT dst,src1 */
+ FDPARAM0 = 1.0 / sqrt(FDPARAM1);
+ break;
+
+ default:
+ fatalerror("Unexpected opcode!");
+ break;
+ }
+
+ /* advance past the parameters and immediates */
+ inst += OPCODE_GET_PWORDS(opcode);
+ }
+
+ return 0;
+}
+
+
+
+/***************************************************************************
+ PRIVATE HELPER FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ output_parameter - output a parameter
+-------------------------------------------------*/
+
+static void output_parameter(drcbe_state *drcbe, drcbec_instruction **dstptr, void **immedptr, int size, int immedsize, const drcuml_parameter *param)
+{
+ drcbec_instruction *dst = *dstptr;
+ void *immed = *immedptr;
+ drcuml_parameter temp_param;
+
+ switch (param->type)
+ {
+ /* convert mapvars to immediates */
+ case DRCUML_PTYPE_MAPVAR:
+ temp_param.value = drcmap_get_last_value(drcbe->map, param->value);
+ param = &temp_param;
+ /* fall through to immediate case */
+
+ /* immediates store a pointer to the immediate data, which is stored at the end of the instruction */
+ case DRCUML_PTYPE_IMMEDIATE:
+ if (param->value == 0)
+ (dst++)->v = &immediate_zero;
+ else
+ {
+ (dst++)->v = immed;
+ if (immedsize == 4)
+ *(UINT32 *)immed = (UINT32)param->value;
+ else
+ *(UINT64 *)immed = (UINT64)param->value;
+ immed = (UINT8 *)immed + immedsize;
+ }
+ break;
+
+ /* int registers point to the appropriate part of the integer register state */
+ case DRCUML_PTYPE_INT_REGISTER:
+ if (size == 4)
+ (dst++)->puint32 = &drcbe->state.r[param->value - DRCUML_REG_I0].l;
+ else
+ (dst++)->puint64 = &drcbe->state.r[param->value - DRCUML_REG_I0].d;
+ break;
+
+ /* float registers point to the appropriate part of the floating point register state */
+ case DRCUML_PTYPE_FLOAT_REGISTER:
+ if (size == 4)
+ (dst++)->pfloat = &drcbe->state.f[param->value - DRCUML_REG_F0].l;
+ else
+ (dst++)->pdouble = &drcbe->state.f[param->value - DRCUML_REG_F0].d;
+ break;
+
+ /* memory just points to the memory */
+ case DRCUML_PTYPE_MEMORY:
+ (dst++)->v = (void *)(FPTR)param->value;
+ break;
+
+ default:
+ fatalerror("Unexpected param->type");
+ break;
+ }
+
+ *dstptr = dst;
+ *immedptr = immed;
+}
+
+
+/*-------------------------------------------------
+ fixup_label - callback to fixup forward-
+ referenced labels
+-------------------------------------------------*/
+
+static void fixup_label(void *parameter, drccodeptr labelcodeptr)
+{
+ drcbec_instruction *dst = parameter;
+ dst->inst = (drcbec_instruction *)labelcodeptr;
+}
+
+
+/*-------------------------------------------------
+ dmulu - perform a double-wide unsigned multiply
+-------------------------------------------------*/
+
+static int dmulu(UINT64 *dstlo, UINT64 *dsthi, UINT64 src1, UINT64 src2, int flags)
+{
+ UINT64 lo, hi, prevlo;
+ UINT64 a, b, temp;
+
+ /* shortcut if we don't care about the high bits or the flags */
+ if (dstlo == dsthi && !flags)
+ {
+ *dstlo = src1 * src2;
+ return 0;
+ }
+
+ /* fetch source values */
+ a = src1;
+ b = src2;
+ if (a == 0 || b == 0)
+ {
+ *dsthi = *dstlo = 0;
+ return DRCUML_FLAG_Z;
+ }
+
+ /* compute high and low parts first */
+ lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0);
+ hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32);
+
+ /* compute middle parts */
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ /* store the results */
+ *dsthi = hi;
+ *dstlo = lo;
+ return ((hi >> 60) & DRCUML_FLAG_S);
+}
+
+
+/*-------------------------------------------------
+ dmuls - perform a double-wide signed multiply
+-------------------------------------------------*/
+
+static int dmuls(UINT64 *dstlo, UINT64 *dsthi, INT64 src1, INT64 src2, int flags)
+{
+ UINT64 lo, hi, prevlo;
+ UINT64 a, b, temp;
+
+ /* shortcut if we don't care about the high bits or the flags */
+ if (dstlo == dsthi && !flags)
+ {
+ *dstlo = src1 * src2;
+ return 0;
+ }
+
+ /* fetch absolute source values */
+ a = src1; if ((INT64)a < 0) a = -a;
+ b = src2; if ((INT64)b < 0) b = -b;
+ if (a == 0 || b == 0)
+ {
+ *dsthi = *dstlo = 0;
+ return DRCUML_FLAG_Z;
+ }
+
+ /* compute high and low parts first */
+ lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0);
+ hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32);
+
+ /* compute middle parts */
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ /* adjust for signage */
+ if ((INT64)(src1 ^ src2) < 0)
+ {
+ hi = ~hi + (lo == 0);
+ lo = ~lo + 1;
+ }
+
+ /* store the results */
+ *dsthi = hi;
+ *dstlo = lo;
+ return ((hi >> 60) & DRCUML_FLAG_S);
+}
diff --git a/src/emu/cpu/drcbeut.c b/src/emu/cpu/drcbeut.c
new file mode 100644
index 00000000000..462ec118f11
--- /dev/null
+++ b/src/emu/cpu/drcbeut.c
@@ -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);
+}
diff --git a/src/emu/cpu/drcbeut.h b/src/emu/cpu/drcbeut.h
new file mode 100644
index 00000000000..0bcf0a2a646
--- /dev/null
+++ b/src/emu/cpu/drcbeut.h
@@ -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
diff --git a/src/emu/cpu/drcbex64.c b/src/emu/cpu/drcbex64.c
new file mode 100644
index 00000000000..156556419bb
--- /dev/null
+++ b/src/emu/cpu/drcbex64.c
@@ -0,0 +1,7680 @@
+/***************************************************************************
+
+ drcbex64.c
+
+ 64-bit x64 back-end 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.
+
+****************************************************************************
+
+ Future improvements/changes:
+
+ * Add support for FP registers
+
+ * Optimize to avoid unnecessary reloads
+
+ * Identify common pairs and optimize output
+
+****************************************************************************
+
+ -------------------------
+ ABI/conventions (Windows)
+ -------------------------
+
+ Registers:
+ RAX - volatile, function return value
+ RBX - non-volatile
+ RCX - volatile, integer function parameter 1
+ RDX - volatile, integer function parameter 2
+ RSI - non-volatile
+ RDI - non-volatile
+ RBP - non-volatile
+ R8 - volatile, integer function parameter 3
+ R9 - volatile, integer function parameter 4
+ R10 - volatile
+ R11 - volatile, scratch immediate storage
+ R12 - non-volatile
+ R13 - non-volatile
+ R14 - non-volatile
+ R15 - non-volatile
+
+ XMM0 - volatile, FP function parameter 1
+ XMM1 - volatile, FP function parameter 2
+ XMM2 - volatile, FP function parameter 3
+ XMM3 - volatile, FP function parameter 4
+ XMM4 - volatile
+ XMM5 - volatile
+ XMM6 - non-volatile
+ XMM7 - non-volatile
+ XMM8 - non-volatile
+ XMM9 - non-volatile
+ XMM10 - non-volatile
+ XMM11 - non-volatile
+ XMM12 - non-volatile
+ XMM13 - non-volatile
+ XMM14 - non-volatile
+ XMM15 - non-volatile
+
+
+ -----------------------------
+ ABI/conventions (Linux/MacOS)
+ -----------------------------
+
+ Registers:
+ RAX - volatile, function return value
+ RBX - non-volatile
+ RCX - volatile, integer function parameter 4
+ RDX - volatile, integer function parameter 3
+ RSI - volatile, integer function parameter 2
+ RDI - volatile, integer function parameter 1
+ RBP - non-volatile
+ R8 - volatile, integer function parameter 5
+ R9 - volatile, integer function parameter 6
+ R10 - volatile
+ R11 - volatile, scratch immediate storage
+ R12 - non-volatile
+ R13 - non-volatile
+ R14 - non-volatile
+ R15 - non-volatile
+
+ XMM0 - volatile, FP function parameter 1
+ XMM1 - volatile, FP function parameter 2
+ XMM2 - volatile, FP function parameter 3
+ XMM3 - volatile, FP function parameter 4
+ XMM4 - volatile
+ XMM5 - volatile
+ XMM6 - volatile
+ XMM7 - volatile
+ XMM8 - volatile
+ XMM9 - volatile
+ XMM10 - volatile
+ XMM11 - volatile
+ XMM12 - volatile
+ XMM13 - volatile
+ XMM14 - volatile
+ XMM15 - volatile
+
+
+ ---------------
+ Execution model
+ ---------------
+
+ Registers (Windows):
+ RAX - scratch register
+ RBX - maps to I0
+ RCX - scratch register
+ RDX - scratch register
+ RSI - maps to I1
+ RDI - maps to I2
+ RBP - pointer to code cache
+ R8 - scratch register
+ R9 - scratch register
+ R10 - scratch register
+ R11 - scratch register
+ R12 - maps to I3
+ R13 - maps to I4
+ R14 - maps to I5
+ R15 - maps to I6
+
+ Registers (Linux/MacOS):
+ RAX - scratch register
+ RBX - maps to I0
+ RCX - scratch register
+ RDX - scratch register
+ RSI - unused
+ RDI - unused
+ RBP - pointer to code cache
+ R8 - scratch register
+ R9 - scratch register
+ R10 - scratch register
+ R11 - scratch register
+ R12 - maps to I1
+ R13 - maps to I2
+ R14 - maps to I3
+ R15 - maps to I4
+
+ Entry point:
+ Assumes 1 parameter passed, which is the codeptr of the code
+ to execute once the environment is set up.
+
+ Exit point:
+ Assumes exit value is in RAX.
+
+ Entry stack:
+ [rsp] - return
+
+ Runtime stack:
+ [rsp] - r9 home
+ [rsp+8] - r8 home
+ [rsp+16] - rdx home
+ [rsp+24] - rcx home
+ [rsp+40] - saved r15
+ [rsp+48] - saved r14
+ [rsp+56] - saved r13
+ [rsp+64] - saved r12
+ [rsp+72] - saved ebp
+ [rsp+80] - saved edi
+ [rsp+88] - saved esi
+ [rsp+96] - saved ebx
+ [rsp+104] - ret
+
+***************************************************************************/
+
+#include "drcuml.h"
+#include "drcumld.h"
+#include "drcbeut.h"
+#include "debugger.h"
+#include "x86emit.h"
+#undef REG_SP
+#include "x86log.h"
+#include <math.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_HASHJMPS (0)
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PTYPE_M (1 << DRCUML_PTYPE_MEMORY)
+#define PTYPE_I (1 << DRCUML_PTYPE_IMMEDIATE)
+#define PTYPE_R (1 << DRCUML_PTYPE_INT_REGISTER)
+#define PTYPE_F (1 << DRCUML_PTYPE_FLOAT_REGISTER)
+#define PTYPE_MI (PTYPE_M | PTYPE_I)
+#define PTYPE_RI (PTYPE_R | PTYPE_I)
+#define PTYPE_MR (PTYPE_M | PTYPE_R)
+#define PTYPE_MRI (PTYPE_M | PTYPE_R | PTYPE_I)
+#define PTYPE_MF (PTYPE_M | PTYPE_F)
+
+#ifdef X64_WINDOWS_ABI
+
+#define REG_PARAM1 REG_RCX
+#define REG_PARAM2 REG_RDX
+#define REG_PARAM3 REG_R8
+#define REG_PARAM4 REG_R9
+
+#else
+
+#define REG_PARAM1 REG_RDI
+#define REG_PARAM2 REG_RSI
+#define REG_PARAM3 REG_RDX
+#define REG_PARAM4 REG_RCX
+
+#endif
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define X86_CONDITION(condflags) (condition_map[condflags - DRCUML_COND_Z])
+#define X86_NOT_CONDITION(condflags) (condition_map[condflags - DRCUML_COND_Z] ^ 1)
+
+#undef MABS
+#define MABS(drcbe, ptr) MBD(REG_RBP, offset_from_rbp(drcbe, (FPTR)(ptr)))
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* entry point */
+typedef UINT32 (*x86_entry_point_func)(UINT8 *rbpvalue, x86code *entry);
+
+/* opcode handler */
+typedef x86code *(*opcode_generate_func)(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+
+/* opcode table entry */
+typedef struct _opcode_table_entry opcode_table_entry;
+struct _opcode_table_entry
+{
+ drcuml_opcode opcode; /* opcode in question */
+ opcode_generate_func func; /* function pointer to the work */
+};
+
+
+/* internal backend-specific state */
+struct _drcbe_state
+{
+ drcuml_state * drcuml; /* pointer back to our owner */
+ drccache * cache; /* pointer to the cache */
+ drcuml_machine_state state; /* state of the machine */
+ drchash_state * hash; /* hash table state */
+ drcmap_state * map; /* code map */
+ drclabel_list * labels; /* label list */
+
+ x86_entry_point_func entry; /* entry point */
+ x86code * exit; /* exit point */
+ x86code * nocode; /* nocode handler */
+
+ x86code * mame_debug_hook; /* debugger callback */
+ x86code * debug_log_hashjmp; /* hashjmp debugging */
+ x86code * drcmap_get_value; /* map lookup helper */
+ data_accessors accessors[ADDRESS_SPACES];/* memory accessors */
+
+ UINT32 ssemode; /* saved SSE mode */
+ UINT32 ssemodesave; /* temporary location for saving */
+ UINT32 ssecontrol[4]; /* copy of the sse_control array */
+ UINT32 * absmask32; /* absolute value mask (32-bit) */
+ UINT64 * absmask64; /* absolute value mask (32-bit) */
+
+ void * stacksave; /* saved stack pointer */
+ void * hashstacksave; /* saved stack pointer for hashjmp */
+
+ UINT8 * rbpvalue; /* value of RBP */
+ UINT8 flagsmap[0x1000]; /* flags map */
+
+ x86log_context * log; /* logging */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* primary back-end callbacks */
+static drcbe_state *drcbex64_alloc(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
+static void drcbex64_free(drcbe_state *drcbe);
+static void drcbex64_reset(drcbe_state *drcbe);
+static int drcbex64_execute(drcbe_state *drcbe, drcuml_codehandle *entry);
+static void drcbex64_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
+static int drcbex64_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc);
+
+/* private helper functions */
+static void fixup_label(void *parameter, drccodeptr labelcodeptr);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* globally-accessible interface to the backend */
+const drcbe_interface drcbe_x64_be_interface =
+{
+ drcbex64_alloc,
+ drcbex64_free,
+ drcbex64_reset,
+ drcbex64_execute,
+ drcbex64_generate,
+ drcbex64_hash_exists
+};
+
+/* opcode table */
+static opcode_generate_func opcode_table[DRCUML_OP_MAX];
+
+/* size-to-mask table */
+static const UINT64 size_to_mask[] = { 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0, U64(0xffffffffffffffff) };
+
+/* register mapping tables */
+static UINT8 int_register_map[DRCUML_REG_I_END - DRCUML_REG_I0] =
+{
+#ifdef X64_WINDOWS_ABI
+ REG_RBX, REG_RSI, REG_RDI, REG_R12, REG_R13, REG_R14, REG_R15
+#else
+ REG_RBX, REG_R12, REG_R13, REG_R14, REG_R15
+#endif
+};
+
+static UINT8 float_register_map[DRCUML_REG_F_END - DRCUML_REG_F0] =
+{
+ 0
+};
+
+/* condition mapping table */
+static UINT8 condition_map[DRCUML_COND_MAX - DRCUML_COND_Z] =
+{
+ COND_Z, /* DRCUML_COND_Z = 0x80, requires Z */
+ COND_NZ, /* DRCUML_COND_NZ, requires Z */
+ COND_S, /* DRCUML_COND_S, requires S */
+ COND_NS, /* DRCUML_COND_NS, requires S */
+ COND_C, /* DRCUML_COND_C, requires C */
+ COND_NC, /* DRCUML_COND_NC, requires C */
+ COND_O, /* DRCUML_COND_V, requires V */
+ COND_NO, /* DRCUML_COND_NV, requires V */
+ COND_P, /* DRCUML_COND_U, requires U */
+ COND_NP, /* DRCUML_COND_NU, requires U */
+ COND_A, /* DRCUML_COND_A, requires CZ */
+ COND_BE, /* DRCUML_COND_BE, requires CZ */
+ COND_G, /* DRCUML_COND_G, requires SVZ */
+ COND_LE, /* DRCUML_COND_LE, requires SVZ */
+ COND_L, /* DRCUML_COND_L, requires SV */
+ COND_GE, /* DRCUML_COND_GE, requires SV */
+};
+
+
+
+/***************************************************************************
+ TABLES
+***************************************************************************/
+
+static x86code *op_handle(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_hash(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_label(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_comment(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_mapvar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_debug(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_exit(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_jmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_exh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_callh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ret(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_callc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_subc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_cmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_divu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_divs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_and(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_test(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_or(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_xor(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_shl(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_shr(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ror(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_rol(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_rorc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_rolc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_fload(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fmul(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fdiv(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fneg(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fabs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_frecip(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_frsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static const opcode_table_entry opcode_table_source[] =
+{
+ /* Compile-time opcodes */
+ { DRCUML_OP_HANDLE, op_handle }, /* HANDLE handle */
+ { DRCUML_OP_HASH, op_hash }, /* HASH mode,pc */
+ { DRCUML_OP_LABEL, op_label }, /* LABEL imm */
+ { DRCUML_OP_COMMENT, op_comment }, /* COMMENT string */
+ { DRCUML_OP_MAPVAR, op_mapvar }, /* MAPVAR mapvar,value */
+
+ /* Control Flow Operations */
+ { DRCUML_OP_DEBUG, op_debug }, /* DEBUG pc */
+ { DRCUML_OP_EXIT, op_exit }, /* EXIT src1[,c] */
+ { DRCUML_OP_HASHJMP, op_hashjmp }, /* HASHJMP mode,pc,handle */
+ { DRCUML_OP_JMP, op_jmp }, /* JMP imm[,c] */
+ { DRCUML_OP_EXH, op_exh }, /* EXH handle,param[,c] */
+ { DRCUML_OP_CALLH, op_callh }, /* CALLH handle[,c] */
+ { DRCUML_OP_RET, op_ret }, /* RET [c] */
+ { DRCUML_OP_CALLC, op_callc }, /* CALLC func,ptr[,c] */
+ { DRCUML_OP_RECOVER, op_recover }, /* RECOVER dst,mapvar */
+
+ /* Internal Register Operations */
+ { DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */
+ { DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */
+ { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */
+
+ /* Integer Operations */
+ { DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */
+ { DRCUML_OP_LOAD1S, op_load1s }, /* LOAD1S dst,base,index */
+ { DRCUML_OP_LOAD2U, op_load2u }, /* LOAD2U dst,base,index */
+ { DRCUML_OP_LOAD2S, op_load2s }, /* LOAD2S dst,base,index */
+ { DRCUML_OP_LOAD4U, op_load4u }, /* LOAD4U dst,base,index */
+ { DRCUML_OP_LOAD4S, op_load4s }, /* LOAD4S dst,base,index */
+ { DRCUML_OP_LOAD8U, op_load8u }, /* LOAD8U dst,base,index */
+ { DRCUML_OP_STORE1, op_store1 }, /* STORE1 base,index,src */
+ { DRCUML_OP_STORE2, op_store2 }, /* STORE2 base,index,src */
+ { DRCUML_OP_STORE4, op_store4 }, /* STORE4 base,index,src */
+ { DRCUML_OP_STORE8, op_store8 }, /* STORE8 base,index,src */
+ { DRCUML_OP_READ1U, op_read1u }, /* READ1U dst,space,src1 */
+ { DRCUML_OP_READ1S, op_read1s }, /* READ1S dst,space,src1 */
+ { DRCUML_OP_READ2U, op_read2u }, /* READ2U dst,space,src1 */
+ { DRCUML_OP_READ2S, op_read2s }, /* READ2S dst,space,src1 */
+ { DRCUML_OP_READ2M, op_read2m }, /* READ2M dst,space,src1,mask */
+ { DRCUML_OP_READ4U, op_read4u }, /* READ4U dst,space,src1 */
+ { DRCUML_OP_READ4S, op_read4s }, /* READ4S dst,space,src1 */
+ { DRCUML_OP_READ4M, op_read4m }, /* READ4M dst,space,src1,mask */
+ { DRCUML_OP_READ8U, op_read8u }, /* READ8U dst,space,src1 */
+ { DRCUML_OP_READ8M, op_read8m }, /* READ8M dst,space,src1,mask */
+ { DRCUML_OP_WRITE1, op_write1 }, /* WRITE1 space,dst,src1 */
+ { DRCUML_OP_WRITE2, op_write2 }, /* WRITE2 space,dst,src1 */
+ { DRCUML_OP_WRIT2M, op_writ2m }, /* WRIT2M space,dst,src1 */
+ { DRCUML_OP_WRITE4, op_write4 }, /* WRITE4 space,dst,src1 */
+ { DRCUML_OP_WRIT4M, op_writ4m }, /* WRIT4M space,dst,mask,src1 */
+ { DRCUML_OP_WRITE8, op_write8 }, /* WRITE8 space,dst,src1 */
+ { DRCUML_OP_WRIT8M, op_writ8m }, /* WRIT8M space,dst,mask,src1 */
+ { DRCUML_OP_FLAGS, op_flags }, /* FLAGS dst,mask,table */
+ { DRCUML_OP_MOV, op_mov }, /* MOV dst,src[,c] */
+ { DRCUML_OP_ZEXT1, op_zext1 }, /* ZEXT1 dst,src */
+ { DRCUML_OP_ZEXT2, op_zext2 }, /* ZEXT2 dst,src */
+ { DRCUML_OP_ZEXT4, op_zext4 }, /* ZEXT4 dst,src */
+ { DRCUML_OP_SEXT1, op_sext1 }, /* SEXT1 dst,src */
+ { DRCUML_OP_SEXT2, op_sext2 }, /* SEXT2 dst,src */
+ { DRCUML_OP_SEXT4, op_sext4 }, /* SEXT4 dst,src */
+ { DRCUML_OP_ADD, op_add }, /* ADD dst,src1,src2[,f] */
+ { DRCUML_OP_ADDC, op_addc }, /* ADDC dst,src1,src2[,f] */
+ { DRCUML_OP_SUB, op_sub }, /* SUB dst,src1,src2[,f] */
+ { DRCUML_OP_SUBB, op_subc }, /* SUBB dst,src1,src2[,f] */
+ { DRCUML_OP_CMP, op_cmp }, /* CMP src1,src2[,f] */
+ { DRCUML_OP_MULU, op_mulu }, /* MULU dst,edst,src1,src2[,f] */
+ { DRCUML_OP_MULS, op_muls }, /* MULS dst,edst,src1,src2[,f] */
+ { DRCUML_OP_DIVU, op_divu }, /* DIVU dst,edst,src1,src2[,f] */
+ { DRCUML_OP_DIVS, op_divs }, /* DIVS dst,edst,src1,src2[,f] */
+ { DRCUML_OP_AND, op_and }, /* AND dst,src1,src2[,f] */
+ { DRCUML_OP_TEST, op_test }, /* TEST src1,src2[,f] */
+ { DRCUML_OP_OR, op_or }, /* OR dst,src1,src2[,f] */
+ { DRCUML_OP_XOR, op_xor }, /* XOR dst,src1,src2[,f] */
+ { DRCUML_OP_SHL, op_shl }, /* SHL dst,src,count[,f] */
+ { DRCUML_OP_SHR, op_shr }, /* SHR dst,src,count[,f] */
+ { DRCUML_OP_SAR, op_sar }, /* SAR dst,src,count[,f] */
+ { DRCUML_OP_ROL, op_rol }, /* ROL dst,src,count[,f] */
+ { DRCUML_OP_ROLC, op_rolc }, /* ROLC dst,src,count[,f] */
+ { DRCUML_OP_ROR, op_ror }, /* ROR dst,src,count[,f] */
+ { DRCUML_OP_RORC, op_rorc }, /* RORC dst,src,count[,f] */
+
+ /* Floating Point Operations */
+ { DRCUML_OP_FLOAD, op_fload }, /* FLOAD dst,base,index */
+ { DRCUML_OP_FSTORE, op_fstore }, /* FSTORE base,index,src */
+ { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,space,src1 */
+ { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE space,dst,src1 */
+ { DRCUML_OP_FMOV, op_fmov }, /* FMOV dst,src1[,c] */
+ { DRCUML_OP_FTOI4, op_ftoi4 }, /* FTOI4 dst,src1 */
+ { DRCUML_OP_FTOI4T, op_ftoi4t }, /* FTOI4T dst,src1 */
+ { DRCUML_OP_FTOI4R, op_ftoi4r }, /* FTOI4R dst,src1 */
+ { DRCUML_OP_FTOI4F, op_ftoi4f }, /* FTOI4F dst,src1 */
+ { DRCUML_OP_FTOI4C, op_ftoi4c }, /* FTOI4C dst,src1 */
+ { DRCUML_OP_FTOI8, op_ftoi8 }, /* FTOI8 dst,src1 */
+ { DRCUML_OP_FTOI8T, op_ftoi8t }, /* FTOI8T dst,src1 */
+ { DRCUML_OP_FTOI8R, op_ftoi8r }, /* FTOI8R dst,src1 */
+ { DRCUML_OP_FTOI8F, op_ftoi8f }, /* FTOI8F dst,src1 */
+ { DRCUML_OP_FTOI8C, op_ftoi8c }, /* FTOI8C dst,src1 */
+ { DRCUML_OP_FFRFS, op_ffrfs }, /* FFRFS dst,src1 */
+ { DRCUML_OP_FFRFD, op_ffrfd }, /* FFRFD dst,src1 */
+ { DRCUML_OP_FFRI4, op_ffri4 }, /* FFRI4 dst,src1 */
+ { DRCUML_OP_FFRI8, op_ffri8 }, /* FFRI8 dst,src1 */
+ { DRCUML_OP_FADD, op_fadd }, /* FADD dst,src1,src2 */
+ { DRCUML_OP_FSUB, op_fsub }, /* FSUB dst,src1,src2 */
+ { DRCUML_OP_FCMP, op_fcmp }, /* FCMP src1,src2 */
+ { DRCUML_OP_FMUL, op_fmul }, /* FMUL dst,src1,src2 */
+ { DRCUML_OP_FDIV, op_fdiv }, /* FDIV dst,src1,src2 */
+ { DRCUML_OP_FNEG, op_fneg }, /* FNEG dst,src1 */
+ { DRCUML_OP_FABS, op_fabs }, /* FABS dst,src1 */
+ { DRCUML_OP_FSQRT, op_fsqrt }, /* FSQRT dst,src1 */
+ { DRCUML_OP_FRECIP, op_frecip }, /* FRECIP dst,src1 */
+ { DRCUML_OP_FRSQRT, op_frsqrt } /* FRSQRT dst,src1 */
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ param_select_register - select a register
+ to use, avoiding conflicts with the optional
+ checkparam
+-------------------------------------------------*/
+
+INLINE int param_select_register(int defreg, const drcuml_parameter *param, const drcuml_parameter *checkparam)
+{
+ if ((param->type == DRCUML_PTYPE_INT_REGISTER || param->type == DRCUML_PTYPE_FLOAT_REGISTER) && (checkparam == NULL || param->type != checkparam->type || param->value != checkparam->value))
+ return param->value;
+ return defreg;
+}
+
+
+/*-------------------------------------------------
+ offset_from_rbp - return the verified offset
+ from rbp
+-------------------------------------------------*/
+
+INLINE INT32 offset_from_rbp(drcbe_state *drcbe, FPTR ptr)
+{
+ INT64 delta = (UINT8 *)ptr - drcbe->rbpvalue;
+ assert_always((INT32)delta == delta, "offset_from_rbp: delta out of range");
+ return (INT32)delta;
+}
+
+
+/*-------------------------------------------------
+ short_immediate - true if the given immediate
+ fits as a signed 32-bit value
+-------------------------------------------------*/
+
+INLINE int short_immediate(INT64 immediate)
+{
+ return (INT32)immediate == immediate;
+}
+
+
+/*-------------------------------------------------
+ get_base_register_and_offset - determine right
+ base register and offset to access the given
+ target address
+-------------------------------------------------*/
+
+INLINE int get_base_register_and_offset(drcbe_state *drcbe, x86code **dst, FPTR target, UINT8 reg, INT32 *offset)
+{
+ INT64 delta = (UINT8 *)target - drcbe->rbpvalue;
+ if (short_immediate(delta))
+ {
+ *offset = delta;
+ return REG_RBP;
+ }
+ else
+ {
+ *offset = 0;
+ emit_mov_r64_imm(dst, reg, target); // mov reg,target
+ return reg;
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_smart_call_r64 - generate a call either
+ directly or via a call through pointer
+-------------------------------------------------*/
+
+INLINE void emit_smart_call_r64(drcbe_state *drcbe, x86code **dst, x86code *target, UINT8 reg)
+{
+ INT64 delta = target - (*dst + 5);
+ if (short_immediate(delta))
+ emit_call(dst, target); // call target
+ else
+ {
+ emit_mov_r64_imm(dst, reg, (FPTR)target); // mov reg,target
+ emit_call_r64(dst, reg); // call reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_smart_call_m64 - generate a call either
+ directly or via a call through pointer
+-------------------------------------------------*/
+
+INLINE void emit_smart_call_m64(drcbe_state *drcbe, x86code **dst, x86code **target)
+{
+ INT64 delta = *target - (*dst + 5);
+ if (short_immediate(delta))
+ emit_call(dst, *target); // call *target
+ else
+ emit_call_m64(dst, MABS(drcbe, target)); // call [target]
+}
+
+
+
+/***************************************************************************
+ BACKEND CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ drcbex64_alloc - allocate back-end-specific
+ state
+-------------------------------------------------*/
+
+static drcbe_state *drcbex64_alloc(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits)
+{
+ /* SSE control register mapping */
+ static const UINT32 sse_control[4] =
+ {
+ 0xffc0, /* DRCUML_FMOD_TRUNC */
+ 0x9fc0, /* DRCUML_FMOD_ROUND */
+ 0xdfc0, /* DRCUML_FMOD_CEIL */
+ 0xbfc0 /* DRCUML_FMOD_FLOOR */
+ };
+ drcbe_state *drcbe;
+ int opnum, entry;
+
+ /* allocate space in the cache for our state */
+ drcbe = drccache_memory_alloc_near(cache, sizeof(*drcbe));
+ if (drcbe == NULL)
+ return NULL;
+ memset(drcbe, 0, sizeof(*drcbe));
+
+ /* remember our pointers */
+ drcbe->drcuml = drcuml;
+ drcbe->cache = cache;
+ drcbe->rbpvalue = drccache_near(cache) + 0x80;
+
+ /* build up necessary arrays */
+ memcpy(drcbe->ssecontrol, sse_control, sizeof(drcbe->ssecontrol));
+ drcbe->absmask32 = drccache_memory_alloc_near(cache, 16*2 + 15);
+ drcbe->absmask32 = (void *)(((FPTR)drcbe->absmask32 + 15) & ~15);
+ drcbe->absmask32[0] = drcbe->absmask32[1] = drcbe->absmask32[2] = drcbe->absmask32[3] = 0x7fffffff;
+ drcbe->absmask64 = (UINT64 *)&drcbe->absmask32[4];
+ drcbe->absmask64[0] = drcbe->absmask64[1] = U64(0x7fffffffffffffff);
+
+ /* get pointers to C functions we need to call */
+#ifdef ENABLE_DEBUGGER
+ drcbe->mame_debug_hook = (x86code *)mame_debug_hook;
+#endif
+#if LOG_HASHJMPS
+ drcbe->debug_log_hashjmp = (x86code *)debug_log_hashjmp;
+#endif
+ drcbe->drcmap_get_value = (x86code *)drcmap_get_value;
+
+ /* allocate hash tables */
+ drcbe->hash = drchash_alloc(cache, modes, addrbits, ignorebits);
+ if (drcbe->hash == NULL)
+ return NULL;
+
+ /* allocate code map */
+ drcbe->map = drcmap_alloc(cache, 0);
+ if (drcbe->map == NULL)
+ return NULL;
+
+ /* allocate a label tracker */
+ drcbe->labels = drclabel_list_alloc(cache);
+ if (drcbe->labels == NULL)
+ return NULL;
+
+ /* build the opcode table (static but it doesn't hurt to regenerate it) */
+ for (opnum = 0; opnum < ARRAY_LENGTH(opcode_table_source); opnum++)
+ opcode_table[opcode_table_source[opnum].opcode] = opcode_table_source[opnum].func;
+
+ /* build the flags map */
+ for (entry = 0; entry < ARRAY_LENGTH(drcbe->flagsmap); entry++)
+ {
+ UINT8 flags = 0;
+ if (entry & 0x001) flags |= DRCUML_FLAG_C;
+ if (entry & 0x004) flags |= DRCUML_FLAG_U;
+ if (entry & 0x040) flags |= DRCUML_FLAG_Z;
+ if (entry & 0x080) flags |= DRCUML_FLAG_S;
+ if (entry & 0x800) flags |= DRCUML_FLAG_V;
+ drcbe->flagsmap[entry] = flags;
+ }
+
+ /* create the log */
+ if (flags & DRCUML_OPTION_LOG_NATIVE)
+ drcbe->log = x86log_create_context("drcbex64.asm");
+
+ return drcbe;
+}
+
+
+/*-------------------------------------------------
+ drcbex64_free - free back-end specific state
+-------------------------------------------------*/
+
+static void drcbex64_free(drcbe_state *drcbe)
+{
+ /* free the log context */
+ if (drcbe->log != NULL)
+ x86log_free_context(drcbe->log);
+}
+
+
+/*-------------------------------------------------
+ drcbex64_reset - reset back-end specific state
+-------------------------------------------------*/
+
+static void drcbex64_reset(drcbe_state *drcbe)
+{
+ x86code **dst;
+ int spacenum;
+
+ /* output a note to the log */
+ if (drcbe->log != NULL)
+ x86log_printf(drcbe->log, "\n\n===========\nCACHE RESET\n===========\n\n");
+
+ /* fetch the accessors now that things are ready to go */
+ for (spacenum = 0; spacenum < ADDRESS_SPACES; spacenum++)
+ if (active_address_space[spacenum].accessors != NULL)
+ drcbe->accessors[spacenum] = *active_address_space[spacenum].accessors;
+
+ /* generate a little bit of glue code to set up the environment */
+ dst = (x86code **)drccache_begin_codegen(drcbe->cache, 500);
+ if (dst == NULL)
+ fatalerror("Out of cache space after a reset!");
+
+ /* generate an entry point */
+ drcbe->entry = (x86_entry_point_func)*dst;
+ emit_push_r64(dst, REG_RBX); // push rbx
+ emit_push_r64(dst, REG_RSI); // push rsi
+ emit_push_r64(dst, REG_RDI); // push rdi
+ emit_push_r64(dst, REG_RBP); // push rbp
+ emit_push_r64(dst, REG_R12); // push r12
+ emit_push_r64(dst, REG_R13); // push r13
+ emit_push_r64(dst, REG_R14); // push r14
+ emit_push_r64(dst, REG_R15); // push r15
+ emit_mov_r64_r64(dst, REG_RBP, REG_RCX); // mov rbp,rcx
+ emit_sub_r64_imm(dst, REG_RSP, 32); // sub rsp,32
+ emit_mov_m64_r64(dst, MABS(drcbe, &drcbe->hashstacksave), REG_RSP); // mov [hashstacksave],rsp
+ emit_sub_r64_imm(dst, REG_RSP, 8); // sub rsp,8
+ emit_mov_m64_r64(dst, MABS(drcbe, &drcbe->stacksave), REG_RSP); // mov [stacksave],rsp
+ emit_stmxcsr_m32(dst, MABS(drcbe, &drcbe->ssemode)); // stmxcsr [ssemode]
+ emit_jmp_r64(dst, REG_RDX); // jmp rdx
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, "entry_point", (x86code *)drcbe->entry, *dst);
+
+ /* generate an exit point */
+ drcbe->exit = *dst;
+ emit_ldmxcsr_m32(dst, MABS(drcbe, &drcbe->ssemode)); // ldmxcsr [ssemode]
+ emit_mov_r64_m64(dst, REG_RSP, MABS(drcbe, &drcbe->hashstacksave)); // mov rsp,[hashstacksave]
+ emit_add_r64_imm(dst, REG_RSP, 32); // add rsp,32
+ emit_pop_r64(dst, REG_R15); // pop r15
+ emit_pop_r64(dst, REG_R14); // pop r14
+ emit_pop_r64(dst, REG_R13); // pop r13
+ emit_pop_r64(dst, REG_R12); // pop r12
+ emit_pop_r64(dst, REG_RBP); // pop rbp
+ emit_pop_r64(dst, REG_RDI); // pop rdi
+ emit_pop_r64(dst, REG_RSI); // pop rsi
+ emit_pop_r64(dst, REG_RBX); // pop rbx
+ emit_ret(dst); // ret
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, "exit_point", drcbe->exit, *dst);
+
+ /* generate a no code point */
+ drcbe->nocode = *dst;
+ emit_ret(dst); // ret
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, "nocode", drcbe->nocode, *dst);
+
+ /* finish up codegen */
+ drccache_end_codegen(drcbe->cache);
+
+ /* reset our hash tables */
+ drchash_reset(drcbe->hash);
+ drchash_set_default_codeptr(drcbe->hash, drcbe->nocode);
+}
+
+
+/*-------------------------------------------------
+ drcbex64_generate - generate code
+-------------------------------------------------*/
+
+static void drcbex64_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst)
+{
+ const char *blockname = NULL;
+ char blockbuffer[100];
+ drccodeptr *cachetop;
+ x86code *base;
+ x86code *dst;
+ int inum;
+
+ /* tell all of our utility objects that a block is beginning */
+ drchash_block_begin(drcbe->hash, block, instlist, numinst);
+ drclabel_block_begin(drcbe->labels, block);
+ drcmap_block_begin(drcbe->map, block);
+
+ /* begin codegen; fail if we can't */
+ cachetop = drccache_begin_codegen(drcbe->cache, numinst * 8 * 4);
+ if (cachetop == NULL)
+ drcuml_block_abort(block);
+
+ /* compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) */
+ base = (x86code *)(((FPTR)*cachetop + 63) & ~63);
+ dst = base;
+
+ /* generate code */
+ for (inum = 0; inum < numinst; inum++)
+ {
+ const drcuml_instruction *inst = &instlist[inum];
+ assert(inst->opcode < ARRAY_LENGTH(opcode_table));
+
+ /* add a comment */
+ if (drcbe->log != NULL)
+ {
+ char dasm[100];
+ drcuml_disasm(inst, dasm);
+ x86log_add_comment(drcbe->log, dst, "%s", dasm);
+ }
+
+ /* extract a blockname */
+ if (blockname == NULL)
+ {
+ if (inst->opcode == DRCUML_OP_HANDLE)
+ blockname = drcuml_handle_name((drcuml_codehandle *)(FPTR)inst->param[0].value);
+ else if (inst->opcode == DRCUML_OP_HASH)
+ {
+ sprintf(blockbuffer, "Code: mode=%d PC=%08X", (UINT32)inst->param[0].value, (offs_t)inst->param[1].value);
+ blockname = blockbuffer;
+ }
+ }
+
+ /* generate code */
+ dst = (*opcode_table[inst->opcode])(drcbe, dst, inst);
+ }
+
+ /* complete codegen */
+ *cachetop = (drccodeptr)dst;
+ drccache_end_codegen(drcbe->cache);
+
+ /* log it */
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, (blockname == NULL) ? "Unknown block" : blockname, base, drccache_top(drcbe->cache));
+
+ /* tell all of our utility objects that the block is finished */
+ drchash_block_end(drcbe->hash, block);
+ drclabel_block_end(drcbe->labels, block);
+ drcmap_block_end(drcbe->map, block);
+}
+
+
+/*-------------------------------------------------
+ drcbex64_hash_exists - return true if the
+ given mode/pc exists in the hash table
+-------------------------------------------------*/
+
+static int drcbex64_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc)
+{
+ return drchash_code_exists(drcbe->hash, mode, pc);
+}
+
+
+/*-------------------------------------------------
+ drcbec_execute - execute a block of code
+ registered at the given mode/pc
+-------------------------------------------------*/
+
+static int drcbex64_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
+{
+ /* call our entry point which will jump to the destination */
+ return (*drcbe->entry)(drcbe->rbpvalue, (x86code *)drcuml_handle_codeptr(entry));
+}
+
+
+
+/***************************************************************************
+ COMPILE HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ param_normalize - convert a full parameter
+ into a reduced set
+-------------------------------------------------*/
+
+static void param_normalize(drcbe_state *drcbe, const drcuml_parameter *src, drcuml_parameter *dest, UINT32 allowed)
+{
+ int regnum;
+
+ switch (src->type)
+ {
+ /* immediates pass through */
+ case DRCUML_PTYPE_IMMEDIATE:
+ assert(allowed & PTYPE_I);
+ dest->type = DRCUML_PTYPE_IMMEDIATE;
+ dest->value = src->value;
+ break;
+
+ /* mapvars are converted to immediates with their current value */
+ case DRCUML_PTYPE_MAPVAR:
+ assert(allowed & PTYPE_I);
+ dest->type = DRCUML_PTYPE_IMMEDIATE;
+ dest->value = drcmap_get_last_value(drcbe->map, src->value);
+ break;
+
+ /* memory passes through */
+ case DRCUML_PTYPE_MEMORY:
+ assert(allowed & PTYPE_M);
+ dest->type = DRCUML_PTYPE_MEMORY;
+ dest->value = (FPTR)src->value;
+ break;
+
+ /* if a register maps to a register, keep it as a register; otherwise map it to memory */
+ case DRCUML_PTYPE_INT_REGISTER:
+ assert(allowed & PTYPE_R);
+ assert(allowed & PTYPE_M);
+ regnum = int_register_map[src->value - DRCUML_REG_I0];
+ if (regnum != 0)
+ {
+ dest->type = DRCUML_PTYPE_INT_REGISTER;
+ dest->value = regnum;
+ }
+ else
+ {
+ dest->type = DRCUML_PTYPE_MEMORY;
+ dest->value = (FPTR)&drcbe->state.r[src->value - DRCUML_REG_I0];
+ }
+ break;
+
+ /* if a register maps to a register, keep it as a register; otherwise map it to memory */
+ case DRCUML_PTYPE_FLOAT_REGISTER:
+ assert(allowed & PTYPE_F);
+ assert(allowed & PTYPE_M);
+ regnum = float_register_map[src->value - DRCUML_REG_F0];
+ if (regnum != 0)
+ {
+ dest->type = DRCUML_PTYPE_FLOAT_REGISTER;
+ dest->value = regnum;
+ }
+ else
+ {
+ dest->type = DRCUML_PTYPE_MEMORY;
+ dest->value = (FPTR)&drcbe->state.f[src->value - DRCUML_REG_F0];
+ }
+ break;
+
+ /* everything else is unexpected */
+ default:
+ fatalerror("Unexpected parameter type");
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ param_normalize_1 - normalize a single
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_1(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0)
+{
+ assert(inst->numparams == 1);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_2 - normalize a 2
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_2(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1)
+{
+ assert(inst->numparams == 2);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+ param_normalize(drcbe, &inst->param[1], dest1, allowed1);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_2_commutative - normalize a 2
+ parameter instruction, shuffling the
+ parameters on the assumption that the two
+ parameters can be swapped
+-------------------------------------------------*/
+
+static void param_normalize_2_commutative(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1)
+{
+ param_normalize_2(drcbe, inst, dest0, allowed0, dest1, allowed1);
+
+ /* if the inner parameter is a memory operand, push it to the outer */
+ if (dest0->type == DRCUML_PTYPE_MEMORY)
+ {
+ drcuml_parameter temp = *dest0;
+ *dest0 = *dest1;
+ *dest1 = temp;
+ }
+
+ /* if the inner parameter is an immediate, push it to the outer */
+ if (dest0->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest0;
+ *dest0 = *dest1;
+ *dest1 = temp;
+ }
+}
+
+
+/*-------------------------------------------------
+ param_normalize_3 - normalize a 3
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_3(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2)
+{
+ assert(inst->numparams == 3);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+ param_normalize(drcbe, &inst->param[1], dest1, allowed1);
+ param_normalize(drcbe, &inst->param[2], dest2, allowed2);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_3_commutative - normalize a 3
+ parameter instruction, shuffling the
+ parameters on the assumption that the last
+ 2 can be swapped
+-------------------------------------------------*/
+
+static void param_normalize_3_commutative(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2)
+{
+ param_normalize_3(drcbe, inst, dest0, allowed0, dest1, allowed1, dest2, allowed2);
+
+ /* if the inner parameter is a memory operand, push it to the outer */
+ if (dest1->type == DRCUML_PTYPE_MEMORY)
+ {
+ drcuml_parameter temp = *dest1;
+ *dest1 = *dest2;
+ *dest2 = temp;
+ }
+
+ /* if the inner parameter is an immediate, push it to the outer */
+ if (dest1->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest1;
+ *dest1 = *dest2;
+ *dest2 = temp;
+ }
+
+ /* if the destination and outer parameters are equal, move the outer to the inner */
+ if (dest0->type == dest2->type && dest0->value == dest2->value && dest0->type != DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest1;
+ *dest1 = *dest2;
+ *dest2 = temp;
+ }
+}
+
+
+/*-------------------------------------------------
+ param_normalize_4 - normalize a 4
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_4(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2, drcuml_parameter *dest3, UINT32 allowed3)
+{
+ assert(inst->numparams == 4);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+ param_normalize(drcbe, &inst->param[1], dest1, allowed1);
+ param_normalize(drcbe, &inst->param[2], dest2, allowed2);
+ param_normalize(drcbe, &inst->param[3], dest3, allowed3);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_4_commutative - normalize a 4
+ parameter instruction, shuffling the
+ parameters on the assumption that the last
+ 2 can be swapped
+-------------------------------------------------*/
+
+static void param_normalize_4_commutative(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2, drcuml_parameter *dest3, UINT32 allowed3)
+{
+ param_normalize_4(drcbe, inst, dest0, allowed0, dest1, allowed1, dest2, allowed2, dest3, allowed3);
+
+ /* if the inner parameter is a memory operand, push it to the outer */
+ if (dest2->type == DRCUML_PTYPE_MEMORY)
+ {
+ drcuml_parameter temp = *dest2;
+ *dest2 = *dest3;
+ *dest3 = temp;
+ }
+
+ /* if the inner parameter is an immediate, push it to the outer */
+ if (dest2->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest2;
+ *dest2 = *dest3;
+ *dest3 = temp;
+ }
+
+ /* if the destination and outer parameters are equal, move the outer to the inner */
+ if (dest0->type == dest3->type && dest0->value == dest3->value && dest0->type != DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest2;
+ *dest2 = *dest3;
+ *dest3 = temp;
+ }
+}
+
+
+
+/***************************************************************************
+ EMITTERS FOR 32-BIT OPERATIONS WITH PARAMETERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_mov_r32_p32 - move a 32-bit parameter
+ into a register
+-------------------------------------------------*/
+
+static void emit_mov_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (param->value == 0)
+ emit_xor_r32_r32(dst, reg, reg); // xor reg,reg
+ else
+ emit_mov_r32_imm(dst, reg, param->value); // mov reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r32_m32(dst, reg, MABS(drcbe, param->value)); // mov reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_mov_r32_r32(dst, reg, param->value); // mov reg,param
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_mov_m32_p32 - move a 32-bit parameter
+ into a memory location
+-------------------------------------------------*/
+
+static void emit_mov_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(dst, MEMPARAMS, param->value); // mov [mem],param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r32_m32(dst, REG_EAX, MABS(drcbe, param->value)); // mov eax,[param]
+ emit_mov_m32_r32(dst, MEMPARAMS, REG_EAX); // mov [mem],eax
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_r32(dst, MEMPARAMS, param->value); // mov [mem],param
+}
+
+
+/*-------------------------------------------------
+ emit_mov_p32_r32 - move a register into a
+ 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_mov_p32_r32(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *param, UINT8 reg)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_r32(dst, MABS(drcbe, param->value), reg); // mov [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_mov_r32_r32(dst, param->value, reg); // mov param,reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_add_r32_p32 - add operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_add_r32_imm(dst, reg, param->value); // add reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_add_r32_m32(dst, reg, MABS(drcbe, param->value)); // add reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_add_r32_r32(dst, reg, param->value); // add reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_add_m32_p32 - add operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_add_m32_imm(dst, MEMPARAMS, param->value); // add [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_add_m32_r32(dst, MEMPARAMS, reg); // add [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_adc_r32_p32 - adc operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_adc_r32_imm(dst, reg, param->value); // adc reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_adc_r32_m32(dst, reg, MABS(drcbe, param->value)); // adc reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_adc_r32_r32(dst, reg, param->value); // adc reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_adc_m32_p32 - adc operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_adc_m32_imm(dst, MEMPARAMS, param->value); // adc [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_adc_m32_r32(dst, MEMPARAMS, reg); // adc [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sub_r32_p32 - sub operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sub_r32_imm(dst, reg, param->value); // sub reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_sub_r32_m32(dst, reg, MABS(drcbe, param->value)); // sub reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_sub_r32_r32(dst, reg, param->value); // sub reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_sub_m32_p32 - sub operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sub_m32_imm(dst, MEMPARAMS, param->value); // sub [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_sub_m32_r32(dst, MEMPARAMS, reg); // sub [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_r32_p32 - sbb operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sbb_r32_imm(dst, reg, param->value); // sbb reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_r32_m32(dst, reg, MABS(drcbe, param->value)); // sbb reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_sbb_r32_r32(dst, reg, param->value); // sbb reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_m32_p32 - sbb operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sbb_m32_imm(dst, MEMPARAMS, param->value); // sbb [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_sbb_m32_r32(dst, MEMPARAMS, reg); // sbb [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_r32_p32 - cmp operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_cmp_r32_imm(dst, reg, param->value); // cmp reg,param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_r32_m32(dst, reg, MABS(drcbe, param->value)); // cmp reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_cmp_r32_r32(dst, reg, param->value); // cmp reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_m32_p32 - cmp operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_cmp_m32_imm(dst, MEMPARAMS, param->value); // cmp [dest],param
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_cmp_m32_r32(dst, MEMPARAMS, reg); // cmp [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_and_r32_p32 - and operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0)
+ emit_xor_r32_r32(dst, reg, reg); // xor reg,reg
+ else
+ emit_and_r32_imm(dst, reg, param->value); // and reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_and_r32_m32(dst, reg, MABS(drcbe, param->value)); // and reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_and_r32_r32(dst, reg, param->value); // and reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_and_m32_p32 - and operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0)
+ emit_mov_m32_imm(dst, MEMPARAMS, 0); // mov [dest],0
+ else
+ emit_and_m32_imm(dst, MEMPARAMS, param->value); // and [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_and_m32_r32(dst, MEMPARAMS, reg); // and [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_test_r32_p32 - test operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_test_r32_imm(dst, reg, param->value); // test reg,param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_test_m32_r32(dst, MABS(drcbe, param->value), reg); // test [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_test_r32_r32(dst, reg, param->value); // test reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_test_m32_p32 - test operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_test_m32_imm(dst, MEMPARAMS, param->value); // test [dest],param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_EAX, param); // mov reg,param
+ emit_test_m32_r32(dst, MEMPARAMS, REG_EAX); // test [dest],reg
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_test_m32_r32(dst, MEMPARAMS, param->value); // test [dest],param
+}
+
+
+/*-------------------------------------------------
+ emit_or_r32_p32 - or operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_mov_r32_imm(dst, reg, -1); // mov reg,-1
+ else
+ emit_or_r32_imm(dst, reg, param->value); // or reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_or_r32_m32(dst, reg, MABS(drcbe, param->value)); // or reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_or_r32_r32(dst, reg, param->value); // or reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_or_m32_p32 - or operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_mov_m32_imm(dst, MEMPARAMS, -1); // mov [dest],-1
+ else
+ emit_or_m32_imm(dst, MEMPARAMS, param->value); // or [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_or_m32_r32(dst, MEMPARAMS, reg); // or [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_xor_r32_p32 - xor operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_not_r32(dst, reg); // not reg
+ else
+ emit_xor_r32_imm(dst, reg, param->value); // xor reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_xor_r32_m32(dst, reg, MABS(drcbe, param->value)); // xor reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_xor_r32_r32(dst, reg, param->value); // xor reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_xor_m32_p32 - xor operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_not_m32(dst, MEMPARAMS); // not [dest]
+ else
+ emit_xor_m32_imm(dst, MEMPARAMS, param->value); // xor [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_xor_m32_r32(dst, MEMPARAMS, reg); // xor [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shl_r32_p32 - shl operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shl_r32_imm(dst, reg, param->value); // shl reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shl_r32_cl(dst, reg); // shl reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shl_m32_p32 - shl operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shl_m32_imm(dst, MEMPARAMS, param->value); // shl [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shl_m32_cl(dst, MEMPARAMS); // shl [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shr_r32_p32 - shr operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shr_r32_imm(dst, reg, param->value); // shr reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shr_r32_cl(dst, reg); // shr reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shr_m32_p32 - shr operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shr_m32_imm(dst, MEMPARAMS, param->value); // shr [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shr_m32_cl(dst, MEMPARAMS); // shr [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sar_r32_p32 - sar operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_sar_r32_imm(dst, reg, param->value); // sar reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_sar_r32_cl(dst, reg); // sar reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sar_m32_p32 - sar operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_sar_m32_imm(dst, MEMPARAMS, param->value); // sar [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_sar_m32_cl(dst, MEMPARAMS); // sar [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rol_r32_p32 - rol operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rol_r32_imm(dst, reg, param->value); // rol reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rol_r32_cl(dst, reg); // rol reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rol_m32_p32 - rol operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rol_m32_imm(dst, MEMPARAMS, param->value); // rol [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rol_m32_cl(dst, MEMPARAMS); // rol [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_ror_r32_p32 - ror operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_ror_r32_imm(dst, reg, param->value); // ror reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_ror_r32_cl(dst, reg); // ror reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_ror_m32_p32 - ror operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_ror_m32_imm(dst, MEMPARAMS, param->value); // ror [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_ror_m32_cl(dst, MEMPARAMS); // ror [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_r32_p32 - rcl operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcl_r32_imm(dst, reg, param->value); // rcl reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcl_r32_cl(dst, reg); // rcl reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_m32_p32 - rcl operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcl_m32_imm(dst, MEMPARAMS, param->value); // rcl [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcl_m32_cl(dst, MEMPARAMS); // rcl [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_r32_p32 - rcr operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcr_r32_imm(dst, reg, param->value); // rcr reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcr_r32_cl(dst, reg); // rcr reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_m32_p32 - rcr operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcr_m32_imm(dst, MEMPARAMS, param->value); // rcr [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcr_m32_cl(dst, MEMPARAMS); // rcr [dest],cl
+ }
+}
+
+
+
+/***************************************************************************
+ EMITTERS FOR 64-BIT OPERATIONS WITH PARAMETERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_mov_r64_p64 - move a 64-bit parameter
+ into a register
+-------------------------------------------------*/
+
+static void emit_mov_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (param->value == 0)
+ emit_xor_r32_r32(dst, reg, reg); // xor reg,reg
+ else
+ emit_mov_r64_imm(dst, reg, param->value); // mov reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r64_m64(dst, reg, MABS(drcbe, param->value)); // mov reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_mov_r64_r64(dst, reg, param->value); // mov reg,param
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_mov_m64_p64 - move a 64-bit parameter
+ into a memory location
+-------------------------------------------------*/
+
+static void emit_mov_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (short_immediate(param->value))
+ emit_mov_m64_imm(dst, MEMPARAMS, param->value); // mov [mem],param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_RAX, param->value); // mov rax,[param]
+ emit_mov_m64_r64(dst, MEMPARAMS, REG_RAX); // mov [mem],rax
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r64_m64(dst, REG_RAX, MABS(drcbe, param->value)); // mov rax,[param]
+ emit_mov_m64_r64(dst, MEMPARAMS, REG_EAX); // mov [mem],rax
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m64_r64(dst, MEMPARAMS, param->value); // mov [mem],param
+}
+
+
+/*-------------------------------------------------
+ emit_mov_p64_r64 - move a registers into a
+ 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_mov_p64_r64(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *param, UINT8 reg)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m64_r64(dst, MABS(drcbe, param->value), reg); // mov [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_mov_r64_r64(dst, param->value, reg); // mov param,reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_add_r64_p64 - add operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (short_immediate(param->value))
+ emit_add_r64_imm(dst, reg, param->value); // add reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_add_r64_r64(dst, reg, REG_R11); // add reg,r11
+ }
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_add_r64_m64(dst, reg, MABS(drcbe, param->value)); // add reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_add_r64_r64(dst, reg, param->value); // add reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_add_m64_p64 - add operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (short_immediate(param->value))
+ emit_add_m64_imm(dst, MEMPARAMS, param->value); // add [mem],param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_add_m64_r64(dst, MEMPARAMS, REG_R11); // add [mem],r11
+ }
+ }
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_add_m64_r64(dst, MEMPARAMS, reg); // add [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_adc_r64_p64 - adc operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (short_immediate(param->value))
+ emit_adc_r64_imm(dst, reg, param->value); // adc reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_adc_r64_r64(dst, reg, REG_R11); // adc reg,r11
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_adc_r64_m64(dst, reg, MABS(drcbe, param->value)); // adc reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_adc_r64_r64(dst, reg, param->value); // adc reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_adc_m64_p64 - adc operation to a 64-bit
+ memory locaiton from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE && short_immediate(param->value))
+ emit_adc_m64_imm(dst, MEMPARAMS, param->value); // adc [mem],param
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_adc_m64_r64(dst, MEMPARAMS, reg); // adc [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sub_r64_p64 - sub operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (short_immediate(param->value))
+ emit_sub_r64_imm(dst, reg, param->value); // sub reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_sub_r64_r64(dst, reg, REG_R11); // sub reg,r11
+ }
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_sub_r64_m64(dst, reg, MABS(drcbe, param->value)); // sub reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_sub_r64_r64(dst, reg, param->value); // sub reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_sub_m64_p64 - sub operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (short_immediate(param->value))
+ emit_sub_m64_imm(dst, MEMPARAMS, param->value); // sub [mem],param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_sub_m64_r64(dst, MEMPARAMS, REG_R11); // sub [mem],r11
+ }
+ }
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_sub_m64_r64(dst, MEMPARAMS, reg); // sub [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_r64_p64 - sbb operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (short_immediate(param->value))
+ emit_sbb_r64_imm(dst, reg, param->value); // sbb reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_sbb_r64_r64(dst, reg, REG_R11); // sbb reg,r11
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_r64_m64(dst, reg, MABS(drcbe, param->value)); // sbb reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_sbb_r64_r64(dst, reg, param->value); // sbb reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_m64_p64 - sbb operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE && short_immediate(param->value))
+ emit_sbb_m64_imm(dst, MEMPARAMS, param->value); // sbb [mem],param
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_sbb_m64_r64(dst, MEMPARAMS, reg); // sbb [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_r64_p64 - cmp operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (short_immediate(param->value))
+ emit_cmp_r64_imm(dst, reg, param->value); // cmp reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_cmp_r64_r64(dst, reg, REG_R11); // cmp reg,r11
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_r64_m64(dst, reg, MABS(drcbe, param->value)); // cmp reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_cmp_r64_r64(dst, reg, param->value); // cmp reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_m64_p64 - cmp operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE && short_immediate(param->value))
+ emit_cmp_m64_imm(dst, MEMPARAMS, param->value); // cmp [dest],param
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_cmp_m64_r64(dst, MEMPARAMS, reg); // cmp [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_and_r64_p64 - and operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != U64(0xffffffffffffffff))
+ {
+ if (short_immediate(param->value))
+ emit_and_r64_imm(dst, reg, param->value); // and reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_and_r64_r64(dst, reg, REG_R11); // and reg,r11
+ }
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_and_r64_m64(dst, reg, MABS(drcbe, param->value)); // and reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_and_r64_r64(dst, reg, param->value); // and reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_and_m64_p64 - and operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != U64(0xffffffffffffffff))
+ {
+ if (short_immediate(param->value))
+ emit_and_m64_imm(dst, MEMPARAMS, param->value); // and [mem],param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_and_m64_r64(dst, MEMPARAMS, REG_R11); // and [mem],r11
+ }
+ }
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_and_m64_r64(dst, MEMPARAMS, reg); // and [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_test_r64_p64 - test operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (short_immediate(param->value))
+ emit_test_r64_imm(dst, reg, param->value); // test reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_test_r64_r64(dst, reg, REG_R11); // test reg,r11
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_test_m64_r64(dst, MABS(drcbe, param->value), reg); // test [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_test_r64_r64(dst, reg, param->value); // test reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_test_m64_p64 - test operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE && short_immediate(param->value))
+ emit_test_m64_imm(dst, MEMPARAMS, param->value); // test [dest],param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_EAX, param); // mov reg,param
+ emit_test_m64_r64(dst, MEMPARAMS, REG_EAX); // test [dest],reg
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_test_m64_r64(dst, MEMPARAMS, param->value); // test [dest],param
+}
+
+
+/*-------------------------------------------------
+ emit_or_r64_p64 - or operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (short_immediate(param->value))
+ emit_or_r64_imm(dst, reg, param->value); // or reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_or_r64_r64(dst, reg, REG_R11); // or reg,r11
+ }
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_or_r64_m64(dst, reg, MABS(drcbe, param->value)); // or reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_or_r64_r64(dst, reg, param->value); // or reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_or_m64_p64 - or operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (short_immediate(param->value))
+ emit_or_m64_imm(dst, MEMPARAMS, param->value); // or [mem],param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_or_m64_r64(dst, MEMPARAMS, REG_R11); // or [mem],r11
+ }
+ }
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_or_m64_r64(dst, MEMPARAMS, reg); // or [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_xor_r64_p64 - xor operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (param->value == U64(0xffffffffffffffff))
+ emit_not_r64(dst, reg); // not reg
+ else if (short_immediate(param->value))
+ emit_xor_r64_imm(dst, reg, param->value); // xor reg,param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_xor_r64_r64(dst, reg, REG_R11); // xor reg,r11
+ }
+ }
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_xor_r64_m64(dst, reg, MABS(drcbe, param->value)); // xor reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_xor_r64_r64(dst, reg, param->value); // xor reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_xor_m64_p64 - xor operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ {
+ if (param->value == U64(0xffffffffffffffff))
+ emit_not_m64(dst, MEMPARAMS); // not [mem]
+ else if (short_immediate(param->value))
+ emit_xor_m64_imm(dst, MEMPARAMS, param->value); // xor [mem],param
+ else
+ {
+ emit_mov_r64_imm(dst, REG_R11, param->value); // mov r11,param
+ emit_xor_m64_r64(dst, MEMPARAMS, REG_R11); // xor [mem],r11
+ }
+ }
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r64_p64(drcbe, dst, reg, param); // mov reg,param
+ emit_xor_m64_r64(dst, MEMPARAMS, reg); // xor [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shl_r64_p64 - shl operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shl_r64_imm(dst, reg, param->value); // shl reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_shl_r64_cl(dst, reg); // shl reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shl_m64_p64 - shl operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_shl_m64_imm(dst, MEMPARAMS, param->value); // shl [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_shl_m64_cl(dst, MEMPARAMS); // shl [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shr_r64_p64 - shr operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shr_r64_imm(dst, reg, param->value); // shr reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_shr_r64_cl(dst, reg); // shr reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shr_m64_p64 - shr operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_shr_m64_imm(dst, MEMPARAMS, param->value); // shr [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_shr_m64_cl(dst, MEMPARAMS); // shr [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sar_r64_p64 - sar operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_sar_r64_imm(dst, reg, param->value); // sar reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_sar_r64_cl(dst, reg); // sar reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sar_m64_p64 - sar operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_sar_m64_imm(dst, MEMPARAMS, param->value); // sar [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_sar_m64_cl(dst, MEMPARAMS); // sar [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rol_r64_p64 - rol operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rol_r64_imm(dst, reg, param->value); // rol reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_rol_r64_cl(dst, reg); // rol reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rol_m64_p64 - rol operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_rol_m64_imm(dst, MEMPARAMS, param->value); // rol [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_rol_m64_cl(dst, MEMPARAMS); // rol [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_ror_r64_p64 - ror operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_ror_r64_imm(dst, reg, param->value); // ror reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_ror_r64_cl(dst, reg); // ror reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_ror_m64_p64 - ror operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_ror_m64_imm(dst, MEMPARAMS, param->value); // ror [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_ror_m64_cl(dst, MEMPARAMS); // ror [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_r64_p64 - rcl operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcl_r64_imm(dst, reg, param->value); // rcl reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_rcl_r64_cl(dst, reg); // rcl reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_m64_p64 - rcl operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_rcl_m64_imm(dst, MEMPARAMS, param->value); // rcl [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_rcl_m64_cl(dst, MEMPARAMS); // rcl [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_r64_p64 - rcr operation to a 64-bit
+ register from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcr_r64_imm(dst, reg, param->value); // rcr reg,param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_rcr_r64_cl(dst, reg); // rcr reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_m64_p64 - rcr operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT64)param->value == 0)
+ /* skip */;
+ else
+ emit_rcr_m64_imm(dst, MEMPARAMS, param->value); // rcr [dest],param
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, dst, REG_RCX, param); // mov rcx,param
+ emit_rcr_m64_cl(dst, MEMPARAMS); // rcr [dest],cl
+ }
+}
+
+
+
+/***************************************************************************
+ EMITTERS FOR FLOATING POINT OPERATIONS WITH PARAMETERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_movss_r128_p32 - move a 32-bit parameter
+ into a register
+-------------------------------------------------*/
+
+static void emit_movss_r128_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_movss_r128_m32(dst, reg, MABS(drcbe, param->value)); // movss reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_movss_r128_r128(dst, reg, param->value); // movss reg,param
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_movss_m32_p32 - move a 32-bit parameter
+ into a memory location
+-------------------------------------------------*/
+
+static void emit_movss_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_movss_r128_m32(dst, REG_XMM0, MABS(drcbe, param->value)); // movss xmm0,[param]
+ emit_movss_m32_r128(dst, MEMPARAMS, REG_XMM0); // movss [mem],xmm0
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movss_m32_r128(dst, MEMPARAMS, param->value); // movss [mem],xmm0
+}
+
+
+/*-------------------------------------------------
+ emit_movss_p32_r128 - move a register into a
+ 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_movss_p32_r128(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *param, UINT8 reg)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_movss_m32_r128(dst, MABS(drcbe, param->value), reg); // movss [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_movss_r128_r128(dst, param->value, reg); // movss param,reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_movsd_r128_p64 - move a 64-bit parameter
+ into a register
+-------------------------------------------------*/
+
+static void emit_movsd_r128_p64(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_movsd_r128_m64(dst, reg, MABS(drcbe, param->value)); // movsd reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_movsd_r128_r128(dst, reg, param->value); // movsd reg,param
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_movsd_m64_p64 - move a 64-bit parameter
+ into a memory location
+-------------------------------------------------*/
+
+static void emit_movsd_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_movsd_r128_m64(dst, REG_XMM0, MABS(drcbe, param->value)); // movsd xmm0,[param]
+ emit_movsd_m64_r128(dst, MEMPARAMS, REG_XMM0); // movsd [mem],xmm0
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsd_m64_r128(dst, MEMPARAMS, param->value); // movsd [mem],xmm0
+}
+
+
+/*-------------------------------------------------
+ emit_movsd_p64_r128 - move a register into a
+ 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_movsd_p64_r128(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *param, UINT8 reg)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_movsd_m64_r128(dst, MABS(drcbe, param->value), reg); // movsd [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_movsd_r128_r128(dst, param->value, reg); // movsd param,reg
+ }
+}
+
+
+
+/***************************************************************************
+ HELPERS TO CONVERT OTHER OPERATIONS TO MOVES
+***************************************************************************/
+
+/*-------------------------------------------------
+ convert_to_mov_imm - convert an instruction
+ into a mov immediate
+-------------------------------------------------*/
+
+static x86code *convert_to_mov_imm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, const drcuml_parameter *dstp, UINT64 imm)
+{
+ drcuml_instruction temp = *inst;
+ temp.numparams = 2;
+ temp.param[0] = *dstp;
+ temp.param[1].type = DRCUML_PTYPE_IMMEDIATE;
+ temp.param[1].value = imm;
+ return op_mov(drcbe, dst, &temp);
+}
+
+
+/*-------------------------------------------------
+ convert_to_mov_src1 - convert an instruction
+ into a mov src1
+-------------------------------------------------*/
+
+static x86code *convert_to_mov_src1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, const drcuml_parameter *dstp, const drcuml_parameter *srcp)
+{
+ drcuml_instruction temp = *inst;
+ temp.numparams = 2;
+ temp.param[0] = *dstp;
+ temp.param[1] = *srcp;
+ return op_mov(drcbe, dst, &temp);
+}
+
+
+
+/***************************************************************************
+ OUT-OF-BAND CODE FIXUP CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ fixup_label - callback to fixup forward-
+ referenced labels
+-------------------------------------------------*/
+
+static void fixup_label(void *parameter, drccodeptr labelcodeptr)
+{
+ drccodeptr src = parameter;
+
+ /* find the end of the instruction */
+ if (src[0] == 0xe3)
+ {
+ src += 1 + 1;
+ src[-1] = labelcodeptr - src;
+ }
+ else if (src[0] == 0xe9)
+ {
+ src += 1 + 4;
+ ((UINT32 *)src)[-1] = labelcodeptr - src;
+ }
+ else if (src[0] == 0x0f && (src[1] & 0xf0) == 0x80)
+ {
+ src += 2 + 4;
+ ((UINT32 *)src)[-1] = labelcodeptr - src;
+ }
+ else
+ fatalerror("fixup_label called with invalid jmp source!");
+}
+
+
+/*-------------------------------------------------
+ fixup_exception - callback to perform cleanup
+ and jump to an exception handler
+-------------------------------------------------*/
+
+static void fixup_exception(drccodeptr *codeptr, void *param1, void *param2, void *param3)
+{
+ drcuml_parameter handp, exp;
+ drcbe_state *drcbe = param1;
+ drccodeptr src = param2;
+ const drcuml_instruction *inst = param3;
+ drccodeptr dst = *codeptr;
+ drccodeptr *targetptr;
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &handp, PTYPE_M, &exp, PTYPE_MRI);
+
+ /* look up the handle target */
+ targetptr = drcuml_handle_codeptr_addr((drcuml_codehandle *)handp.value);
+
+ /* first fixup the jump to get us here */
+ ((UINT32 *)src)[-1] = dst - src;
+
+ /* then store the exception parameter */
+ emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp), &exp); // mov [exp],exp
+
+ /* push the original return address on the stack */
+ emit_lea_r64_m64(&dst, REG_RAX, MABS(drcbe, src)); // lea rax,[return]
+ emit_push_r64(&dst, REG_RAX); // push rax
+ if (*targetptr != NULL)
+ emit_jmp(&dst, *targetptr); // jmp *targetptr
+ else
+ emit_jmp_m64(&dst, MABS(drcbe, targetptr)); // jmp [targetptr]
+
+ *codeptr = dst;
+}
+
+
+
+/***************************************************************************
+ DEBUG HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_log_hashjmp - callback to handle
+ logging of hashjmps
+-------------------------------------------------*/
+
+#if LOG_HASHJMPS
+static void debug_log_hashjmp(int mode, offs_t pc)
+{
+ printf("mode=%d PC=%08X\n", mode, pc);
+}
+#endif
+
+
+
+/***************************************************************************
+ COMPILE-TIME OPCODES
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_handle - process a HANDLE opcode
+-------------------------------------------------*/
+
+static x86code *op_handle(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_MEMORY);
+
+ /* register the current pointer for the handle */
+ drcuml_handle_set_codeptr((drcuml_codehandle *)(FPTR)inst->param[0].value, dst);
+
+ /* by default, the handle points to prolog code that moves the stack pointer */
+ emit_sub_r64_imm(&dst, REG_RSP, 40); // sub rsp,40
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_hash - process a HASH opcode
+-------------------------------------------------*/
+
+static x86code *op_hash(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 2);
+ assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
+ assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
+
+ /* register the current pointer for the mode/PC */
+ drchash_set_codeptr(drcbe->hash, inst->param[0].value, inst->param[1].value, dst);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_label - process a LABEL opcode
+-------------------------------------------------*/
+
+static x86code *op_label(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
+
+ /* register the current pointer for the label */
+ drclabel_set_codeptr(drcbe->labels, inst->param[0].value, dst);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_comment - process a COMMENT opcode
+-------------------------------------------------*/
+
+static x86code *op_comment(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_MEMORY);
+
+ /* do nothing */
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_mapvar - process a MAPVAR opcode
+-------------------------------------------------*/
+
+static x86code *op_mapvar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 2);
+ assert(inst->param[0].type == DRCUML_PTYPE_MAPVAR);
+ assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
+
+ /* set the value of the specified mapvar */
+ drcmap_set_value(drcbe->map, dst, inst->param[0].value, inst->param[1].value);
+ return dst;
+}
+
+
+
+/***************************************************************************
+ CONTROL FLOW OPCODES
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_debug - process a DEBUG opcode
+-------------------------------------------------*/
+
+static x86code *op_debug(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+#ifdef ENABLE_DEBUGGER
+ if (Machine->debug_mode)
+ {
+ drcuml_parameter pcp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &pcp, PTYPE_MRI);
+
+ /* push the parameter */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &pcp); // mov param1,pcp
+ emit_smart_call_m64(drcbe, &dst, &drcbe->mame_debug_hook); // call mame_debug_hook
+ }
+#endif
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_exit - process an EXIT opcode
+-------------------------------------------------*/
+
+static x86code *op_exit(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter retp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &retp, PTYPE_MRI);
+
+ /* load the parameter into EAX */
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &retp); // mov eax,retp
+ if (inst->condflags == DRCUML_COND_ALWAYS)
+ emit_jmp(&dst, drcbe->exit); // jmp exit
+ else
+ emit_jcc(&dst, X86_CONDITION(inst->condflags), drcbe->exit); // jcc exit
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_hashjmp - process a HASHJMP opcode
+-------------------------------------------------*/
+
+static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter modep, pcp, exp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &modep, PTYPE_MRI, &pcp, PTYPE_MRI, &exp, PTYPE_M);
+
+#if LOG_HASHJMPS
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &pcp);
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &modep);
+ emit_smart_call_m64(drcbe, &dst, &drcbe->debug_log_hashjmp);
+#endif
+
+ /* load the stack base one word early so we end up at the right spot after our call below */
+ emit_mov_r64_m64(&dst, REG_RSP, MABS(drcbe, &drcbe->hashstacksave)); // mov rsp,[hashstacksave]
+
+ /* fixed mode cases */
+ if (modep.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ /* a straight immediate jump is direct, though we need the PC in EAX in case of failure */
+ if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask;
+ UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask;
+ emit_call_m64(&dst, MABS(drcbe, &drcbe->hash->base[modep.value][l1val][l2val]));
+ // call hash[modep][l1val][l2val]
+ }
+
+ /* a fixed mode but variable PC */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
+ emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
+ emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift
+ emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift
+ emit_mov_r64_m64(&dst, REG_RDX, MBISD(REG_RBP, REG_RDX, 8, offset_from_rbp(drcbe, (FPTR)&drcbe->hash->base[modep.value][0])));
+ // mov rdx,hash[modep+edx*8]
+ emit_call_m64(&dst, MBISD(REG_RDX, REG_RAX, 8 >> drcbe->hash->l2shift, 0)); // call [rdx+rax*shift]
+ }
+ }
+ else
+ {
+ /* variable mode */
+ int modereg = param_select_register(REG_ECX, &modep, NULL);
+ emit_mov_r32_p32(drcbe, &dst, modereg, &modep); // mov modereg,modep
+ emit_mov_r64_m64(&dst, REG_RCX, MBISD(REG_RBP, modereg, 8, offset_from_rbp(drcbe, (FPTR)&drcbe->hash->base[0])));
+ // mov rcx,hash[modereg*8]
+
+ /* fixed PC */
+ if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask;
+ UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask;
+ emit_mov_r64_m64(&dst, REG_RDX, MBD(REG_RCX, l1val*8)); // mov rdx,[rcx+l1val*8]
+ emit_call_m64(&dst, MBD(REG_RDX, l2val*8)); // call [l2val*8]
+ }
+
+ /* variable PC */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
+ emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
+ emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift
+ emit_mov_r64_m64(&dst, REG_RDX, MBISD(REG_RCX, REG_RDX, 8, 0)); // mov rdx,[rcx+rdx*8]
+ emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift
+ emit_call_m64(&dst, MBISD(REG_RDX, REG_RAX, 8 >> drcbe->hash->l2shift, 0)); // call [rdx+rax*shift]
+ }
+ }
+
+ /* in all cases, if there is no code, we return here to generate the exception */
+ emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp.l), &pcp); // mov [exp],param
+ emit_sub_r64_imm(&dst, REG_RSP, 8); // sub rsp,8
+ emit_call_m64(&dst, MABS(drcbe, exp.value)); // call [exp]
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_jmp - process a JMP opcode
+-------------------------------------------------*/
+
+static x86code *op_jmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter labelp;
+ x86code *jmptarget;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &labelp, PTYPE_I);
+
+ /* look up the jump target and jump there */
+ jmptarget = (x86code *)drclabel_get_codeptr(drcbe->labels, labelp.value, fixup_label, dst);
+ if (jmptarget == NULL)
+ jmptarget = dst + 0x7ffffff0;
+ if (inst->condflags == DRCUML_COND_ALWAYS)
+ emit_jmp(&dst, jmptarget); // jmp target
+ else
+ emit_jcc(&dst, X86_CONDITION(inst->condflags), jmptarget); // jcc target
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_exh - process an EXH opcode
+-------------------------------------------------*/
+
+static x86code *op_exh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter handp, exp;
+ drccodeptr *targetptr;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &handp, PTYPE_M, &exp, PTYPE_MRI);
+
+ /* look up the handle target */
+ targetptr = drcuml_handle_codeptr_addr((drcuml_codehandle *)handp.value);
+
+ /* perform the exception processing inline if unconditional */
+ if (inst->condflags == DRCUML_COND_ALWAYS)
+ {
+ emit_mov_m32_p32(drcbe, &dst, MABS(drcbe, &drcbe->state.exp.l), &exp); // mov [exp],exp
+ if (*targetptr != NULL)
+ emit_call(&dst, *targetptr); // call *targetptr
+ else
+ emit_call_m64(&dst, MABS(drcbe, targetptr)); // call [targetptr]
+ }
+
+ /* otherwise, jump to an out-of-band handler */
+ else
+ {
+ emit_jcc(&dst, X86_CONDITION(inst->condflags), dst + 0x7ffffff0); // jcc exception
+ drccache_request_oob_codegen(drcbe->cache, fixup_exception, drcbe, dst, (void *)inst);
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_callh - process a CALLH opcode
+-------------------------------------------------*/
+
+static x86code *op_callh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter handp;
+ drccodeptr *targetptr;
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &handp, PTYPE_M);
+
+ /* look up the handle target */
+ targetptr = drcuml_handle_codeptr_addr((drcuml_codehandle *)handp.value);
+
+ /* skip if conditional */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* jump through the handle; directly if a normal jump */
+ if (*targetptr != NULL)
+ emit_call(&dst, *targetptr); // call *targetptr
+ else
+ emit_call_m64(&dst, MABS(drcbe, targetptr)); // call [targetptr]
+
+ /* resolve the conditional link */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ret - process a RET opcode
+-------------------------------------------------*/
+
+static x86code *op_ret(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+ assert(inst->numparams == 0);
+
+ /* skip if conditional */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* return */
+ emit_add_r64_imm(&dst, REG_RSP, 40); // add rsp,40
+ emit_ret(&dst); // ret
+
+ /* resolve the conditional link */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_callc - process a CALLC opcode
+-------------------------------------------------*/
+
+static x86code *op_callc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter funcp, paramp;
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &funcp, PTYPE_M, &paramp, PTYPE_M);
+
+ /* skip if conditional */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* perform the call */
+ emit_mov_r64_imm(&dst, REG_PARAM1, paramp.value); // mov param1,paramp
+ emit_smart_call_r64(drcbe, &dst, (x86code *)(FPTR)funcp.value, REG_RAX); // call funcp
+
+ /* resolve the conditional link */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_recover - process a RECOVER opcode
+-------------------------------------------------*/
+
+static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, mvparam;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &mvparam, PTYPE_I);
+
+ /* call the recovery code */
+ emit_mov_r64_m64(&dst, REG_RAX, MABS(drcbe, &drcbe->stacksave)); // mov rax,stacksave
+ emit_mov_r64_m64(&dst, REG_RAX, MBD(REG_RAX, -8)); // mov rax,[rax-4]
+ emit_mov_r64_imm(&dst, REG_PARAM1, (FPTR)drcbe->map); // mov param1,drcbe->map
+ emit_lea_r64_m64(&dst, REG_PARAM2, MBD(REG_RAX, -1)); // lea param2,[rax-1]
+ emit_mov_r64_imm(&dst, REG_PARAM3, inst->param[1].value); // mov param3,param[1].value
+ emit_smart_call_m64(drcbe, &dst, &drcbe->drcmap_get_value); // call drcmap_get_value
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+
+ return dst;
+}
+
+
+
+/***************************************************************************
+ INTERNAL REGISTER OPCODES
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_setfmod - process a SETFMOD opcode
+-------------------------------------------------*/
+
+static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &srcp, PTYPE_MRI);
+
+ /* immediate case */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ srcp.value &= 3;
+ emit_mov_m8_imm(&dst, MABS(drcbe, &drcbe->state.fmod), srcp.value); // mov [fmod],srcp
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[srcp.value])); // ldmxcsr fp_control[srcp]
+ }
+
+ /* register/memory case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &srcp); // mov eax,srcp
+ emit_and_r32_imm(&dst, REG_EAX, 3); // and eax,3
+ emit_mov_m8_r8(&dst, MABS(drcbe, &drcbe->state.fmod), REG_AL); // mov [fmod],al
+ emit_ldmxcsr_m32(&dst, MBISD(REG_RBP, REG_RAX, 4, offset_from_rbp(drcbe, (FPTR)&drcbe->ssecontrol[0])));
+ // ldmxcsr fp_control[eax]
+ }
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_getfmod - process a GETFMOD opcode
+-------------------------------------------------*/
+
+static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &dstp, PTYPE_MR);
+
+ /* fetch the current mode and store to the destination */
+ if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_m8(&dst, dstp.value, MABS(drcbe, &drcbe->state.fmod)); // movzx reg,[fmod]
+ else
+ {
+ emit_movzx_r32_m8(&dst, REG_EAX, MABS(drcbe, &drcbe->state.fmod)); // movzx eax,[fmod]
+ emit_mov_m32_r32(&dst, MABS(drcbe, dstp.value), REG_EAX); // mov [dstp],eax
+ }
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_getexp - process a GETEXP opcode
+-------------------------------------------------*/
+
+static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &dstp, PTYPE_MR);
+
+ /* fetch the exception parameter and store to the destination */
+ if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe, &drcbe->state.exp.l)); // mov reg,[exp]
+ else
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS(drcbe, &drcbe->state.exp.l)); // mov eax,[exp]
+ emit_mov_m32_r32(&dst, MABS(drcbe, dstp.value), REG_EAX); // mov [dstp],eax
+ }
+
+ return dst;
+}
+
+
+
+/***************************************************************************
+ INTEGER OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_load1u - process a LOAD1U opcode
+-------------------------------------------------*/
+
+static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movzx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movzx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movzx dstreg,[basep + 1*indp]
+ }
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load1s - process a LOAD1S opcode
+-------------------------------------------------*/
+
+static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx eax,[basep + 1*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx eax,[basep + 1*indp]
+ }
+
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsx_r64_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx rax,[basep + 1*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsx_r64_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx rax,[basep + 1*indp]
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load2u - process a LOAD2U opcode
+-------------------------------------------------*/
+
+static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movzx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movzx dstreg,[basep + 2*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movzx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movzx dstreg,[basep + 2*indp]
+ }
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load2s - process a LOAD2S opcode
+-------------------------------------------------*/
+
+static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movsx eax,[basep + 2*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx eax,[basep + 2*indp]
+ }
+
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsx_r64_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movsx rax,[basep + 2*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsx_r64_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx rax,[basep + 2*indp]
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load4u - process a LOAD4U opcode
+-------------------------------------------------*/
+
+static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp]
+ }
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load4s - process a LOAD4S opcode
+-------------------------------------------------*/
+
+static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsxd_r64_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsxd_r64_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // movsx dstreg,[basep + 4*indp]
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load8u - process a LOAD8U opcode
+-------------------------------------------------*/
+
+static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp]
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,edx:dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store1 - process a STORE1 opcode
+-------------------------------------------------*/
+
+static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int basereg, srcreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m8_imm(&dst, MBD(basereg, baseoffs + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m8_r8(&dst, MBD(basereg, baseoffs + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m8_imm(&dst, MBISD(basereg, indreg, 1, baseoffs), srcp.value); // mov [basep + 1*ecx],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m8_r8(&dst, MBISD(basereg, indreg, 1, baseoffs), srcreg); // mov [basep + 1*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store2 - process a STORE2 opcode
+-------------------------------------------------*/
+
+static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int basereg, srcreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m16_imm(&dst, MBD(basereg, baseoffs + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m16_r16(&dst, MBD(basereg, baseoffs + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m16_imm(&dst, MBISD(basereg, indreg, 2, baseoffs), srcp.value); // mov [basep + 2*ecx],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m16_r16(&dst, MBISD(basereg, indreg, 2, baseoffs), srcreg); // mov [basep + 2*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store4 - process a STORE4 opcode
+-------------------------------------------------*/
+
+static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int basereg, srcreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m32_r32(&dst, MBD(basereg, baseoffs + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 4, baseoffs), srcp.value); // mov [basep + 4*ecx],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m32_r32(&dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // mov [basep + 4*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store8 - process a STORE8 opcode
+-------------------------------------------------*/
+
+static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int basereg, srcreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value))
+ emit_mov_m64_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m64_r64(&dst, MBD(basereg, baseoffs + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value))
+ emit_mov_m64_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value); // mov [basep + 8*ecx],srcp
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m64_r64(&dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // mov [basep + 8*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read1u - process a READ1U opcode
+-------------------------------------------------*/
+
+static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read byte handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_byte);// call read_byte
+ emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read1s - process a READ1S opcode
+-------------------------------------------------*/
+
+static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read byte handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_byte);// call read_byte
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_movsx_r32_r8(&dst, dstreg, REG_AL); // movsx dstreg,al
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* general case */
+ emit_movsx_r64_r8(&dst, dstreg, REG_AL); // movsx dstreg,al
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read2u - process a READ2U opcode
+-------------------------------------------------*/
+
+static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read word handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word);// call read_word
+ emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read2s - process a READ2S opcode
+-------------------------------------------------*/
+
+static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read word handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word);// call read_word
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_movsx_r32_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* general case */
+ emit_movsx_r64_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read2m - process a READ2M opcode
+-------------------------------------------------*/
+
+static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp, maskp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read dword masked handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param1,maskp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word_masked);// call read_word_masked
+ emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read4u - process a READ4U opcode
+-------------------------------------------------*/
+
+static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read dword handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read4s - process a READ4S opcode
+-------------------------------------------------*/
+
+static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read dword handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword
+
+ /* 64-bit form */
+ emit_movsxd_r64_r32(&dst, dstreg, REG_EAX); // movsxd dstreg,eax
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read4m - process a READ4M opcode
+-------------------------------------------------*/
+
+static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp, maskp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI);
+
+ /* set up a call to the read dword masked handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword_masked);// call read_dword_masked
+
+ /* store to appropriate target size */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read8u - process a READ8U opcode
+-------------------------------------------------*/
+
+static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read qword handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword);// call read_qword
+
+ /* 64-bit form */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read8m - process a READ8M opcode
+-------------------------------------------------*/
+
+static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp, maskp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI);
+
+ /* set up a call to the read qword masked handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword_masked);// call read_qword_masked
+
+ /* 64-bit form */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write1 - process a WRITE1 opcode
+-------------------------------------------------*/
+
+static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write byte handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_byte);// call write_byte
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write2 - process a WRITE2 opcode
+-------------------------------------------------*/
+
+static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_word);// call write_word
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_writ2m - process a WRIT2M opcode
+-------------------------------------------------*/
+
+static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, maskp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_word_masked);// call write_word_masked
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write4 - process a WRITE4 opcode
+-------------------------------------------------*/
+
+static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write dword handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword);// call write_dword
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_writ4m - process a WRIT4M opcode
+-------------------------------------------------*/
+
+static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, maskp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword_masked);// call write_dword_masked
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write8 - process a WRITE8 opcode
+-------------------------------------------------*/
+
+static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write qword handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword);// call write_qword
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_writ8m - process a WRIT8M opcode
+-------------------------------------------------*/
+
+static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, maskp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp
+ emit_mov_r64_p64(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword_masked);// call write_qword_masked
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_flags - process a FLAGS opcode
+-------------------------------------------------*/
+
+static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, maskp, tablep;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &maskp, PTYPE_I, &tablep, PTYPE_M);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_ECX, &dstp, NULL);
+
+ /* translate live flags into UML flags */
+ emit_pushf(&dst); // pushf
+ emit_pop_r64(&dst, REG_RAX); // pop rax
+ emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5
+ emit_movzx_r32_m8(&dst, REG_EAX, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsmap[0])));
+ // movzx eax,[flags_map]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* no masking */
+ if (maskp.value == 0xffffffff)
+ {
+ emit_mov_r32_m32(&dst, dstreg, MBISD(REG_RBP, REG_EAX, 4, offset_from_rbp(drcbe, tablep.value)));
+ // mov dstreg,[eax*4+table]
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp
+ emit_mov_r32_m32(&dst, REG_EDX, MBISD(REG_RBP, REG_EAX, 4, offset_from_rbp(drcbe, tablep.value)));
+ // mov edx,[eax*4+table]
+ emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask
+ emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask
+ emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* no masking */
+ if (maskp.value == U64(0xffffffffffffffff))
+ {
+ emit_mov_r64_m64(&dst, dstreg, MBISD(REG_RBP, REG_EAX, 8, offset_from_rbp(drcbe, tablep.value)));
+ // mov dstreg,[eax*8+table]
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp
+ emit_mov_r64_m64(&dst, REG_EDX, MBISD(REG_RBP, REG_EAX, 8, offset_from_rbp(drcbe, tablep.value)));
+ // mov edx,[eax*84+table]
+ if (short_immediate(~maskp.value))
+ emit_and_r64_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask
+ else
+ {
+ emit_mov_r64_imm(&dst, REG_R11, ~maskp.value); // mov r11,~mask
+ emit_and_r64_r64(&dst, dstreg, REG_R11); // and dstreg,r11
+ }
+ if (short_immediate(maskp.value))
+ emit_and_r64_imm(&dst, REG_EDX, maskp.value); // and edx,mask
+ else
+ {
+ emit_mov_r64_imm(&dst, REG_R11, maskp.value); // mov r11,mask
+ emit_and_r64_r64(&dst, REG_EDX, REG_R11); // and edx,r11
+ }
+ emit_or_r64_r64(&dst, dstreg, REG_EDX); // or dstreg,edx
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_mov - process a MOV opcode
+-------------------------------------------------*/
+
+static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ x86code *savedst = dst;
+ emit_link skip = { 0 };
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters, but only if we got here directly */
+ /* other opcodes call through here with pre-normalized parameters */
+ if (inst->opcode == DRCUML_OP_MOV)
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+ else
+ {
+ dstp = inst->param[0];
+ srcp = inst->param[1];
+ }
+
+ /* degenerate case: dest and source are equal */
+ if (dstp.type == srcp.type && dstp.value == srcp.value)
+ return dst;
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* always start with a jmp */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* register to memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_r32(&dst, MABS(drcbe, dstp.value), srcp.value); // mov [dstp],srcp
+
+ /* immediate to memory */
+ else if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(&dst, MABS(drcbe, dstp.value), srcp.value); // mov [dstp],srcp
+
+ /* conditional memory to register */
+ else if (inst->condflags != 0 && dstp.type == DRCUML_PTYPE_INT_REGISTER && srcp.type == DRCUML_PTYPE_MEMORY)
+ {
+ dst = savedst;
+ skip.target = NULL;
+ emit_cmovcc_r32_m32(&dst, X86_CONDITION(inst->condflags), dstp.value, MABS(drcbe, srcp.value));
+ // cmovcc dstp,[srcp]
+ }
+
+ /* conditional register to register */
+ else if (inst->condflags != 0 && dstp.type == DRCUML_PTYPE_INT_REGISTER && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ dst = savedst;
+ skip.target = NULL;
+ emit_cmovcc_r32_r32(&dst, X86_CONDITION(inst->condflags), dstp.value, srcp.value);
+ // cmovcc dstp,srcp
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &srcp); // mov dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* register to memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m64_r64(&dst, MABS(drcbe, dstp.value), srcp.value); // mov [dstp],srcp
+
+ /* immediate to memory */
+ else if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value))
+ emit_mov_m64_imm(&dst, MABS(drcbe, dstp.value), srcp.value); // mov [dstp],srcp
+
+ /* conditional memory to register */
+ else if (inst->condflags != 0 && dstp.type == DRCUML_PTYPE_INT_REGISTER && srcp.type == DRCUML_PTYPE_MEMORY)
+ {
+ dst = savedst;
+ skip.target = NULL;
+ emit_cmovcc_r64_m64(&dst, X86_CONDITION(inst->condflags), dstp.value, MABS(drcbe, srcp.value));
+ // cmovcc dstp,[srcp]
+ }
+
+ /* conditional register to register */
+ else if (inst->condflags != 0 && dstp.type == DRCUML_PTYPE_INT_REGISTER && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ dst = savedst;
+ skip.target = NULL;
+ emit_cmovcc_r64_r64(&dst, X86_CONDITION(inst->condflags), dstp.value, srcp.value);
+ // cmovcc dstp,srcp
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &srcp); // mov dstreg,srcp
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* resolve the jump */
+ if (skip.target != NULL)
+ resolve_link(&dst, &skip);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_zext1 - process a ZEXT1 opcode
+-------------------------------------------------*/
+
+static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT8)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movzx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movzx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_zext2 - process a ZEXT2 opcode
+-------------------------------------------------*/
+
+static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT16)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movzx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movzx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_zext4 - process a ZEXT4 opcode
+-------------------------------------------------*/
+
+static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sext1 - process a SEXT1 opcode
+-------------------------------------------------*/
+
+static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* convert 8-bit source registers */
+ if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4))
+ {
+ emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp
+ srcp.value = REG_EAX;
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r64_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r64_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sext2 - process a SEXT2 opcode
+-------------------------------------------------*/
+
+static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r64_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r64_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sext4 - process a SEXT4 opcode
+-------------------------------------------------*/
+
+static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 64-bit form */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsxd_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // movsxd dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsxd_r64_r32(&dst, dstreg, srcp.value); // movsxd dstreg,srcp
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_add - process a ADD opcode
+-------------------------------------------------*/
+
+static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value + src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
+ emit_add_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // add [dstp],src2p
+
+ /* reg = reg + imm */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ emit_lea_r32_m32(&dst, dstp.value, MBD(src1p.value, src2p.value)); // lea dstp,[src1p+src2p]
+
+ /* reg = reg + reg */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_INT_REGISTER && inst->condflags == 0)
+ emit_lea_r32_m32(&dst, dstp.value, MBISD(src1p.value, src2p.value, 1, 0)); // lea dstp,[src1p+src2p]
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_add_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // add dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
+ emit_add_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // add [dstp],src2p
+
+ /* reg = reg + imm */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(src2p.value) && inst->condflags == 0)
+ emit_lea_r64_m64(&dst, dstp.value, MBD(src1p.value, src2p.value)); // lea dstp,[src1p+src2p]
+
+ /* reg = reg + reg */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_INT_REGISTER && inst->condflags == 0)
+ emit_lea_r64_m64(&dst, dstp.value, MBISD(src1p.value, src2p.value, 1, 0)); // lea dstp,[src1p+src2p]
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_add_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // add dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_addc - process a ADDC opcode
+-------------------------------------------------*/
+
+static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_adc_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // adc [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_adc_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // adc dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_adc_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // adc [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_adc_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // adc dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sub - process a SUB opcode
+-------------------------------------------------*/
+
+static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value - src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
+ emit_sub_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // sub [dstp],src2p
+
+ /* reg = reg - imm */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ emit_lea_r32_m32(&dst, dstp.value, MBD(src1p.value, -src2p.value)); // lea dstp,[src1p-src2p]
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sub_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // sub dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
+ emit_sub_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // sub [dstp],src2p
+
+ /* reg = reg - imm */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(src2p.type) && inst->condflags == 0)
+ emit_lea_r64_m64(&dst, dstp.value, MBD(src1p.value, -src2p.value)); // lea dstp,[src1p-src2p]
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sub_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // sub dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_subc - process a SUBC opcode
+-------------------------------------------------*/
+
+static x86code *op_subc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // sbb [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sbb_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // sbb dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // sbb [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sbb_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // sbb dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_cmp - process a CMP opcode
+-------------------------------------------------*/
+
+static x86code *op_cmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter src1p, src2p;
+ int src1reg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && src1p.value == src2p.value)
+ {
+ emit_cmp_r32_r32(&dst, REG_EAX, REG_EAX); // cmp eax,eax
+ return dst;
+ }
+
+ /* pick a target register for the general case */
+ src1reg = param_select_register(REG_EAX, &src1p, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* memory versus anything */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_m32_p32(drcbe, &dst, MABS(drcbe, src1p.value), &src2p, inst); // cmp [dstp],src2p
+
+ /* general case */
+ else
+ {
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_imm(&dst, src1reg, src1p.value); // mov src1reg,imm
+ emit_cmp_r32_p32(drcbe, &dst, src1reg, &src2p, inst); // cmp src1reg,src2p
+ }
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* memory versus anything */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_m64_p64(drcbe, &dst, MABS(drcbe, src1p.value), &src2p, inst); // cmp [dstp],src2p
+
+ /* general case */
+ else
+ {
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r64_imm(&dst, src1reg, src1p.value); // mov src1reg,imm
+ emit_cmp_r64_p64(drcbe, &dst, src1reg, &src2p, inst); // cmp src1reg,src2p
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_mulu - process a MULU opcode
+-------------------------------------------------*/
+
+static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_hi;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4_commutative(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_hi = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if (!compute_hi)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value * (UINT32)src2p.value);
+ else
+ {
+ UINT64 result = (UINT64)(UINT32)src1p.value * (UINT64)(UINT32)src2p.value;
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, result & 0xffffffff);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, result >> 32);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_mul_m32(&dst, MABS(drcbe, src2p.value)); // mul [src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mul_r32(&dst, src2p.value); // mul src2p
+ else if (src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r32_imm(&dst, REG_EDX, src2p.value); // mov edx,src2p
+ emit_mul_r32(&dst, REG_EDX); // mul edx
+ }
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ if (compute_hi)
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, REG_RAX, &src1p); // mov rax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_mul_m64(&dst, MABS(drcbe, src2p.value)); // mul [src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mul_r64(&dst, src2p.value); // mul src2p
+ else if (src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r64_imm(&dst, REG_RDX, src2p.value); // mov rdx,src2p
+ emit_mul_r64(&dst, REG_RDX); // mul rdx
+ }
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+ if (compute_hi)
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_muls - process a MULS opcode
+-------------------------------------------------*/
+
+static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_hi;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4_commutative(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_hi = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if (!compute_hi)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value * (INT32)src2p.value);
+ else
+ {
+ UINT64 result = (INT64)(INT32)src1p.value * (INT64)(INT32)src2p.value;
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, result & 0xffffffff);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, result >> 32);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* 32-bit destination with memory/immediate or register/immediate */
+ if (!compute_hi && src1p.type != DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_r32_m32_imm(&dst, REG_EAX, MABS(drcbe, src1p.value), src2p.value); // imul eax,[src1p],src2p
+ else if (src1p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r32_r32_imm(&dst, REG_EAX, src1p.value, src2p.value); // imul eax,src1p,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ }
+
+ /* 32-bit destination, general case */
+ else if (!compute_hi)
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_r32_m32(&dst, REG_EAX, MABS(drcbe, src2p.value)); // imul eax,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r32_r32(&dst, REG_EAX, src2p.value); // imul eax,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ }
+
+ /* 64-bit destination, general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_m32(&dst, MABS(drcbe, src2p.value)); // imul [src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r32(&dst, src2p.value); // imul src2p
+ else if (src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r32_imm(&dst, REG_EDX, src2p.value); // mov edx,src2p
+ emit_imul_r32(&dst, REG_EDX); // imul edx
+ }
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* 64-bit destination with memory/immediate or register/immediate */
+ if (!compute_hi && src1p.type != DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(src2p.type))
+ {
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_r64_m64_imm(&dst, REG_RAX, MABS(drcbe, src1p.value), src2p.value);// imul rax,[src1p],src2p
+ else if (src1p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r64_r64_imm(&dst, REG_RAX, src1p.value, src2p.value); // imul rax,src1p,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+ }
+
+ /* 64-bit destination, general case */
+ else if (!compute_hi)
+ {
+ emit_mov_r64_p64(drcbe, &dst, REG_RAX, &src1p); // mov rax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_r64_m64(&dst, REG_RAX, MABS(drcbe, src2p.value)); // imul rax,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r64_r64(&dst, REG_RAX, src2p.value); // imul rax,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+ }
+
+ /* 128-bit destination, general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, REG_RAX, &src1p); // mov rax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_m64(&dst, MABS(drcbe, src2p.value)); // imul [src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r64(&dst, src2p.value); // imul src2p
+ else if (src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r64_imm(&dst, REG_RDX, src2p.value); // mov rdx,src2p
+ emit_imul_r64(&dst, REG_RDX); // imul rdx
+ }
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_divu - process a DIVU opcode
+-------------------------------------------------*/
+
+static x86code *op_divu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_rem;
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_rem = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if ((UINT32)src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value / (UINT32)src2p.value);
+ else
+ {
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value / (UINT32)src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value % (UINT32)src2p.value);
+ }
+ }
+ else if (inst->size == 8)
+ {
+ UINT64 reslo, reshi;
+ if (src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ {
+ reslo = (UINT64)src1p.value / (UINT64)src2p.value;
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ }
+ else
+ {
+ reslo = (UINT64)src1p.value / (UINT64)src2p.value;
+ reshi = (UINT64)src1p.value % (UINT64)src2p.value;
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reshi);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_ECX, &src2p); // mov ecx,src2p
+ emit_jecxz_link(&dst, &skip); // jecxz skip
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ emit_xor_r32_r32(&dst, REG_EDX, REG_EDX); // xor edx,edx
+ emit_div_r32(&dst, REG_ECX); // div ecx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ if (compute_rem)
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ resolve_link(&dst, &skip); // skip:
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, REG_RCX, &src2p); // mov rcx,src2p
+ emit_jrcxz_link(&dst, &skip); // jrcxz skip
+ emit_mov_r64_p64(drcbe, &dst, REG_RAX, &src1p); // mov rax,src1p
+ emit_xor_r32_r32(&dst, REG_EDX, REG_EDX); // xor edx,edx
+ emit_div_r64(&dst, REG_RCX); // div rcx
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+ if (compute_rem)
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx
+ resolve_link(&dst, &skip); // skip:
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_divs - process a DIVS opcode
+-------------------------------------------------*/
+
+static x86code *op_divs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_rem;
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_rem = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if ((INT32)src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value / (INT32)src2p.value);
+ else
+ {
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value / (INT32)src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value % (INT32)src2p.value);
+ }
+ }
+ else if (inst->size == 8)
+ {
+ UINT64 reslo, reshi;
+ if (src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ {
+ reslo = (INT64)src1p.value / (INT64)src2p.value;
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ }
+ else
+ {
+ reslo = (INT64)src1p.value / (INT64)src2p.value;
+ reshi = (INT64)src1p.value % (INT64)src2p.value;
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reshi);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_ECX, &src2p); // mov ecx,src2p
+ emit_jecxz_link(&dst, &skip); // jecxz skip
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ emit_cdq(&dst); // cdq
+ emit_idiv_r32(&dst, REG_ECX); // idiv ecx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ if (compute_rem)
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ resolve_link(&dst, &skip); // skip:
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, REG_RCX, &src2p); // mov rcx,src2p
+ emit_jrcxz_link(&dst, &skip); // jrcxz skip
+ emit_mov_r64_p64(drcbe, &dst, REG_RAX, &src1p); // mov rax,src1p
+ emit_cqo(&dst); // cqo
+ emit_idiv_r64(&dst, REG_RCX); // idiv rcx
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax
+ if (compute_rem)
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx
+ resolve_link(&dst, &skip); // skip:
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_and - process a AND opcode
+-------------------------------------------------*/
+
+static x86code *op_and(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value & src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && (src2p.value & size_to_mask[inst->size]) == size_to_mask[inst->size] && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_and_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // and [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_and_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // and dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_and_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // and [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_and_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // and dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_test - process a TEST opcode
+-------------------------------------------------*/
+
+static x86code *op_test(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter src1p, src2p;
+ int src1reg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_2_commutative(drcbe, inst, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ src1reg = param_select_register(REG_EAX, &src1p, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* src1p in memory */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_test_m32_p32(drcbe, &dst, MABS(drcbe, src1p.value), &src2p, inst); // test [src1p],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, src1reg, &src1p); // mov src1reg,src1p
+ emit_test_r32_p32(drcbe, &dst, src1reg, &src2p, inst); // test src1reg,src2p
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* src1p in memory */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_test_m64_p64(drcbe, &dst, MABS(drcbe, src1p.value), &src2p, inst); // test [src1p],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, src1reg, &src1p); // mov src1reg,src1p
+ emit_test_r64_p64(drcbe, &dst, src1reg, &src2p, inst); // test src1reg,src2p
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_or - process a OR opcode
+-------------------------------------------------*/
+
+static x86code *op_or(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value | src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_or_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // or [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_or_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // or dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_or_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // or [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_or_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // or dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_xor - process a XOR opcode
+-------------------------------------------------*/
+
+static x86code *op_xor(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value & src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_xor_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // xor [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_xor_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // xor dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_xor_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // xor [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_xor_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // xor dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_shl - process a SHL opcode
+-------------------------------------------------*/
+
+static x86code *op_shl(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value << src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_shl_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // shl [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_shl_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // shl dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_shl_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // shl [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_shl_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // shl dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_shr - process a SHR opcode
+-------------------------------------------------*/
+
+static x86code *op_shr(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_shr_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // shr [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_shr_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // shr dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_shr_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // shr [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_shr_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // shr dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sar - process a SAR opcode
+-------------------------------------------------*/
+
+static x86code *op_sar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value >> src2p.value);
+ else if (inst->size == 8)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT64)src1p.value >> src2p.value);
+ }
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sar_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // sar [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sar_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // sar dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sar_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // sar [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sar_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // sar dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_rol - process a rol opcode
+-------------------------------------------------*/
+
+static x86code *op_rol(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rol_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // rol [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rol_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // rol dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rol_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // rol [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rol_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // rol dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ror - process a ROR opcode
+-------------------------------------------------*/
+
+static x86code *op_ror(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_ror_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // ror [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_ror_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // ror dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_ror_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // ror [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_ror_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // ror dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_rolc - process a ROLC opcode
+-------------------------------------------------*/
+
+static x86code *op_rolc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcl_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // rcl [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rcl_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // rcl dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcl_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // rcl [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rcl_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // rcl dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_rorc - process a RORC opcode
+-------------------------------------------------*/
+
+static x86code *op_rorc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcr_m32_p32(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // rcr [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rcr_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // rcr dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcr_m64_p64(drcbe, &dst, MABS(drcbe, dstp.value), &src2p, inst); // rcr [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rcr_r64_p64(drcbe, &dst, dstreg, &src2p, inst); // rcr dstreg,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+ return dst;
+}
+
+
+
+/***************************************************************************
+ FLOATING POINT OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_fload - process a FLOAD opcode
+-------------------------------------------------*/
+
+static x86code *op_fload(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int basereg, dstreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movss_r128_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // movss dstreg,[basep + 4*indp]
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ emit_movss_r128_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // movss dstreg,[basep + 4*indp]
+ }
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsd_r128_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // movsd dstreg,[basep + 8*indp]
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ emit_movsd_r128_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // movsd dstreg,[basep + 8*indp]
+ }
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fstore - process a FSTORE opcode
+-------------------------------------------------*/
+
+static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int basereg, srcreg;
+ INT32 baseoffs;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ srcreg = param_select_register(REG_XMM0, &srcp, NULL);
+
+ /* determine the pointer base */
+ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, srcreg, &srcp); // movss srcreg,srcp
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movss_m32_r128(&dst, MBD(basereg, baseoffs + 4*indp.value), srcreg); // movss [basep + 4*indp],srcreg
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ emit_movss_m32_r128(&dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // movss [basep + 4*indp],srcreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, srcreg, &srcp); // movsd srcreg,srcp
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsd_m64_r128(&dst, MBD(basereg, baseoffs + 8*indp.value), srcreg); // movsd [basep + 8*indp],srcreg
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ emit_movsd_m64_r128(&dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // movsd [basep + 8*indp],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fread - process a FREAD opcode
+-------------------------------------------------*/
+
+static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read dword/qword handler */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+ if (inst->size == 4)
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword
+ else if (inst->size == 8)
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword);// call read_qword
+
+ /* store result */
+ if (inst->size == 4)
+ {
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_r32(&dst, MABS(drcbe, dstp.value), REG_EAX); // mov [dstp],eax
+ else if (dstp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_movd_r128_r32(&dst, dstp.value, REG_EAX); // movd dstp,eax
+ }
+ else if (inst->size == 8)
+ {
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m64_r64(&dst, MABS(drcbe, dstp.value), REG_RAX); // mov [dstp],rax
+ else if (dstp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_movq_r128_r64(&dst, dstp.value, REG_RAX); // movq dstp,rax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fwrite - process a FWRITE opcode
+-------------------------------------------------*/
+
+static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r32_m32(&dst, REG_PARAM2, MABS(drcbe, srcp.value)); // mov param2,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_movd_r32_r128(&dst, REG_PARAM2, srcp.value); // movd param2,srcp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword);// call write_dword
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r64_m64(&dst, REG_PARAM2, MABS(drcbe, srcp.value)); // mov param2,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_movq_r64_r128(&dst, REG_PARAM2, srcp.value); // movq param2,srcp
+ emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword);// call write_qword
+ }
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fmov - process a FMOV opcode
+-------------------------------------------------*/
+
+static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ emit_link skip = { 0 };
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* always start with a jmp */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, dstreg, &srcp); // movss dstreg,srcp
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, dstreg, &srcp); // movsd dstreg,srcp
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+
+ /* resolve the jump */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4 - process a FTOI4 opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4t - process a FTOI4T opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvttss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvttss2si_r32_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvttsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvttsd2si_r32_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp
+ }
+
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4r - process a FTOI4R opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* save and set the control word */
+ emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave]
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[DRCUML_FMOD_ROUND])); // ldmxcsr fpcontrol[DRCUML_FMOD_ROUND]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* restore control word and proceed */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4f - process a FTOI4F opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* save and set the control word */
+ emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave]
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[DRCUML_FMOD_FLOOR])); // ldmxcsr fpcontrol[DRCUML_FMOD_FLOOR]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* restore control word and proceed */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4c - process a FTOI4C opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* save and set the control word */
+ emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave]
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[DRCUML_FMOD_CEIL])); // ldmxcsr fpcontrol[DRCUML_FMOD_CEIL]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* restore control word and proceed */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8 - process a FTOI8 opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8t - process a FTOI8T opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvttss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvttss2si_r64_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvttsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvttsd2si_r64_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8r - process a FTOI8R opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* save and set the control word */
+ emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave]
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[DRCUML_FMOD_ROUND])); // ldmxcsr fpcontrol[DRCUML_FMOD_ROUND]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* restore control word and proceed */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8f - process a FTOI8F opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* save and set the control word */
+ emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave]
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[DRCUML_FMOD_FLOOR])); // ldmxcsr fpcontrol[DRCUML_FMOD_FLOOR]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* restore control word and proceed */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8c - process a FTOI8C opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* save and set the control word */
+ emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave]
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[DRCUML_FMOD_CEIL])); // ldmxcsr fpcontrol[DRCUML_FMOD_CEIL]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp
+ }
+
+ /* restore control word and proceed */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffrfs - process a FFRFS opcode
+-------------------------------------------------*/
+
+static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtss2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2sd dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtss2sd_r128_r128(&dst, dstreg, srcp.value); // cvtss2sd dstreg,srcp
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffrfd - process a FFRFD opcode
+-------------------------------------------------*/
+
+static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffri4 - process a FFRI4 opcode
+-------------------------------------------------*/
+
+static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsi2ss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp]
+ else
+ {
+ int srcreg = param_select_register(REG_EAX, &srcp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_cvtsi2ss_r128_r32(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg
+ }
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsi2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp]
+ else
+ {
+ int srcreg = param_select_register(REG_EAX, &srcp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_cvtsi2sd_r128_r32(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg
+ }
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffri8 - process a FFRI8 opcode
+-------------------------------------------------*/
+
+static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsi2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp]
+ else
+ {
+ int srcreg = param_select_register(REG_EAX, &srcp, NULL);
+ emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_cvtsi2ss_r128_r64(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg
+ }
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsi2sd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp]
+ else
+ {
+ int srcreg = param_select_register(REG_EAX, &srcp, NULL);
+ emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_cvtsi2sd_r128_r64(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg
+ }
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fadd - process a FADD opcode
+-------------------------------------------------*/
+
+static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, dstreg, &src1p); // movss dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_addss_r128_m32(&dst, dstreg, MABS(drcbe, src2p.value)); // addss dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_addss_r128_r128(&dst, dstreg, src2p.value); // addss dstreg,src2p
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, dstreg, &src1p); // movsd dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_addsd_r128_m64(&dst, dstreg, MABS(drcbe, src2p.value)); // addsd dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_addsd_r128_r128(&dst, dstreg, src2p.value); // addsd dstreg,src2p
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fsub - process a FSUB opcode
+-------------------------------------------------*/
+
+static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, dstreg, &src1p); // movss dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_subss_r128_m32(&dst, dstreg, MABS(drcbe, src2p.value)); // subss dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_subss_r128_r128(&dst, dstreg, src2p.value); // subss dstreg,src2p
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, dstreg, &src1p); // movsd dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_subsd_r128_m64(&dst, dstreg, MABS(drcbe, src2p.value)); // subsd dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_subsd_r128_r128(&dst, dstreg, src2p.value); // subsd dstreg,src2p
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fcmp - process a FCMP opcode
+-------------------------------------------------*/
+
+static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter src1p, src2p;
+ int src1reg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ src1reg = param_select_register(REG_XMM0, &src1p, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, src1reg, &src1p); // movss src1reg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_comiss_r128_m32(&dst, src1reg, MABS(drcbe, src2p.value)); // comiss src1reg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_comiss_r128_r128(&dst, src1reg, src2p.value); // comiss src1reg,src2p
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, src1reg, &src1p); // movsd src1reg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_comisd_r128_m64(&dst, src1reg, MABS(drcbe, src2p.value)); // comisd src1reg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_comisd_r128_r128(&dst, src1reg, src2p.value); // comisd src1reg,src2p
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fmul - process a FMUL opcode
+-------------------------------------------------*/
+
+static x86code *op_fmul(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, dstreg, &src1p); // movss dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_mulss_r128_m32(&dst, dstreg, MABS(drcbe, src2p.value)); // mulss dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_mulss_r128_r128(&dst, dstreg, src2p.value); // mulss dstreg,src2p
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, dstreg, &src1p); // movsd dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_mulsd_r128_m64(&dst, dstreg, MABS(drcbe, src2p.value)); // mulsd dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_mulsd_r128_r128(&dst, dstreg, src2p.value); // mulsd dstreg,src2p
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fdiv - process a FDIV opcode
+-------------------------------------------------*/
+
+static x86code *op_fdiv(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, dstreg, &src1p); // movss dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_divss_r128_m32(&dst, dstreg, MABS(drcbe, src2p.value)); // divss dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_divss_r128_r128(&dst, dstreg, src2p.value); // divss dstreg,src2p
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, dstreg, &src1p); // movsd dstreg,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_divsd_r128_m64(&dst, dstreg, MABS(drcbe, src2p.value)); // divsd dstreg,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_divsd_r128_r128(&dst, dstreg, src2p.value); // divsd dstreg,src2p
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fneg - process a FNEG opcode
+-------------------------------------------------*/
+
+static x86code *op_fneg(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, &srcp);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_xorps_r128_r128(&dst, dstreg, dstreg); // xorps dstreg,dstreg
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_subss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // subss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_subss_r128_r128(&dst, dstreg, srcp.value); // subss dstreg,srcp
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_xorpd_r128_r128(&dst, dstreg, dstreg); // xorpd dstreg,dstreg
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_subsd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // subsd dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_subsd_r128_r128(&dst, dstreg, srcp.value); // subsd dstreg,srcp
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fabs - process a FABS opcode
+-------------------------------------------------*/
+
+static x86code *op_fabs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, &srcp);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ emit_movss_r128_p32(drcbe, &dst, dstreg, &srcp); // movss dstreg,srcp
+ emit_andps_r128_m128(&dst, dstreg, MABS(drcbe, drcbe->absmask32)); // andps dstreg,[absmask32]
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ emit_movsd_r128_p64(drcbe, &dst, dstreg, &srcp); // movsd dstreg,srcp
+ emit_andpd_r128_m128(&dst, dstreg, MABS(drcbe, drcbe->absmask64)); // andpd dstreg,[absmask64]
+ emit_movsd_p64_r128(drcbe, &dst, &srcp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fsqrt - process a FSQRT opcode
+-------------------------------------------------*/
+
+static x86code *op_fsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_sqrtss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // sqrtss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_sqrtss_r128_r128(&dst, dstreg, srcp.value); // sqrtss dstreg,srcp
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_sqrtsd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // sqrtsd dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_sqrtsd_r128_r128(&dst, dstreg, srcp.value); // sqrtsd dstreg,srcp
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_frecip - process a FRECIP opcode
+-------------------------------------------------*/
+
+static x86code *op_frecip(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcpss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // rcpss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_rcpss_r128_r128(&dst, dstreg, srcp.value); // rcpss dstreg,srcp
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp
+ emit_rcpss_r128_r128(&dst, dstreg, dstreg); // rcpss dstreg,dstreg
+ emit_cvtss2sd_r128_r128(&dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_frsqrt - process a FRSQRT opcode
+-------------------------------------------------*/
+
+static x86code *op_frsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_XMM0, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_rsqrtss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // rsqrtss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_rsqrtss_r128_r128(&dst, dstreg, srcp.value); // rsqrtss dstreg,srcp
+ emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER)
+ emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp
+ emit_rsqrtss_r128_r128(&dst, dstreg, dstreg); // rsqrtss dstreg,dstreg
+ emit_cvtss2sd_r128_r128(&dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg
+ emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg
+ }
+ return dst;
+}
diff --git a/src/emu/cpu/drcbex86.c b/src/emu/cpu/drcbex86.c
new file mode 100644
index 00000000000..ebff66c8a40
--- /dev/null
+++ b/src/emu/cpu/drcbex86.c
@@ -0,0 +1,7418 @@
+/***************************************************************************
+
+ drcbex86.c
+
+ 32-bit x86 back-end 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.
+
+****************************************************************************
+
+ Future improvements/changes:
+
+ * Optimize to avoid unnecessary reloads
+ - especially EDX for 64-bit operations
+ - also FCMP/FLAGS has unnecessary PUSHF/POP EAX
+
+ * Identify common pairs and optimize output
+
+****************************************************************************
+
+ ---------------
+ ABI/conventions
+ ---------------
+
+ Registers:
+ EAX - volatile, function return value
+ EBX - non-volatile
+ ECX - volatile
+ EDX - volatile, function return value (upper 32 bits)
+ ESI - non-volatile
+ EDI - non-volatile
+ EBP - non-volatile
+
+ FP stack - volatile
+
+
+ ---------------
+ Execution model
+ ---------------
+
+ Registers:
+ EAX - scratch register
+ EBX - maps to I0 (low 32 bits)
+ ECX - scratch register
+ EDX - scratch register
+ ESI - maps to I1 (low 32 bits)
+ EDI - maps to I2 (low 32 bits)
+ EBP - maps to I3 (low 32 bits)
+
+ FP stack - scratch registers
+
+ Entry point:
+ Assumes 1 parameter passed, which is the codeptr of the code
+ to execute once the environment is set up.
+
+ Exit point:
+ Assumes exit value is in EAX.
+
+ Entry stack:
+ [esp] - return
+ [esp+4] - input parameter (entry handle)
+
+ Runtime stack:
+ [esp] - temporary space for hash jump
+ [esp+4] - saved ebp
+ [esp+8] - saved edi
+ [esp+12] - saved esi
+ [esp+16] - saved ebx
+ [esp+20] - ret
+ [esp+24] - input parameter (entry handle)
+
+***************************************************************************/
+
+#include "drcuml.h"
+#include "drcumld.h"
+#include "drcbeut.h"
+#include "debugger.h"
+#include "x86emit.h"
+#undef REG_SP
+#include "x86log.h"
+#include <math.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_HASHJMPS (0)
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PTYPE_M (1 << DRCUML_PTYPE_MEMORY)
+#define PTYPE_I (1 << DRCUML_PTYPE_IMMEDIATE)
+#define PTYPE_R (1 << DRCUML_PTYPE_INT_REGISTER)
+#define PTYPE_F (1 << DRCUML_PTYPE_FLOAT_REGISTER)
+#define PTYPE_MI (PTYPE_M | PTYPE_I)
+#define PTYPE_RI (PTYPE_R | PTYPE_I)
+#define PTYPE_MR (PTYPE_M | PTYPE_R)
+#define PTYPE_MRI (PTYPE_M | PTYPE_R | PTYPE_I)
+#define PTYPE_MF (PTYPE_M | PTYPE_F)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define X86_CONDITION(condflags) (condition_map[condflags - DRCUML_COND_Z])
+#define X86_NOT_CONDITION(condflags) (condition_map[condflags - DRCUML_COND_Z] ^ 1)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* entry point */
+typedef UINT32 (*x86_entry_point_func)(x86code *entry);
+
+/* opcode handler */
+typedef x86code *(*opcode_generate_func)(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+
+/* opcode table entry */
+typedef struct _opcode_table_entry opcode_table_entry;
+struct _opcode_table_entry
+{
+ drcuml_opcode opcode; /* opcode in question */
+ opcode_generate_func func; /* function pointer to the work */
+};
+
+
+/* internal backend-specific state */
+struct _drcbe_state
+{
+ drcuml_state * drcuml; /* pointer back to our owner */
+ drccache * cache; /* pointer to the cache */
+ drcuml_machine_state state; /* state of the machine */
+ drchash_state * hash; /* hash table state */
+ drcmap_state * map; /* code map */
+ drclabel_list * labels; /* label list */
+
+ x86_entry_point_func entry; /* entry point */
+ x86code * exit; /* exit point */
+ x86code * nocode; /* nocode handler */
+
+ UINT32 * reglo[REG_MAX]; /* pointer to low part of data for each register */
+ UINT32 * reghi[REG_MAX]; /* pointer to high part of data for each register */
+ double fptemp; /* temporary storage for floating point */
+
+ UINT16 fpumode; /* saved FPU mode */
+ UINT16 fmodesave; /* temporary location for saving */
+
+ void * stacksave; /* saved stack pointer */
+ void * hashstacksave; /* saved stack pointer for hashjmp */
+ UINT64 reslo; /* extended low result */
+ UINT64 reshi; /* extended high result */
+
+ x86log_context * log; /* logging */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* primary back-end callbacks */
+static drcbe_state *drcbex86_alloc(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits);
+static void drcbex86_free(drcbe_state *drcbe);
+static void drcbex86_reset(drcbe_state *drcbe);
+static int drcbex86_execute(drcbe_state *drcbe, drcuml_codehandle *entry);
+static void drcbex86_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst);
+static int drcbex86_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc);
+
+/* private helper functions */
+static void fixup_label(void *parameter, drccodeptr labelcodeptr);
+
+/* miscellaneous functions */
+static void dmulu(UINT64 *dstlo, UINT64 *dsthi, UINT64 src1, UINT64 src2);
+static void dmuls(UINT64 *dstlo, UINT64 *dsthi, INT64 src1, INT64 src2);
+static void ddivu(UINT64 *dstlo, UINT64 *dsthi, UINT64 src1, UINT64 src2);
+static void ddivs(UINT64 *dstlo, UINT64 *dsthi, INT64 src1, INT64 src2);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+/* globally-accessible interface to the backend */
+const drcbe_interface drcbe_x86_be_interface =
+{
+ drcbex86_alloc,
+ drcbex86_free,
+ drcbex86_reset,
+ drcbex86_execute,
+ drcbex86_generate,
+ drcbex86_hash_exists
+};
+
+/* opcode table */
+static opcode_generate_func opcode_table[DRCUML_OP_MAX];
+
+/* size-to-mask table */
+static const UINT64 size_to_mask[] = { 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0, U64(0xffffffffffffffff) };
+
+/* register mapping tables */
+static UINT8 int_register_map[DRCUML_REG_I_END - DRCUML_REG_I0] =
+{
+ REG_EBX, REG_ESI, REG_EDI, REG_EBP
+};
+
+/* flags mapping tables */
+static UINT8 flags_map[0x1000];
+
+/* condition mapping table */
+static UINT8 condition_map[DRCUML_COND_MAX - DRCUML_COND_Z] =
+{
+ COND_Z, /* DRCUML_COND_Z = 0x80, requires Z */
+ COND_NZ, /* DRCUML_COND_NZ, requires Z */
+ COND_S, /* DRCUML_COND_S, requires S */
+ COND_NS, /* DRCUML_COND_NS, requires S */
+ COND_C, /* DRCUML_COND_C, requires C */
+ COND_NC, /* DRCUML_COND_NC, requires C */
+ COND_O, /* DRCUML_COND_V, requires V */
+ COND_NO, /* DRCUML_COND_NV, requires V */
+ COND_P, /* DRCUML_COND_U, requires U */
+ COND_NP, /* DRCUML_COND_NU, requires U */
+ COND_A, /* DRCUML_COND_A, requires CZ */
+ COND_BE, /* DRCUML_COND_BE, requires CZ */
+ COND_G, /* DRCUML_COND_G, requires SVZ */
+ COND_LE, /* DRCUML_COND_LE, requires SVZ */
+ COND_L, /* DRCUML_COND_L, requires SV */
+ COND_GE, /* DRCUML_COND_GE, requires SV */
+};
+
+/* FPU control register mapping */
+static const UINT16 fp_control[4] =
+{
+ 0x0e3f, /* DRCUML_FMOD_TRUNC */
+ 0x023f, /* DRCUML_FMOD_ROUND */
+ 0x0a3f, /* DRCUML_FMOD_CEIL */
+ 0x063f /* DRCUML_FMOD_FLOOR */
+};
+
+
+
+/***************************************************************************
+ TABLES
+***************************************************************************/
+
+static x86code *op_handle(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_hash(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_label(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_comment(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_mapvar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_debug(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_exit(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_jmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_exh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_callh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ret(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_callc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_subc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_cmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_divu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_divs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_and(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_test(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_or(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_xor(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_shl(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_shr(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_sar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ror(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_rol(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_rorc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_rolc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static x86code *op_fload(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fmul(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fdiv(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fneg(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fabs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_fsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_frecip(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+static x86code *op_frsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst);
+
+static const opcode_table_entry opcode_table_source[] =
+{
+ /* Compile-time opcodes */
+ { DRCUML_OP_HANDLE, op_handle }, /* HANDLE handle */
+ { DRCUML_OP_HASH, op_hash }, /* HASH mode,pc */
+ { DRCUML_OP_LABEL, op_label }, /* LABEL imm */
+ { DRCUML_OP_COMMENT, op_comment }, /* COMMENT string */
+ { DRCUML_OP_MAPVAR, op_mapvar }, /* MAPVAR mapvar,value */
+
+ /* Control Flow Operations */
+ { DRCUML_OP_DEBUG, op_debug }, /* DEBUG pc */
+ { DRCUML_OP_EXIT, op_exit }, /* EXIT src1[,c] */
+ { DRCUML_OP_HASHJMP, op_hashjmp }, /* HASHJMP mode,pc,handle */
+ { DRCUML_OP_JMP, op_jmp }, /* JMP imm[,c] */
+ { DRCUML_OP_EXH, op_exh }, /* EXH handle,param[,c] */
+ { DRCUML_OP_CALLH, op_callh }, /* CALLH handle[,c] */
+ { DRCUML_OP_RET, op_ret }, /* RET [c] */
+ { DRCUML_OP_CALLC, op_callc }, /* CALLC func,ptr[,c] */
+ { DRCUML_OP_RECOVER, op_recover }, /* RECOVER dst,mapvar */
+
+ /* Internal Register Operations */
+ { DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */
+ { DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */
+ { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */
+
+ /* Integer Operations */
+ { DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */
+ { DRCUML_OP_LOAD1S, op_load1s }, /* LOAD1S dst,base,index */
+ { DRCUML_OP_LOAD2U, op_load2u }, /* LOAD2U dst,base,index */
+ { DRCUML_OP_LOAD2S, op_load2s }, /* LOAD2S dst,base,index */
+ { DRCUML_OP_LOAD4U, op_load4u }, /* LOAD4U dst,base,index */
+ { DRCUML_OP_LOAD4S, op_load4s }, /* LOAD4S dst,base,index */
+ { DRCUML_OP_LOAD8U, op_load8u }, /* LOAD8U dst,base,index */
+ { DRCUML_OP_STORE1, op_store1 }, /* STORE1 base,index,src */
+ { DRCUML_OP_STORE2, op_store2 }, /* STORE2 base,index,src */
+ { DRCUML_OP_STORE4, op_store4 }, /* STORE4 base,index,src */
+ { DRCUML_OP_STORE8, op_store8 }, /* STORE8 base,index,src */
+ { DRCUML_OP_READ1U, op_read1u }, /* READ1U dst,space,src1 */
+ { DRCUML_OP_READ1S, op_read1s }, /* READ1S dst,space,src1 */
+ { DRCUML_OP_READ2U, op_read2u }, /* READ2U dst,space,src1 */
+ { DRCUML_OP_READ2S, op_read2s }, /* READ2S dst,space,src1 */
+ { DRCUML_OP_READ2M, op_read2m }, /* READ2M dst,space,src1,mask */
+ { DRCUML_OP_READ4U, op_read4u }, /* READ4U dst,space,src1 */
+ { DRCUML_OP_READ4S, op_read4s }, /* READ4S dst,space,src1 */
+ { DRCUML_OP_READ4M, op_read4m }, /* READ4M dst,space,src1,mask */
+ { DRCUML_OP_READ8U, op_read8u }, /* READ8U dst,space,src1 */
+ { DRCUML_OP_READ8M, op_read8m }, /* READ8M dst,space,src1,mask */
+ { DRCUML_OP_WRITE1, op_write1 }, /* WRITE1 space,dst,src1 */
+ { DRCUML_OP_WRITE2, op_write2 }, /* WRITE2 space,dst,src1 */
+ { DRCUML_OP_WRIT2M, op_writ2m }, /* WRIT2M space,dst,src1 */
+ { DRCUML_OP_WRITE4, op_write4 }, /* WRITE4 space,dst,src1 */
+ { DRCUML_OP_WRIT4M, op_writ4m }, /* WRIT4M space,dst,mask,src1 */
+ { DRCUML_OP_WRITE8, op_write8 }, /* WRITE8 space,dst,src1 */
+ { DRCUML_OP_WRIT8M, op_writ8m }, /* WRIT8M space,dst,mask,src1 */
+ { DRCUML_OP_FLAGS, op_flags }, /* FLAGS dst,mask,table */
+ { DRCUML_OP_MOV, op_mov }, /* MOV dst,src[,c] */
+ { DRCUML_OP_ZEXT1, op_zext1 }, /* ZEXT1 dst,src */
+ { DRCUML_OP_ZEXT2, op_zext2 }, /* ZEXT2 dst,src */
+ { DRCUML_OP_ZEXT4, op_zext4 }, /* ZEXT4 dst,src */
+ { DRCUML_OP_SEXT1, op_sext1 }, /* SEXT1 dst,src */
+ { DRCUML_OP_SEXT2, op_sext2 }, /* SEXT2 dst,src */
+ { DRCUML_OP_SEXT4, op_sext4 }, /* SEXT4 dst,src */
+ { DRCUML_OP_ADD, op_add }, /* ADD dst,src1,src2[,f] */
+ { DRCUML_OP_ADDC, op_addc }, /* ADDC dst,src1,src2[,f] */
+ { DRCUML_OP_SUB, op_sub }, /* SUB dst,src1,src2[,f] */
+ { DRCUML_OP_SUBB, op_subc }, /* SUBB dst,src1,src2[,f] */
+ { DRCUML_OP_CMP, op_cmp }, /* CMP src1,src2[,f] */
+ { DRCUML_OP_MULU, op_mulu }, /* MULU dst,edst,src1,src2[,f] */
+ { DRCUML_OP_MULS, op_muls }, /* MULS dst,edst,src1,src2[,f] */
+ { DRCUML_OP_DIVU, op_divu }, /* DIVU dst,edst,src1,src2[,f] */
+ { DRCUML_OP_DIVS, op_divs }, /* DIVS dst,edst,src1,src2[,f] */
+ { DRCUML_OP_AND, op_and }, /* AND dst,src1,src2[,f] */
+ { DRCUML_OP_TEST, op_test }, /* TEST src1,src2[,f] */
+ { DRCUML_OP_OR, op_or }, /* OR dst,src1,src2[,f] */
+ { DRCUML_OP_XOR, op_xor }, /* XOR dst,src1,src2[,f] */
+ { DRCUML_OP_SHL, op_shl }, /* SHL dst,src,count[,f] */
+ { DRCUML_OP_SHR, op_shr }, /* SHR dst,src,count[,f] */
+ { DRCUML_OP_SAR, op_sar }, /* SAR dst,src,count[,f] */
+ { DRCUML_OP_ROL, op_rol }, /* ROL dst,src,count[,f] */
+ { DRCUML_OP_ROLC, op_rolc }, /* ROLC dst,src,count[,f] */
+ { DRCUML_OP_ROR, op_ror }, /* ROR dst,src,count[,f] */
+ { DRCUML_OP_RORC, op_rorc }, /* RORC dst,src,count[,f] */
+
+ /* Floating Point Operations */
+ { DRCUML_OP_FLOAD, op_fload }, /* FLOAD dst,base,index */
+ { DRCUML_OP_FSTORE, op_fstore }, /* FSTORE base,index,src */
+ { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,space,src1 */
+ { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE space,dst,src1 */
+ { DRCUML_OP_FMOV, op_fmov }, /* FMOV dst,src1[,c] */
+ { DRCUML_OP_FTOI4, op_ftoi4 }, /* FTOI4 dst,src1 */
+ { DRCUML_OP_FTOI4T, op_ftoi4t }, /* FTOI4T dst,src1 */
+ { DRCUML_OP_FTOI4R, op_ftoi4r }, /* FTOI4R dst,src1 */
+ { DRCUML_OP_FTOI4F, op_ftoi4f }, /* FTOI4F dst,src1 */
+ { DRCUML_OP_FTOI4C, op_ftoi4c }, /* FTOI4C dst,src1 */
+ { DRCUML_OP_FTOI8, op_ftoi8 }, /* FTOI8 dst,src1 */
+ { DRCUML_OP_FTOI8T, op_ftoi8t }, /* FTOI8T dst,src1 */
+ { DRCUML_OP_FTOI8R, op_ftoi8r }, /* FTOI8R dst,src1 */
+ { DRCUML_OP_FTOI8F, op_ftoi8f }, /* FTOI8F dst,src1 */
+ { DRCUML_OP_FTOI8C, op_ftoi8c }, /* FTOI8C dst,src1 */
+ { DRCUML_OP_FFRFS, op_ffrfs }, /* FFRFS dst,src1 */
+ { DRCUML_OP_FFRFD, op_ffrfd }, /* FFRFD dst,src1 */
+ { DRCUML_OP_FFRI4, op_ffri4 }, /* FFRI4 dst,src1 */
+ { DRCUML_OP_FFRI8, op_ffri8 }, /* FFRI8 dst,src1 */
+ { DRCUML_OP_FADD, op_fadd }, /* FADD dst,src1,src2 */
+ { DRCUML_OP_FSUB, op_fsub }, /* FSUB dst,src1,src2 */
+ { DRCUML_OP_FCMP, op_fcmp }, /* FCMP src1,src2 */
+ { DRCUML_OP_FMUL, op_fmul }, /* FMUL dst,src1,src2 */
+ { DRCUML_OP_FDIV, op_fdiv }, /* FDIV dst,src1,src2 */
+ { DRCUML_OP_FNEG, op_fneg }, /* FNEG dst,src1 */
+ { DRCUML_OP_FABS, op_fabs }, /* FABS dst,src1 */
+ { DRCUML_OP_FSQRT, op_fsqrt }, /* FSQRT dst,src1 */
+ { DRCUML_OP_FRECIP, op_frecip }, /* FRECIP dst,src1 */
+ { DRCUML_OP_FRSQRT, op_frsqrt } /* FRSQRT dst,src1 */
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ param_select_register - select a register
+ to use, avoiding conflicts with the optional
+ checkparam
+-------------------------------------------------*/
+
+INLINE int param_select_register(int defreg, const drcuml_parameter *param, const drcuml_parameter *checkparam)
+{
+ if (param->type == DRCUML_PTYPE_INT_REGISTER && (checkparam == NULL || param->type != checkparam->type || param->value != checkparam->value))
+ return param->value;
+ return defreg;
+}
+
+
+/*-------------------------------------------------
+ emit_combine_z_flags - combine the Z flag from
+ two 32-bit operations
+-------------------------------------------------*/
+
+INLINE void emit_combine_z_flags(x86code **dst)
+{
+ /* this assumes that the flags from the low 32-bit op are on the stack */
+ /* and the flags from the high 32-bit op are live */
+ emit_pushf(dst); // pushf
+ emit_mov_r32_m32(dst, REG_ECX, MBD(REG_ESP, 4)); // mov ecx,[esp+4]
+ emit_or_r32_imm(dst, REG_ECX, ~0x40); // or ecx,~0x40
+ emit_and_m32_r32(dst, MBD(REG_ESP, 0), REG_ECX); // and [esp],ecx
+ emit_popf(dst); // popf
+ emit_lea_r32_m32(dst, REG_ESP, MBD(REG_ESP, 4)); // lea esp,[esp+4]
+}
+
+
+/*-------------------------------------------------
+ emit_combine_z_shl_flags - combine the Z
+ flags from two 32-bit shift left operations
+-------------------------------------------------*/
+
+INLINE void emit_combine_z_shl_flags(x86code **dst)
+{
+ /* this assumes that the flags from the high 32-bit op are on the stack */
+ /* and the flags from the low 32-bit op are live */
+ emit_pushf(dst); // pushf
+ emit_pop_r32(dst, REG_ECX); // pop ecx
+ emit_or_r32_imm(dst, REG_ECX, ~0x40); // or ecx,~0x40
+ emit_and_m32_r32(dst, MBD(REG_ESP, 0), REG_ECX); // and [esp],ecx
+ emit_popf(dst); // popf
+}
+
+
+
+/***************************************************************************
+ BACKEND CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ drcbex86_alloc - allocate back-end-specific
+ state
+-------------------------------------------------*/
+
+static drcbe_state *drcbex86_alloc(drcuml_state *drcuml, drccache *cache, UINT32 flags, int modes, int addrbits, int ignorebits)
+{
+ int opnum, regnum, entry;
+ drcbe_state *drcbe;
+
+ /* allocate space in the cache for our state */
+ drcbe = drccache_memory_alloc(cache, sizeof(*drcbe));
+ if (drcbe == NULL)
+ return NULL;
+ memset(drcbe, 0, sizeof(*drcbe));
+
+ /* remember our pointers */
+ drcbe->drcuml = drcuml;
+ drcbe->cache = cache;
+
+ /* allocate hash tables */
+ drcbe->hash = drchash_alloc(cache, modes, addrbits, ignorebits);
+ if (drcbe->hash == NULL)
+ return NULL;
+
+ /* allocate code map */
+ drcbe->map = drcmap_alloc(cache, 0);
+ if (drcbe->map == NULL)
+ return NULL;
+
+ /* allocate a label tracker */
+ drcbe->labels = drclabel_list_alloc(cache);
+ if (drcbe->labels == NULL)
+ return NULL;
+
+ /* build the opcode table (static but it doesn't hurt to regenerate it) */
+ for (opnum = 0; opnum < ARRAY_LENGTH(opcode_table_source); opnum++)
+ opcode_table[opcode_table_source[opnum].opcode] = opcode_table_source[opnum].func;
+
+ /* build the flags map (static but it doesn't hurt to regenerate it) */
+ for (entry = 0; entry < ARRAY_LENGTH(flags_map); entry++)
+ {
+ UINT8 flags = 0;
+ if (entry & 0x001) flags |= DRCUML_FLAG_C;
+ if (entry & 0x004) flags |= DRCUML_FLAG_U;
+ if (entry & 0x040) flags |= DRCUML_FLAG_Z;
+ if (entry & 0x080) flags |= DRCUML_FLAG_S;
+ if (entry & 0x800) flags |= DRCUML_FLAG_V;
+ flags_map[entry] = flags;
+ }
+
+ /* compute hi pointers for each register */
+ for (regnum = 0; regnum < ARRAY_LENGTH(int_register_map); regnum++)
+ if (int_register_map[regnum] != 0)
+ {
+ drcbe->reglo[int_register_map[regnum]] = &drcbe->state.r[regnum].l;
+ drcbe->reghi[int_register_map[regnum]] = &drcbe->state.r[regnum].h;
+ }
+
+ /* create the log */
+ if (flags & DRCUML_OPTION_LOG_NATIVE)
+ drcbe->log = x86log_create_context("drcbex86.asm");
+
+ return drcbe;
+}
+
+
+/*-------------------------------------------------
+ drcbex86_free - free back-end specific state
+-------------------------------------------------*/
+
+static void drcbex86_free(drcbe_state *drcbe)
+{
+ /* free the log context */
+ if (drcbe->log != NULL)
+ x86log_free_context(drcbe->log);
+}
+
+
+/*-------------------------------------------------
+ drcbex86_reset - reset back-end specific state
+-------------------------------------------------*/
+
+static void drcbex86_reset(drcbe_state *drcbe)
+{
+ x86code **dst;
+
+ /* output a note to the log */
+ if (drcbe->log != NULL)
+ x86log_printf(drcbe->log, "\n\n===========\nCACHE RESET\n===========\n\n");
+
+ /* generate a little bit of glue code to set up the environment */
+ dst = (x86code **)drccache_begin_codegen(drcbe->cache, 500);
+ if (dst == NULL)
+ fatalerror("Out of cache space after a reset!");
+
+ /* generate an entry point */
+ drcbe->entry = (x86_entry_point_func)*dst;
+ emit_mov_r32_m32(dst, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4]
+ emit_push_r32(dst, REG_EBX); // push ebx
+ emit_push_r32(dst, REG_ESI); // push esi
+ emit_push_r32(dst, REG_EDI); // push edi
+ emit_push_r32(dst, REG_EBP); // push ebp
+ emit_mov_m32_r32(dst, MABS(&drcbe->hashstacksave), REG_ESP); // mov [hashstacksave],esp
+ emit_sub_r32_imm(dst, REG_ESP, 4); // sub esp,4
+ emit_mov_m32_r32(dst, MABS(&drcbe->stacksave), REG_ESP); // mov [stacksave],esp
+ emit_fstcw_m16(dst, MABS(&drcbe->fpumode)); // fstcw [fpumode]
+ emit_jmp_r32(dst, REG_EAX); // jmp eax
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, "entry_point", (x86code *)drcbe->entry, *dst);
+
+ /* generate an exit point */
+ drcbe->exit = *dst;
+ emit_fldcw_m16(dst, MABS(&drcbe->fpumode)); // fldcw [fpumode]
+ emit_mov_r32_m32(dst, REG_ESP, MABS(&drcbe->hashstacksave)); // mov esp,[hashstacksave]
+ emit_pop_r32(dst, REG_EBP); // pop ebp
+ emit_pop_r32(dst, REG_EDI); // pop edi
+ emit_pop_r32(dst, REG_ESI); // pop esi
+ emit_pop_r32(dst, REG_EBX); // pop ebx
+ emit_ret(dst); // ret
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, "exit_point", drcbe->exit, *dst);
+
+ /* generate a no code point */
+ drcbe->nocode = *dst;
+ emit_ret(dst); // ret
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, "nocode", drcbe->nocode, *dst);
+
+ /* finish up codegen */
+ drccache_end_codegen(drcbe->cache);
+
+ /* reset our hash tables */
+ drchash_reset(drcbe->hash);
+ drchash_set_default_codeptr(drcbe->hash, drcbe->nocode);
+}
+
+
+/*-------------------------------------------------
+ drcbex86_generate - generate code
+-------------------------------------------------*/
+
+static void drcbex86_generate(drcbe_state *drcbe, drcuml_block *block, const drcuml_instruction *instlist, UINT32 numinst)
+{
+ const char *blockname = NULL;
+ char blockbuffer[100];
+ drccodeptr *cachetop;
+ x86code *base;
+ x86code *dst;
+ int inum;
+
+ /* tell all of our utility objects that a block is beginning */
+ drchash_block_begin(drcbe->hash, block, instlist, numinst);
+ drclabel_block_begin(drcbe->labels, block);
+ drcmap_block_begin(drcbe->map, block);
+
+ /* begin codegen; fail if we can't */
+ cachetop = drccache_begin_codegen(drcbe->cache, numinst * 8 * 4);
+ if (cachetop == NULL)
+ drcuml_block_abort(block);
+
+ /* compute the base by aligning the cache top to a cache line (assumed to be 64 bytes) */
+ base = (x86code *)(((FPTR)*cachetop + 63) & ~63);
+ dst = base;
+
+ /* generate code */
+ for (inum = 0; inum < numinst; inum++)
+ {
+ const drcuml_instruction *inst = &instlist[inum];
+ assert(inst->opcode < ARRAY_LENGTH(opcode_table));
+
+ /* add a comment */
+ if (drcbe->log != NULL)
+ {
+ char dasm[100];
+ drcuml_disasm(inst, dasm);
+ x86log_add_comment(drcbe->log, dst, "%s", dasm);
+ }
+
+ /* extract a blockname */
+ if (blockname == NULL)
+ {
+ if (inst->opcode == DRCUML_OP_HANDLE)
+ blockname = drcuml_handle_name((drcuml_codehandle *)(FPTR)inst->param[0].value);
+ else if (inst->opcode == DRCUML_OP_HASH)
+ {
+ sprintf(blockbuffer, "Code: mode=%d PC=%08X", (UINT32)inst->param[0].value, (offs_t)inst->param[1].value);
+ blockname = blockbuffer;
+ }
+ }
+
+ /* generate code */
+ dst = (*opcode_table[inst->opcode])(drcbe, dst, inst);
+ }
+
+ /* complete codegen */
+ *cachetop = (drccodeptr)dst;
+ drccache_end_codegen(drcbe->cache);
+
+ /* log it */
+ if (drcbe->log != NULL)
+ x86log_disasm_code_range(drcbe->log, (blockname == NULL) ? "Unknown block" : blockname, base, drccache_top(drcbe->cache));
+
+ /* tell all of our utility objects that the block is finished */
+ drchash_block_end(drcbe->hash, block);
+ drclabel_block_end(drcbe->labels, block);
+ drcmap_block_end(drcbe->map, block);
+}
+
+
+/*-------------------------------------------------
+ drcbex86_hash_exists - return true if the
+ given mode/pc exists in the hash table
+-------------------------------------------------*/
+
+static int drcbex86_hash_exists(drcbe_state *drcbe, UINT32 mode, UINT32 pc)
+{
+ return drchash_code_exists(drcbe->hash, mode, pc);
+}
+
+
+/*-------------------------------------------------
+ drcbec_execute - execute a block of code
+ registered at the given mode/pc
+-------------------------------------------------*/
+
+static int drcbex86_execute(drcbe_state *drcbe, drcuml_codehandle *entry)
+{
+ /* call our entry point which will jump to the destination */
+ return (*drcbe->entry)((x86code *)drcuml_handle_codeptr(entry));
+}
+
+
+
+/***************************************************************************
+ COMPILE HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ param_normalize - convert a full parameter
+ into a reduced set
+-------------------------------------------------*/
+
+static void param_normalize(drcbe_state *drcbe, const drcuml_parameter *src, drcuml_parameter *dest, UINT32 allowed)
+{
+ int regnum;
+
+ switch (src->type)
+ {
+ /* immediates pass through */
+ case DRCUML_PTYPE_IMMEDIATE:
+ assert(allowed & PTYPE_I);
+ dest->type = DRCUML_PTYPE_IMMEDIATE;
+ dest->value = src->value;
+ break;
+
+ /* mapvars are converted to immediates with their current value */
+ case DRCUML_PTYPE_MAPVAR:
+ assert(allowed & PTYPE_I);
+ dest->type = DRCUML_PTYPE_IMMEDIATE;
+ dest->value = drcmap_get_last_value(drcbe->map, src->value);
+ break;
+
+ /* memory passes through */
+ case DRCUML_PTYPE_MEMORY:
+ assert(allowed & PTYPE_M);
+ dest->type = DRCUML_PTYPE_MEMORY;
+ dest->value = src->value;
+ break;
+
+ /* if a register maps to a register, keep it as a register; otherwise map it to memory */
+ case DRCUML_PTYPE_INT_REGISTER:
+ assert(allowed & PTYPE_R);
+ assert(allowed & PTYPE_M);
+ regnum = int_register_map[src->value - DRCUML_REG_I0];
+ if (regnum != 0)
+ {
+ dest->type = DRCUML_PTYPE_INT_REGISTER;
+ dest->value = regnum;
+ }
+ else
+ {
+ dest->type = DRCUML_PTYPE_MEMORY;
+ dest->value = (FPTR)&drcbe->state.r[src->value - DRCUML_REG_I0];
+ }
+ break;
+
+ /* all floating point registers map to memory */
+ case DRCUML_PTYPE_FLOAT_REGISTER:
+ assert(allowed & PTYPE_F);
+ assert(allowed & PTYPE_M);
+ dest->type = DRCUML_PTYPE_MEMORY;
+ dest->value = (FPTR)&drcbe->state.f[src->value - DRCUML_REG_F0];
+ break;
+
+ /* everything else is unexpected */
+ default:
+ fatalerror("Unexpected parameter type");
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+ param_normalize_1 - normalize a single
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_1(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0)
+{
+ assert(inst->numparams == 1);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_2 - normalize a 2
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_2(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1)
+{
+ assert(inst->numparams == 2);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+ param_normalize(drcbe, &inst->param[1], dest1, allowed1);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_2_commutative - normalize a 2
+ parameter instruction, shuffling the
+ parameters on the assumption that the two
+ parameters can be swapped
+-------------------------------------------------*/
+
+static void param_normalize_2_commutative(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1)
+{
+ param_normalize_2(drcbe, inst, dest0, allowed0, dest1, allowed1);
+
+ /* if the inner parameter is a memory operand, push it to the outer */
+ if (dest0->type == DRCUML_PTYPE_MEMORY)
+ {
+ drcuml_parameter temp = *dest0;
+ *dest0 = *dest1;
+ *dest1 = temp;
+ }
+
+ /* if the inner parameter is an immediate, push it to the outer */
+ if (dest0->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest0;
+ *dest0 = *dest1;
+ *dest1 = temp;
+ }
+}
+
+
+/*-------------------------------------------------
+ param_normalize_3 - normalize a 3
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_3(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2)
+{
+ assert(inst->numparams == 3);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+ param_normalize(drcbe, &inst->param[1], dest1, allowed1);
+ param_normalize(drcbe, &inst->param[2], dest2, allowed2);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_3_commutative - normalize a 3
+ parameter instruction, shuffling the
+ parameters on the assumption that the last
+ 2 can be swapped
+-------------------------------------------------*/
+
+static void param_normalize_3_commutative(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2)
+{
+ param_normalize_3(drcbe, inst, dest0, allowed0, dest1, allowed1, dest2, allowed2);
+
+ /* if the inner parameter is a memory operand, push it to the outer */
+ if (dest1->type == DRCUML_PTYPE_MEMORY)
+ {
+ drcuml_parameter temp = *dest1;
+ *dest1 = *dest2;
+ *dest2 = temp;
+ }
+
+ /* if the inner parameter is an immediate, push it to the outer */
+ if (dest1->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest1;
+ *dest1 = *dest2;
+ *dest2 = temp;
+ }
+
+ /* if the destination and outer parameters are equal, move the outer to the inner */
+ if (dest0->type == dest2->type && dest0->value == dest2->value && dest0->type != DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest1;
+ *dest1 = *dest2;
+ *dest2 = temp;
+ }
+}
+
+
+/*-------------------------------------------------
+ param_normalize_4 - normalize a 4
+ parameter instruction
+-------------------------------------------------*/
+
+static void param_normalize_4(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2, drcuml_parameter *dest3, UINT32 allowed3)
+{
+ assert(inst->numparams == 4);
+ param_normalize(drcbe, &inst->param[0], dest0, allowed0);
+ param_normalize(drcbe, &inst->param[1], dest1, allowed1);
+ param_normalize(drcbe, &inst->param[2], dest2, allowed2);
+ param_normalize(drcbe, &inst->param[3], dest3, allowed3);
+}
+
+
+/*-------------------------------------------------
+ param_normalize_4_commutative - normalize a 4
+ parameter instruction, shuffling the
+ parameters on the assumption that the last
+ 2 can be swapped
+-------------------------------------------------*/
+
+static void param_normalize_4_commutative(drcbe_state *drcbe, const drcuml_instruction *inst, drcuml_parameter *dest0, UINT32 allowed0, drcuml_parameter *dest1, UINT32 allowed1, drcuml_parameter *dest2, UINT32 allowed2, drcuml_parameter *dest3, UINT32 allowed3)
+{
+ param_normalize_4(drcbe, inst, dest0, allowed0, dest1, allowed1, dest2, allowed2, dest3, allowed3);
+
+ /* if the inner parameter is a memory operand, push it to the outer */
+ if (dest2->type == DRCUML_PTYPE_MEMORY)
+ {
+ drcuml_parameter temp = *dest2;
+ *dest2 = *dest3;
+ *dest3 = temp;
+ }
+
+ /* if the inner parameter is an immediate, push it to the outer */
+ if (dest2->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest2;
+ *dest2 = *dest3;
+ *dest3 = temp;
+ }
+
+ /* if the destination and outer parameters are equal, move the outer to the inner */
+ if (dest0->type == dest3->type && dest0->value == dest3->value && dest0->type != DRCUML_PTYPE_IMMEDIATE)
+ {
+ drcuml_parameter temp = *dest2;
+ *dest2 = *dest3;
+ *dest3 = temp;
+ }
+}
+
+
+
+/***************************************************************************
+ EMITTERS FOR 32-BIT OPERATIONS WITH PARAMETERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_mov_r32_p32 - move a 32-bit parameter
+ into a register
+-------------------------------------------------*/
+
+static void emit_mov_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (param->value == 0)
+ emit_xor_r32_r32(dst, reg, reg); // xor reg,reg
+ else
+ emit_mov_r32_imm(dst, reg, param->value); // mov reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r32_m32(dst, reg, MABS(param->value)); // mov reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_mov_r32_r32(dst, reg, param->value); // mov reg,param
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_mov_m32_p32 - move a 32-bit parameter
+ into a memory location
+-------------------------------------------------*/
+
+static void emit_mov_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(dst, MEMPARAMS, param->value); // mov [mem],param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r32_m32(dst, REG_EAX, MABS(param->value)); // mov eax,[param]
+ emit_mov_m32_r32(dst, MEMPARAMS, REG_EAX); // mov [mem],eax
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_r32(dst, MEMPARAMS, param->value); // mov [mem],param
+}
+
+
+/*-------------------------------------------------
+ emit_mov_p32_r32 - move a register into a
+ 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_mov_p32_r32(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *param, UINT8 reg)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_r32(dst, MABS(param->value), reg); // mov [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reg != param->value)
+ emit_mov_r32_r32(dst, param->value, reg); // mov param,reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_push_p32 - push a 32-bit parameter onto
+ the stack
+-------------------------------------------------*/
+
+static void emit_push_p32(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *src)
+{
+ if (src->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_push_imm(dst, src->value); // push src
+ else if (src->type == DRCUML_PTYPE_MEMORY)
+ emit_push_m32(dst, MABS(src->value)); // push [src]
+ else if (src->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_push_r32(dst, src->value); // push src
+}
+
+
+/*-------------------------------------------------
+ emit_add_r32_p32 - add operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_add_r32_imm(dst, reg, param->value); // add reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_add_r32_m32(dst, reg, MABS(param->value)); // add reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_add_r32_r32(dst, reg, param->value); // add reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_add_m32_p32 - add operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_add_m32_imm(dst, MEMPARAMS, param->value); // add [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_add_m32_r32(dst, MEMPARAMS, reg); // add [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_adc_r32_p32 - adc operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_adc_r32_imm(dst, reg, param->value); // adc reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_adc_r32_m32(dst, reg, MABS(param->value)); // adc reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_adc_r32_r32(dst, reg, param->value); // adc reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_adc_m32_p32 - adc operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_adc_m32_imm(dst, MEMPARAMS, param->value); // adc [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_adc_m32_r32(dst, MEMPARAMS, reg); // adc [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sub_r32_p32 - sub operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sub_r32_imm(dst, reg, param->value); // sub reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_sub_r32_m32(dst, reg, MABS(param->value)); // sub reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_sub_r32_r32(dst, reg, param->value); // sub reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_sub_m32_p32 - sub operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sub_m32_imm(dst, MEMPARAMS, param->value); // sub [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_sub_m32_r32(dst, MEMPARAMS, reg); // sub [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_r32_p32 - sbb operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sbb_r32_imm(dst, reg, param->value); // sbb reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_r32_m32(dst, reg, MABS(param->value)); // sbb reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_sbb_r32_r32(dst, reg, param->value); // sbb reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_m32_p32 - sbb operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 || param->value != 0)
+ emit_sbb_m32_imm(dst, MEMPARAMS, param->value); // sbb [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_sbb_m32_r32(dst, MEMPARAMS, reg); // sbb [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_r32_p32 - cmp operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_cmp_r32_imm(dst, reg, param->value); // cmp reg,param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_r32_m32(dst, reg, MABS(param->value)); // cmp reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_cmp_r32_r32(dst, reg, param->value); // cmp reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_r32_p32hi - cmp operation to a 32-bit
+ register from the upper 32 bits of a 64-bit
+ parameter
+-------------------------------------------------*/
+
+static void emit_cmp_r32_p32hi(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_cmp_r32_imm(dst, reg, param->value >> 32); // cmp reg,param >> 32
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_r32_m32(dst, reg, MABS(param->value + 4)); // cmp reg,[param+4]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_cmp_r32_m32(dst, reg, MABS(drcbe->reghi[param->value])); // cmp reg,reghi[param]
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_m32_p32 - cmp operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_cmp_m32_imm(dst, MEMPARAMS, param->value); // cmp [dest],param
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_cmp_m32_r32(dst, MEMPARAMS, reg); // cmp [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_cmp_m32_p32hi - cmp operation to a 32-bit
+ memory location from the upper half of a
+ 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_cmp_m32_p32hi(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_cmp_m32_imm(dst, MEMPARAMS, param->value >> 32); // cmp [dest],param >> 32
+ else
+ {
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_mov_r32_m32(dst, REG_EAX, MABS(param->value + 4)); // mov eax,[param+4]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_r32_m32(dst, REG_EAX, MABS(drcbe->reghi[param->value])); // mov eax,reghi[param]
+ emit_cmp_m32_r32(dst, MEMPARAMS, REG_EAX); // cmp [dest],eax
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_and_r32_p32 - and operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0)
+ emit_xor_r32_r32(dst, reg, reg); // xor reg,reg
+ else
+ emit_and_r32_imm(dst, reg, param->value); // and reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_and_r32_m32(dst, reg, MABS(param->value)); // and reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_and_r32_r32(dst, reg, param->value); // and reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_and_m32_p32 - and operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0)
+ emit_mov_m32_imm(dst, MEMPARAMS, 0); // mov [dest],0
+ else
+ emit_and_m32_imm(dst, MEMPARAMS, param->value); // and [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_and_m32_r32(dst, MEMPARAMS, reg); // and [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_test_r32_p32 - test operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_test_r32_imm(dst, reg, param->value); // test reg,param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_test_m32_r32(dst, MABS(param->value), reg); // test [param],reg
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_test_r32_r32(dst, reg, param->value); // test reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_test_m32_p32 - test operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ emit_test_m32_imm(dst, MEMPARAMS, param->value); // test [dest],param
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_EAX, param); // mov reg,param
+ emit_test_m32_r32(dst, MEMPARAMS, REG_EAX); // test [dest],reg
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_test_m32_r32(dst, MEMPARAMS, param->value); // test [dest],param
+}
+
+
+/*-------------------------------------------------
+ emit_or_r32_p32 - or operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_mov_r32_imm(dst, reg, -1); // mov reg,-1
+ else
+ emit_or_r32_imm(dst, reg, param->value); // or reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_or_r32_m32(dst, reg, MABS(param->value)); // or reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_or_r32_r32(dst, reg, param->value); // or reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_or_m32_p32 - or operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_mov_m32_imm(dst, MEMPARAMS, -1); // mov [dest],-1
+ else
+ emit_or_m32_imm(dst, MEMPARAMS, param->value); // or [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_or_m32_r32(dst, MEMPARAMS, reg); // or [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_xor_r32_p32 - xor operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_not_r32(dst, reg); // not reg
+ else
+ emit_xor_r32_imm(dst, reg, param->value); // xor reg,param
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ emit_xor_r32_m32(dst, reg, MABS(param->value)); // xor reg,[param]
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ emit_xor_r32_r32(dst, reg, param->value); // xor reg,param
+}
+
+
+/*-------------------------------------------------
+ emit_xor_m32_p32 - xor operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags != 0 && (UINT32)param->value == 0xffffffff)
+ emit_not_m32(dst, MEMPARAMS); // not [dest]
+ else
+ emit_xor_m32_imm(dst, MEMPARAMS, param->value); // xor [dest],param
+ }
+ else
+ {
+ int reg = param_select_register(REG_EAX, param, NULL);
+ emit_mov_r32_p32(drcbe, dst, reg, param); // mov reg,param
+ emit_xor_m32_r32(dst, MEMPARAMS, reg); // xor [dest],reg
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shl_r32_p32 - shl operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shl_r32_imm(dst, reg, param->value); // shl reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shl_r32_cl(dst, reg); // shl reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shl_m32_p32 - shl operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shl_m32_imm(dst, MEMPARAMS, param->value); // shl [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shl_m32_cl(dst, MEMPARAMS); // shl [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shr_r32_p32 - shr operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shr_r32_imm(dst, reg, param->value); // shr reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shr_r32_cl(dst, reg); // shr reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_shr_m32_p32 - shr operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_shr_m32_imm(dst, MEMPARAMS, param->value); // shr [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_shr_m32_cl(dst, MEMPARAMS); // shr [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sar_r32_p32 - sar operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_sar_r32_imm(dst, reg, param->value); // sar reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_sar_r32_cl(dst, reg); // sar reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_sar_m32_p32 - sar operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_sar_m32_imm(dst, MEMPARAMS, param->value); // sar [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_sar_m32_cl(dst, MEMPARAMS); // sar [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rol_r32_p32 - rol operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rol_r32_imm(dst, reg, param->value); // rol reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rol_r32_cl(dst, reg); // rol reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rol_m32_p32 - rol operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rol_m32_imm(dst, MEMPARAMS, param->value); // rol [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rol_m32_cl(dst, MEMPARAMS); // rol [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_ror_r32_p32 - ror operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_ror_r32_imm(dst, reg, param->value); // ror reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_ror_r32_cl(dst, reg); // ror reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_ror_m32_p32 - ror operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_ror_m32_imm(dst, MEMPARAMS, param->value); // ror [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_ror_m32_cl(dst, MEMPARAMS); // ror [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_r32_p32 - rcl operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcl_r32_imm(dst, reg, param->value); // rcl reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcl_r32_cl(dst, reg); // rcl reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_m32_p32 - rcl operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcl_m32_imm(dst, MEMPARAMS, param->value); // rcl [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcl_m32_cl(dst, MEMPARAMS); // rcl [dest],cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_r32_p32 - rcr operation to a 32-bit
+ register from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_r32_p32(drcbe_state *drcbe, x86code **dst, UINT8 reg, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcr_r32_imm(dst, reg, param->value); // rcr reg,param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcr_r32_cl(dst, reg); // rcr reg,cl
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_m32_p32 - rcr operation to a 32-bit
+ memory location from a 32-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_m32_p32(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags != 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else
+ emit_rcr_m32_imm(dst, MEMPARAMS, param->value); // rcr [dest],param
+ }
+ else
+ {
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_rcr_m32_cl(dst, MEMPARAMS); // rcr [dest],cl
+ }
+}
+
+
+
+/***************************************************************************
+ EMITTERS FOR 64-BIT OPERATIONS WITH PARAMETERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_mov_r64_p64 - move a 64-bit parameter
+ into a pair of registers
+-------------------------------------------------*/
+
+static void emit_mov_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param)
+{
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if ((UINT32)param->value == 0)
+ emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo
+ else
+ emit_mov_r32_imm(dst, reglo, param->value); // mov reglo,param
+ if ((UINT32)(param->value >> 32) == 0)
+ emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi
+ else
+ emit_mov_r32_imm(dst, reghi, param->value >> 32); // mov reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_r32_m32(dst, reglo, MABS(param->value)); // mov reglo,[param]
+ emit_mov_r32_m32(dst, reghi, MABS(param->value + 4)); // mov reghi,[param+4]
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reglo != param->value)
+ emit_mov_r32_r32(dst, reglo, param->value); // mov reglo,param
+ emit_mov_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // mov reghi,reghi[param]
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_mov_p64_r64 - move a pair of registers
+ into a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_mov_p64_r64(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *param, UINT8 reglo, UINT8 reghi)
+{
+ assert(param->type != DRCUML_PTYPE_IMMEDIATE);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_mov_m32_r32(dst, MABS(param->value), reglo); // mov [param],reglo
+ emit_mov_m32_r32(dst, MABS(param->value + 4), reghi); // mov [param+4],reghi
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ if (reglo != param->value)
+ emit_mov_r32_r32(dst, param->value, reglo); // mov param,reglo
+ emit_mov_m32_r32(dst, MABS(drcbe->reghi[param->value]), reghi); // mov reghi[param],reghi
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_push_p64 - push a 64-bit parameter onto
+ the stack
+-------------------------------------------------*/
+
+static void emit_push_p64(drcbe_state *drcbe, x86code **dst, const drcuml_parameter *src)
+{
+ if (src->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_push_imm(dst, src->value >> 32); // push src >> 32
+ emit_push_imm(dst, src->value); // push src
+ }
+ else if (src->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_push_m32(dst, MABS(src->value + 4)); // push [src+4]
+ emit_push_m32(dst, MABS(src->value)); // push [src]
+ }
+ else if (src->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_push_m32(dst, MABS(drcbe->reghi[src->value])); // push reghi[src]
+ emit_push_r32(dst, src->value); // push src
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_add_r64_p64 - add operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_add_r32_m32(dst, reglo, MABS(param->value)); // add reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_r32_m32(dst, reghi, MABS(param->value + 4)); // adc reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_add_r32_imm(dst, reglo, param->value); // add reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_r32_imm(dst, reghi, param->value >> 32); // adc reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_add_r32_r32(dst, reglo, param->value); // add reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // adc reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_add_m64_p64 - add operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_add_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_add_m32_imm(dst, MEMPARAMS, param->value); // add [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // adc [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_add_m32_r32(dst, MEMPARAMS, reglo); // add [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // adc [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_adc_r64_p64 - adc operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_adc_r32_m32(dst, reglo, MABS(param->value)); // adc reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_r32_m32(dst, reghi, MABS(param->value + 4)); // adc reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_adc_r32_imm(dst, reglo, param->value); // adc reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_r32_imm(dst, reghi, param->value >> 32); // adc reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_adc_r32_r32(dst, reglo, param->value); // adc reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // adc reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_adc_m64_p64 - adc operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_adc_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_adc_m32_imm(dst, MEMPARAMS, param->value); // adc [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // adc [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_adc_m32_r32(dst, MEMPARAMS, reglo); // adc [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_adc_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // adc [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_sub_r64_p64 - sub operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_sub_r32_m32(dst, reglo, MABS(param->value)); // sub reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_r32_m32(dst, reghi, MABS(param->value + 4)); // sbb reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_sub_r32_imm(dst, reglo, param->value); // sub reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_r32_imm(dst, reghi, param->value >> 32); // sbb reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_sub_r32_r32(dst, reglo, param->value); // sub reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // sbb reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_sub_m64_p64 - sub operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sub_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_sub_m32_imm(dst, MEMPARAMS, param->value); // sub [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // sbb [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_sub_m32_r32(dst, MEMPARAMS, reglo); // sub [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // sbb [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_r64_p64 - sbb operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_sbb_r32_m32(dst, reglo, MABS(param->value)); // sbb reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_r32_m32(dst, reghi, MABS(param->value + 4)); // sbb reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_sbb_r32_imm(dst, reglo, param->value); // sbb reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_r32_imm(dst, reghi, param->value >> 32); // sbb reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_sbb_r32_r32(dst, reglo, param->value); // sbb reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // sbb reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_sbb_m64_p64 - sbb operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sbb_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_sbb_m32_imm(dst, MEMPARAMS, param->value); // sbb [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // sbb [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_sbb_m32_r32(dst, MEMPARAMS, reglo); // sbb [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sbb_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // sbb [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_and_r64_p64 - and operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_and_r32_m32(dst, reglo, MABS(param->value)); // and reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_and_r32_m32(dst, reghi, MABS(param->value + 4)); // and reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags == 0 && (UINT32)param->value == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)param->value == 0)
+ emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo
+ else
+ emit_and_r32_imm(dst, reglo, param->value); // and reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0)
+ emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi
+ else
+ emit_and_r32_imm(dst, reghi, param->value >> 32); // and reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_and_r32_r32(dst, reglo, param->value); // and reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_and_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // and reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_and_m64_p64 - and operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_and_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags == 0 && (UINT32)param->value == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)param->value == 0)
+ emit_mov_m32_imm(dst, MEMPARAMS, 0); // mov [dest],0
+ else
+ emit_and_m32_imm(dst, MEMPARAMS, param->value); // and [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0xffffffff)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0)
+ emit_mov_m32_imm(dst, MEMPARAMS + 4, 0); // mov [dest+4],0
+ else
+ emit_and_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // and [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_and_m32_r32(dst, MEMPARAMS, reglo); // and [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_and_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // and [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_test_r64_p64 - test operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_test_m32_r32(dst, MABS(param->value), reglo); // test [param],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_test_m32_r32(dst, MABS(param->value + 4), reghi); // test [param],reghi
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_test_r32_imm(dst, reglo, param->value); // test reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_test_r32_imm(dst, reghi, param->value >> 32); // test reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_test_r32_r32(dst, reglo, param->value); // test reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_test_m32_r32(dst, MABS(drcbe->reghi[param->value]), reghi); // test reghi[param],reghi
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_test_m64_p64 - test operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_test_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_test_m32_imm(dst, MEMPARAMS, param->value); // test [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_test_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // test [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_test_m32_r32(dst, MEMPARAMS, reglo); // test [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_test_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // test [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_or_r64_p64 - or operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_or_r32_m32(dst, reglo, MABS(param->value)); // or reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_or_r32_m32(dst, reghi, MABS(param->value + 4)); // or reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags == 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)param->value == 0xffffffff)
+ emit_mov_r32_imm(dst, reglo, -1); // mov reglo,-1
+ else
+ emit_or_r32_imm(dst, reglo, param->value); // or reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0xffffffff)
+ emit_mov_r32_imm(dst, reghi, -1); // mov reghi,-1
+ else
+ emit_or_r32_imm(dst, reghi, param->value >> 32); // or reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_or_r32_r32(dst, reglo, param->value); // or reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_or_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // or reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_or_m64_p64 - or operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_or_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags == 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)param->value == 0xffffffff)
+ emit_mov_m32_imm(dst, MEMPARAMS, -1); // mov [dest],-1
+ else
+ emit_or_m32_imm(dst, MEMPARAMS, param->value); // or [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0xffffffff)
+ emit_mov_m32_imm(dst, MEMPARAMS + 4, -1); // mov [dest+4],-1
+ else
+ emit_or_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // or [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_or_m32_r32(dst, MEMPARAMS, reglo); // or [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_or_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // or [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_xor_r64_p64 - xor operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_xor_r32_m32(dst, reglo, MABS(param->value)); // xor reglo,[param]
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_xor_r32_m32(dst, reghi, MABS(param->value + 4)); // xor reghi,[param]
+ }
+ else if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags == 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)param->value == 0xffffffff)
+ emit_not_r32(dst, reglo); // not reglo
+ else
+ emit_xor_r32_imm(dst, reglo, param->value); // xor reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0xffffffff)
+ emit_not_r32(dst, reghi); // not reghi
+ else
+ emit_xor_r32_imm(dst, reghi, param->value >> 32); // xor reghi,param >> 32
+ }
+ else if (param->type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_xor_r32_r32(dst, reglo, param->value); // xor reglo,param
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_xor_r32_m32(dst, reghi, MABS(drcbe->reghi[param->value])); // xor reghi,reghi[param]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_xor_m64_p64 - xor operation to a 64-bit
+ memory location from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_xor_m64_p64(drcbe_state *drcbe, x86code **dst, DECLARE_MEMPARAMS, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->condflags == 0 && (UINT32)param->value == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)param->value == 0xffffffff)
+ emit_not_m32(dst, MEMPARAMS); // not [dest]
+ else
+ emit_xor_m32_imm(dst, MEMPARAMS, param->value); // xor [dest],param
+ if (saveflags) emit_pushf(dst); // pushf
+ if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0)
+ /* skip */;
+ else if (inst->condflags == 0 && (UINT32)(param->value >> 32) == 0xffffffff)
+ emit_not_m32(dst, MEMPARAMS + 4); // not [dest+4]
+ else
+ emit_xor_m32_imm(dst, MEMPARAMS + 4, param->value >> 32); // xor [dest+4],param >> 32
+ }
+ else
+ {
+ int reglo = (param->type == DRCUML_PTYPE_INT_REGISTER) ? param->value : REG_EAX;
+ emit_mov_r64_p64(drcbe, dst, reglo, REG_EDX, param); // mov edx:reglo,param
+ emit_xor_m32_r32(dst, MEMPARAMS, reglo); // xor [dest],reglo
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_xor_m32_r32(dst, MEMPARAMS + 4, REG_EDX); // xor [dest+4],edx
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_shl_r64_p64 - shl operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_shl_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = (inst->condflags != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ int count = param->value & 63;
+ if (inst->condflags != 0 && count == 0)
+ /* skip */;
+ else
+ {
+ while (count >= 32)
+ {
+ if (inst->condflags != 0)
+ {
+ emit_shld_r32_r32_imm(dst, reghi, reglo, 31); // shld reghi,reglo,31
+ emit_shl_r32_imm(dst, reglo, 31); // shl reglo,31
+ count -= 31;
+ }
+ else
+ {
+ emit_mov_r32_r32(dst, reghi, reglo); // mov reghi,reglo
+ emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo
+ count -= 32;
+ }
+ }
+ if (inst->condflags != 0 || count > 0)
+ {
+ emit_shld_r32_r32_imm(dst, reghi, reglo, count); // shld reghi,reglo,count
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shl_r32_imm(dst, reglo, count); // shl reglo,count
+ }
+ }
+ }
+ else
+ {
+ emit_link skip1, skip2;
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip1); // jz skip1
+ if (inst->condflags != 0)
+ {
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_shld_r32_r32_imm(dst, reghi, reglo, 31); // shld reghi,reglo,31
+ emit_shl_r32_imm(dst, reglo, 31); // shl reglo,31
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip2); // jz skip2
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_shld_r32_r32_imm(dst, reghi, reglo, 31); // shld reghi,reglo,31
+ emit_shl_r32_imm(dst, reglo, 31); // shl reglo,31
+ resolve_link(dst, &skip2); // skip2:
+ }
+ else
+ {
+ emit_mov_r32_r32(dst, reghi, reglo); // mov reghi,reglo
+ emit_xor_r32_r32(dst, reglo, reglo); // xor reglo,reglo
+ }
+ resolve_link(dst, &skip1); // skip1:
+ emit_shld_r32_r32_cl(dst, reghi, reglo); // shld reghi,reglo,cl
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shl_r32_cl(dst, reglo); // shl reglo,cl
+ }
+ if (saveflags)
+ emit_combine_z_shl_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_shr_r64_p64 - shr operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_shr_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ int count = param->value & 63;
+ if (inst->condflags != 0 && count == 0)
+ /* skip */;
+ else
+ {
+ while (count >= 32)
+ {
+ if (inst->condflags != 0)
+ {
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_shr_r32_imm(dst, reghi, 31); // shr reghi,31
+ count -= 31;
+ }
+ else
+ {
+ emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi
+ emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi
+ count -= 32;
+ }
+ }
+ if (inst->condflags != 0 || count > 0)
+ {
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, count); // shrd reglo,reghi,count
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shr_r32_imm(dst, reghi, count); // shr reghi,count
+ }
+ }
+ }
+ else
+ {
+ emit_link skip1, skip2;
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip1); // jz skip1
+ if (inst->condflags != 0)
+ {
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_shr_r32_imm(dst, reghi, 31); // shr reghi,31
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip2); // jz skip2
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_shr_r32_imm(dst, reghi, 31); // shr reghi,31
+ resolve_link(dst, &skip2); // skip2:
+ }
+ else
+ {
+ emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi
+ emit_xor_r32_r32(dst, reghi, reghi); // xor reghi,reghi
+ }
+ resolve_link(dst, &skip1); // skip1:
+ emit_shrd_r32_r32_cl(dst, reglo, reghi); // shrd reglo,reghi,cl
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shr_r32_cl(dst, reghi); // shr reghi,cl
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_sar_r64_p64 - sar operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_sar_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ int count = param->value & 63;
+ if (inst->condflags != 0 && count == 0)
+ /* skip */;
+ else
+ {
+ while (count >= 32)
+ {
+ if (inst->condflags != 0)
+ {
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31
+ count -= 31;
+ }
+ else
+ {
+ emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi
+ emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31
+ count -= 32;
+ }
+ }
+ if (inst->condflags != 0 || count > 0)
+ {
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, count); // shrd reglo,reghi,count
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sar_r32_imm(dst, reghi, count); // sar reghi,count
+ }
+ }
+ }
+ else
+ {
+ emit_link skip1, skip2;
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip1); // jz skip1
+ if (inst->condflags != 0)
+ {
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip2); // jz skip
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31
+ resolve_link(dst, &skip2); // skip2:
+ }
+ else
+ {
+ emit_mov_r32_r32(dst, reglo, reghi); // mov reglo,reghi
+ emit_sar_r32_imm(dst, reghi, 31); // sar reghi,31
+ }
+ resolve_link(dst, &skip1); // skip1:
+ emit_shrd_r32_r32_cl(dst, reglo, reghi); // shrd reglo,reghi,cl
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_sar_r32_cl(dst, reghi); // sar reghi,cl
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_rol_r64_p64 - rol operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rol_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ int count = param->value & 63;
+ if (inst->condflags != 0 && count == 0)
+ /* skip */;
+ else
+ {
+ while (count >= 32)
+ {
+ if (inst->condflags != 0)
+ {
+ emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo
+ emit_shld_r32_r32_imm(dst, reglo, reghi, 31); // shld reglo,reghi,31
+ emit_shld_r32_r32_imm(dst, reghi, REG_ECX, 31); // shld reghi,ecx,31
+ count -= 31;
+ }
+ else
+ {
+ emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo
+ count -= 32;
+ }
+ }
+ if (inst->condflags != 0 || count > 0)
+ {
+ emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo
+ emit_shld_r32_r32_imm(dst, reglo, reghi, count); // shld reglo,reghi,count
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shld_r32_r32_imm(dst, reghi, REG_ECX, count); // shld reghi,ecx,count
+ }
+ }
+ }
+ else
+ {
+ emit_link skip1, skip2;
+ emit_mov_m32_r32(dst, MBD(REG_ESP, -8), REG_EBX); // mov [esp-8],ebx
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip1); // jz skip1
+ if (inst->condflags != 0)
+ {
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_mov_r32_r32(dst, REG_EBX, reglo); // mov ebx,reglo
+ emit_shld_r32_r32_imm(dst, reglo, reghi, 31); // shld reglo,reghi,31
+ emit_shld_r32_r32_imm(dst, reghi, REG_EBX, 31); // shld reghi,ebx,31
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip2); // jz skip2
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_mov_r32_r32(dst, REG_EBX, reglo); // mov ebx,reglo
+ emit_shld_r32_r32_imm(dst, reglo, reghi, 31); // shld reglo,reghi,31
+ emit_shld_r32_r32_imm(dst, reghi, REG_EBX, 31); // shld reghi,ebx,31
+ resolve_link(dst, &skip2); // skip2:
+ }
+ else
+ emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo
+ resolve_link(dst, &skip1); // skip1:
+ emit_mov_r32_r32(dst, REG_EBX, reglo); // mov ebx,reglo
+ emit_shld_r32_r32_cl(dst, reglo, reghi); // shld reglo,reghi,cl
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shld_r32_r32_cl(dst, reghi, REG_EBX); // shld reghi,ebx,cl
+ emit_mov_r32_m32(dst, MBD(REG_ESP, saveflags ? -4 : -8), REG_EBX); // mov ebx,[esp-8]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_ror_r64_p64 - ror operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_ror_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ if (param->type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ int count = param->value & 63;
+ if (inst->condflags != 0 && count == 0)
+ /* skip */;
+ else
+ {
+ while (count >= 32)
+ {
+ if (inst->condflags != 0)
+ {
+ emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_shrd_r32_r32_imm(dst, reghi, REG_ECX, 31); // shrd reghi,ecx,31
+ count -= 31;
+ }
+ else
+ {
+ emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo
+ count -= 32;
+ }
+ }
+ if (inst->condflags != 0 || count > 0)
+ {
+ emit_mov_r32_r32(dst, REG_ECX, reglo); // mov ecx,reglo
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, count); // shrd reglo,reghi,count
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shrd_r32_r32_imm(dst, reghi, REG_ECX, count); // shrd reghi,ecx,count
+ }
+ }
+ }
+ else
+ {
+ emit_link skip1, skip2;
+ emit_mov_m32_r32(dst, MBD(REG_ESP, -8), REG_EBX); // mov [esp-8],ebx
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip1); // jz skip1
+ if (inst->condflags != 0)
+ {
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_mov_r32_r32(dst, REG_EBX, reglo); // mov ebx,reglo
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_shrd_r32_r32_imm(dst, reghi, REG_EBX, 31); // shrd reghi,ebx,31
+ emit_test_r32_imm(dst, REG_ECX, 0x20); // test ecx,0x20
+ emit_jcc_short_link(dst, COND_Z, &skip2); // jz skip2
+ emit_sub_r32_imm(dst, REG_ECX, 31); // sub ecx,31
+ emit_mov_r32_r32(dst, REG_EBX, reglo); // mov ebx,reglo
+ emit_shrd_r32_r32_imm(dst, reglo, reghi, 31); // shrd reglo,reghi,31
+ emit_shrd_r32_r32_imm(dst, reghi, REG_EBX, 31); // shrd reghi,ebx,31
+ resolve_link(dst, &skip2); // skip2:
+ }
+ else
+ emit_xchg_r32_r32(dst, reghi, reglo); // xchg reghi,reglo
+ resolve_link(dst, &skip1); // skip1:
+ emit_mov_r32_r32(dst, REG_EBX, reglo); // mov ebx,reglo
+ emit_shrd_r32_r32_cl(dst, reglo, reghi); // shrd reglo,reghi,cl
+ if (saveflags) emit_pushf(dst); // pushf
+ emit_shrd_r32_r32_cl(dst, reghi, REG_EBX); // shrd reghi,ebx,cl
+ emit_mov_r32_m32(dst, MBD(REG_ESP, saveflags ? -4 : -8), REG_EBX); // mov ebx,[esp-8]
+ }
+ if (saveflags)
+ emit_combine_z_flags(dst);
+}
+
+
+/*-------------------------------------------------
+ emit_rcl_r64_p64 - rcl operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcl_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = ((inst->condflags & DRCUML_FLAG_Z) != 0);
+ emit_link skipall, skiploop;
+ x86code *loop;
+
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ if (!saveflags)
+ {
+ loop = *dst; // loop:
+ emit_jecxz_link(dst, &skipall); // jecxz skipall
+ emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1]
+ emit_rcl_r32_imm(dst, reglo, 1); // rcl reglo,1
+ emit_rcl_r32_imm(dst, reghi, 1); // rcl reghi,1
+ emit_jmp(dst, loop); // jmp loop
+ resolve_link(dst, &skipall); // skipall:
+ }
+ else
+ {
+ emit_jecxz_link(dst, &skipall); // jecxz skipall
+ emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1]
+ loop = *dst; // loop:
+ emit_jecxz_link(dst, &skiploop); // jecxz skiploop
+ emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1]
+ emit_rcl_r32_imm(dst, reglo, 1); // rcl reglo,1
+ emit_rcl_r32_imm(dst, reghi, 1); // rcl reghi,1
+ emit_jmp(dst, loop); // jmp loop
+ resolve_link(dst, &skiploop); // skiploop:
+ emit_rcl_r32_imm(dst, reglo, 1); // rcl reglo,1
+ emit_pushf(dst); // pushf
+ emit_rcl_r32_imm(dst, reghi, 1); // rcl reghi,1
+ resolve_link(dst, &skipall); // skipall:
+ emit_combine_z_flags(dst);
+ }
+}
+
+
+/*-------------------------------------------------
+ emit_rcr_r64_p64 - rcr operation to a 64-bit
+ pair of registers from a 64-bit parameter
+-------------------------------------------------*/
+
+static void emit_rcr_r64_p64(drcbe_state *drcbe, x86code **dst, UINT8 reglo, UINT8 reghi, const drcuml_parameter *param, const drcuml_instruction *inst)
+{
+ int saveflags = (inst->condflags != 0);
+ emit_link skipall, skiploop;
+ x86code *loop;
+
+ emit_mov_r32_p32(drcbe, dst, REG_ECX, param); // mov ecx,param
+ if (!saveflags)
+ {
+ loop = *dst; // loop:
+ emit_jecxz_link(dst, &skipall); // jecxz skipall
+ emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1]
+ emit_rcr_r32_imm(dst, reghi, 1); // rcr reghi,1
+ emit_rcr_r32_imm(dst, reglo, 1); // rcr reglo,1
+ emit_jmp(dst, loop); // jmp loop
+ resolve_link(dst, &skipall); // skipall:
+ }
+ else
+ {
+ emit_jecxz_link(dst, &skipall); // jecxz skipall
+ emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1]
+ loop = *dst; // loop:
+ emit_jecxz_link(dst, &skiploop); // jecxz skiploop
+ emit_lea_r32_m32(dst, REG_ECX, MBD(REG_ECX, -1)); // lea ecx,[ecx-1]
+ emit_rcr_r32_imm(dst, reghi, 1); // rcr reghi,1
+ emit_rcr_r32_imm(dst, reglo, 1); // rcr reglo,1
+ emit_jmp(dst, loop); // jmp loop
+ resolve_link(dst, &skiploop); // skiploop:
+ emit_rcr_r32_imm(dst, reghi, 1); // rcr reghi,1
+ emit_pushf(dst); // pushf
+ emit_rcr_r32_imm(dst, reglo, 1); // rcr reglo,1
+ resolve_link(dst, &skipall); // skipall:
+ emit_combine_z_shl_flags(dst);
+ }
+}
+
+
+
+/***************************************************************************
+ EMITTERS FOR FLOATING POINT
+***************************************************************************/
+
+/*-------------------------------------------------
+ emit_fld_p - load a floating point parameter
+ onto the stack
+-------------------------------------------------*/
+
+static void emit_fld_p(x86code **dst, int size, const drcuml_parameter *param)
+{
+ assert(param->type == DRCUML_PTYPE_MEMORY);
+ assert(size == 4 || size == 8);
+ if (size == 4)
+ emit_fld_m32(dst, MABS(param->value));
+ else if (size == 8)
+ emit_fld_m64(dst, MABS(param->value));
+}
+
+
+/*-------------------------------------------------
+ emit_fstp_p - store a floating point parameter
+ from the stack and pop it
+-------------------------------------------------*/
+
+static void emit_fstp_p(x86code **dst, int size, const drcuml_parameter *param)
+{
+ assert(param->type == DRCUML_PTYPE_MEMORY);
+ assert(size == 4 || size == 8);
+ if (size == 4)
+ emit_fstp_m32(dst, MABS(param->value));
+ else if (size == 8)
+ emit_fstp_m64(dst, MABS(param->value));
+}
+
+
+
+/***************************************************************************
+ HELPERS TO CONVERT OTHER OPERATIONS TO MOVES
+***************************************************************************/
+
+/*-------------------------------------------------
+ convert_to_mov_imm - convert an instruction
+ into a mov immediate
+-------------------------------------------------*/
+
+static x86code *convert_to_mov_imm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, const drcuml_parameter *dstp, UINT64 imm)
+{
+ drcuml_instruction temp = *inst;
+ temp.numparams = 2;
+ temp.param[0] = *dstp;
+ temp.param[1].type = DRCUML_PTYPE_IMMEDIATE;
+ temp.param[1].value = imm;
+ return op_mov(drcbe, dst, &temp);
+}
+
+
+/*-------------------------------------------------
+ convert_to_mov_src1 - convert an instruction
+ into a mov src1
+-------------------------------------------------*/
+
+static x86code *convert_to_mov_src1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, const drcuml_parameter *dstp, const drcuml_parameter *srcp)
+{
+ drcuml_instruction temp = *inst;
+ temp.numparams = 2;
+ temp.param[0] = *dstp;
+ temp.param[1] = *srcp;
+ return op_mov(drcbe, dst, &temp);
+}
+
+
+
+/***************************************************************************
+ OUT-OF-BAND CODE FIXUP CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ fixup_label - callback to fixup forward-
+ referenced labels
+-------------------------------------------------*/
+
+static void fixup_label(void *parameter, drccodeptr labelcodeptr)
+{
+ drccodeptr src = parameter;
+
+ /* find the end of the instruction */
+ if (src[0] == 0xe3)
+ {
+ src += 1 + 1;
+ src[-1] = labelcodeptr - src;
+ }
+ else if (src[0] == 0xe9)
+ {
+ src += 1 + 4;
+ ((UINT32 *)src)[-1] = labelcodeptr - src;
+ }
+ else if (src[0] == 0x0f && (src[1] & 0xf0) == 0x80)
+ {
+ src += 2 + 4;
+ ((UINT32 *)src)[-1] = labelcodeptr - src;
+ }
+ else
+ fatalerror("fixup_label called with invalid jmp source!");
+}
+
+
+/*-------------------------------------------------
+ fixup_exception - callback to perform cleanup
+ and jump to an exception handler
+-------------------------------------------------*/
+
+static void fixup_exception(drccodeptr *codeptr, void *param1, void *param2, void *param3)
+{
+ drcuml_parameter handp, exp;
+ drcbe_state *drcbe = param1;
+ drccodeptr src = param2;
+ const drcuml_instruction *inst = param3;
+ drccodeptr dst = *codeptr;
+ drccodeptr *targetptr;
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &handp, PTYPE_M, &exp, PTYPE_MRI);
+
+ /* look up the handle target */
+ targetptr = drcuml_handle_codeptr_addr((drcuml_codehandle *)(FPTR)handp.value);
+
+ /* first fixup the jump to get us here */
+ ((UINT32 *)src)[-1] = dst - src;
+
+ /* then store the exception parameter */
+ emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp), &exp); // mov [exp],exp
+
+ /* push the original return address on the stack */
+ emit_push_imm(&dst, (FPTR)src); // push <return>
+ if (*targetptr != NULL)
+ emit_jmp(&dst, *targetptr); // jmp *targetptr
+ else
+ emit_jmp_m32(&dst, MABS(targetptr)); // jmp [targetptr]
+
+ *codeptr = dst;
+}
+
+
+
+/***************************************************************************
+ DEBUG HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ debug_log_hashjmp - callback to handle
+ logging of hashjmps
+-------------------------------------------------*/
+
+#if LOG_HASHJMPS
+static void debug_log_hashjmp(int mode, offs_t pc)
+{
+ printf("mode=%d PC=%08X\n", mode, pc);
+}
+#endif
+
+
+
+/***************************************************************************
+ COMPILE-TIME OPCODES
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_handle - process a HANDLE opcode
+-------------------------------------------------*/
+
+static x86code *op_handle(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_MEMORY);
+
+ /* register the current pointer for the handle */
+ drcuml_handle_set_codeptr((drcuml_codehandle *)(FPTR)inst->param[0].value, dst);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_hash - process a HASH opcode
+-------------------------------------------------*/
+
+static x86code *op_hash(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 2);
+ assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
+ assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
+
+ /* register the current pointer for the mode/PC */
+ drchash_set_codeptr(drcbe->hash, inst->param[0].value, inst->param[1].value, dst);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_label - process a LABEL opcode
+-------------------------------------------------*/
+
+static x86code *op_label(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE);
+
+ /* register the current pointer for the label */
+ drclabel_set_codeptr(drcbe->labels, inst->param[0].value, dst);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_comment - process a COMMENT opcode
+-------------------------------------------------*/
+
+static x86code *op_comment(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 1);
+ assert(inst->param[0].type == DRCUML_PTYPE_MEMORY);
+
+ /* do nothing */
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_mapvar - process a MAPVAR opcode
+-------------------------------------------------*/
+
+static x86code *op_mapvar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ assert(inst->numparams == 2);
+ assert(inst->param[0].type == DRCUML_PTYPE_MAPVAR);
+ assert(inst->param[1].type == DRCUML_PTYPE_IMMEDIATE);
+
+ /* set the value of the specified mapvar */
+ drcmap_set_value(drcbe->map, dst, inst->param[0].value, inst->param[1].value);
+ return dst;
+}
+
+
+
+/***************************************************************************
+ CONTROL FLOW OPCODES
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_debug - process a DEBUG opcode
+-------------------------------------------------*/
+
+static x86code *op_debug(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+#ifdef ENABLE_DEBUGGER
+ if (Machine->debug_mode)
+ {
+ drcuml_parameter pcp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &pcp, PTYPE_MRI);
+
+ /* push the parameter */
+ emit_push_p32(drcbe, &dst, &pcp); // push pcp
+ emit_call(&dst, (x86code *)mame_debug_hook); // call mame_debug_hook
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+ }
+#endif
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_exit - process an EXIT opcode
+-------------------------------------------------*/
+
+static x86code *op_exit(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter retp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &retp, PTYPE_MRI);
+
+ /* load the parameter into EAX */
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &retp); // mov eax,retp
+ if (inst->condflags == DRCUML_COND_ALWAYS)
+ emit_jmp(&dst, drcbe->exit); // jmp exit
+ else
+ emit_jcc(&dst, X86_CONDITION(inst->condflags), drcbe->exit); // jcc exit
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_hashjmp - process a HASHJMP opcode
+-------------------------------------------------*/
+
+static x86code *op_hashjmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter modep, pcp, exp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &modep, PTYPE_MRI, &pcp, PTYPE_MRI, &exp, PTYPE_M);
+
+#if LOG_HASHJMPS
+ emit_push_p32(drcbe, &dst, &pcp);
+ emit_push_p32(drcbe, &dst, &modep);
+ emit_call(&dst, (x86code *)debug_log_hashjmp);
+ emit_add_r32_imm(&dst, REG_ESP, 8);
+#endif
+
+ /* load the stack base one word early so we end up at the right spot after our call below */
+ emit_mov_r32_m32(&dst, REG_ESP, MABS(&drcbe->hashstacksave)); // mov esp,[hashstacksave]
+
+ /* fixed mode cases */
+ if (modep.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ /* a straight immediate jump is direct, though we need the PC in EAX in case of failure */
+ if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask;
+ UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask;
+ emit_call_m32(&dst, MABS(&drcbe->hash->base[modep.value][l1val][l2val])); // call hash[modep][l1val][l2val]
+ }
+
+ /* a fixed mode but variable PC */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
+ emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
+ emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift
+ emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift
+ emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EDX, 4, &drcbe->hash->base[modep.value][0]));
+ // mov edx,hash[modep+edx*4]
+ emit_call_m32(&dst, MBISD(REG_EDX, REG_EAX, 4 >> drcbe->hash->l2shift, 0)); // call [edx+eax*shift]
+ }
+ }
+ else
+ {
+ /* variable mode */
+ int modereg = param_select_register(REG_ECX, &modep, NULL);
+ emit_mov_r32_p32(drcbe, &dst, modereg, &modep); // mov modereg,modep
+ emit_mov_r32_m32(&dst, REG_ECX, MISD(modereg, 4, &drcbe->hash->base[0])); // mov ecx,hash[modereg*4]
+
+ /* fixed PC */
+ if (pcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ UINT32 l1val = (pcp.value >> drcbe->hash->l1shift) & drcbe->hash->l1mask;
+ UINT32 l2val = (pcp.value >> drcbe->hash->l2shift) & drcbe->hash->l2mask;
+ emit_mov_r32_m32(&dst, REG_EDX, MBD(REG_ECX, l1val*4)); // mov edx,[ecx+l1val*4]
+ emit_call_m32(&dst, MBD(REG_EDX, l2val*4)); // call [l2val*4]
+ }
+
+ /* variable PC */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &pcp); // mov eax,pcp
+ emit_mov_r32_r32(&dst, REG_EDX, REG_EAX); // mov edx,eax
+ emit_shr_r32_imm(&dst, REG_EDX, drcbe->hash->l1shift); // shr edx,l1shift
+ emit_mov_r32_m32(&dst, REG_EDX, MBISD(REG_ECX, REG_EDX, 4, 0)); // mov edx,[ecx+edx*4]
+ emit_and_r32_imm(&dst, REG_EAX, drcbe->hash->l2mask << drcbe->hash->l2shift);// and eax,l2mask << l2shift
+ emit_call_m32(&dst, MBISD(REG_EDX, REG_EAX, 4 >> drcbe->hash->l2shift, 0)); // call [edx+eax*shift]
+ }
+ }
+
+ /* in all cases, if there is no code, we return here to generate the exception */
+ emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp.l), &pcp); // mov [exp],param
+ emit_sub_r32_imm(&dst, REG_ESP, 4); // sub esp,4
+ emit_call_m32(&dst, MABS(exp.value)); // call [exp]
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_jmp - process a JMP opcode
+-------------------------------------------------*/
+
+static x86code *op_jmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter labelp;
+ x86code *jmptarget;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &labelp, PTYPE_I);
+
+ /* look up the jump target and jump there */
+ jmptarget = (x86code *)drclabel_get_codeptr(drcbe->labels, labelp.value, fixup_label, dst);
+ if (inst->condflags == DRCUML_COND_ALWAYS)
+ emit_jmp(&dst, jmptarget); // jmp target
+ else
+ emit_jcc(&dst, X86_CONDITION(inst->condflags), jmptarget); // jcc target
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_exh - process an EXH opcode
+-------------------------------------------------*/
+
+static x86code *op_exh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter handp, exp;
+ drccodeptr *targetptr;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &handp, PTYPE_M, &exp, PTYPE_MRI);
+
+ /* look up the handle target */
+ targetptr = drcuml_handle_codeptr_addr((drcuml_codehandle *)(FPTR)handp.value);
+
+ /* perform the exception processing inline if unconditional */
+ if (inst->condflags == DRCUML_COND_ALWAYS)
+ {
+ emit_mov_m32_p32(drcbe, &dst, MABS(&drcbe->state.exp.l), &exp); // mov [exp],exp
+ if (*targetptr != NULL)
+ emit_call(&dst, *targetptr); // call *targetptr
+ else
+ emit_call_m32(&dst, MABS(targetptr)); // call [targetptr]
+ }
+
+ /* otherwise, jump to an out-of-band handler */
+ else
+ {
+ emit_jcc(&dst, X86_CONDITION(inst->condflags), 0); // jcc exception
+ drccache_request_oob_codegen(drcbe->cache, fixup_exception, drcbe, dst, (void *)inst);
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_callh - process a CALLH opcode
+-------------------------------------------------*/
+
+static x86code *op_callh(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter handp;
+ drccodeptr *targetptr;
+ emit_link skip = { 0 };
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &handp, PTYPE_M);
+
+ /* look up the handle target */
+ targetptr = drcuml_handle_codeptr_addr((drcuml_codehandle *)(FPTR)handp.value);
+
+ /* skip if conditional */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* jump through the handle; directly if a normal jump */
+ if (*targetptr != NULL)
+ emit_call(&dst, *targetptr); // call *targetptr
+ else
+ emit_call_m32(&dst, MABS(targetptr)); // call [targetptr]
+
+ /* resolve the conditional link */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ret - process a RET opcode
+-------------------------------------------------*/
+
+static x86code *op_ret(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ emit_link skip = { 0 };
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+ assert(inst->numparams == 0);
+
+ /* skip if conditional */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* return */
+ emit_ret(&dst); // ret
+
+ /* resolve the conditional link */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_callc - process a CALLC opcode
+-------------------------------------------------*/
+
+static x86code *op_callc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter funcp, paramp;
+ emit_link skip = { 0 };
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &funcp, PTYPE_M, &paramp, PTYPE_M);
+
+ /* skip if conditional */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* perform the call */
+ emit_push_imm(&dst, paramp.value); // push paramp
+ emit_call(&dst, (x86code *)(FPTR)funcp.value); // call funcp
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+
+ /* resolve the conditional link */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_recover - process a RECOVER opcode
+-------------------------------------------------*/
+
+static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, mvparam;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &mvparam, PTYPE_I);
+
+ /* call the recovery code */
+ emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->stacksave)); // mov eax,stacksave
+ emit_mov_r32_m32(&dst, REG_EAX, MBD(REG_EAX, -4)); // mov eax,[eax-4]
+ emit_sub_r32_imm(&dst, REG_EAX, 1); // sub eax,1
+ emit_push_imm(&dst, inst->param[1].value); // push param1
+ emit_push_r32(&dst, REG_EAX); // push eax
+ emit_push_imm(&dst, (FPTR)drcbe->map); // push drcbe->map
+ emit_call(&dst, (x86code *)drcmap_get_value); // call drcmap_get_value
+ emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+
+ return dst;
+}
+
+
+
+/***************************************************************************
+ INTERNAL REGISTER OPCODES
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_setfmod - process a SETFMOD opcode
+-------------------------------------------------*/
+
+static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &srcp, PTYPE_MRI);
+
+ /* immediate case */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ srcp.value &= 3;
+ emit_mov_m8_imm(&dst, MABS(&drcbe->state.fmod), srcp.value); // mov [fmod],srcp
+ emit_fldcw_m16(&dst, MABS(&fp_control[srcp.value])); // fldcw fp_control[srcp]
+ }
+
+ /* register/memory case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &srcp); // mov eax,srcp
+ emit_and_r32_imm(&dst, REG_EAX, 3); // and eax,3
+ emit_mov_m8_r8(&dst, MABS(&drcbe->state.fmod), REG_AL); // mov [fmod],al
+ emit_fldcw_m16(&dst, MISD(REG_EAX, 2, &fp_control[0])); // fldcw fp_control[eax]
+ }
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_getfmod - process a GETFMOD opcode
+-------------------------------------------------*/
+
+static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &dstp, PTYPE_MR);
+
+ /* fetch the current mode and store to the destination */
+ if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_m8(&dst, dstp.value, MABS(&drcbe->state.fmod)); // movzx reg,[fmod]
+ else
+ {
+ emit_movzx_r32_m8(&dst, REG_EAX, MABS(&drcbe->state.fmod)); // movzx eax,[fmod]
+ emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax
+ }
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_getexp - process a GETEXP opcode
+-------------------------------------------------*/
+
+static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_1(drcbe, inst, &dstp, PTYPE_MR);
+
+ /* fetch the exception parameter and store to the destination */
+ if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_r32_m32(&dst, dstp.value, MABS(&drcbe->state.exp.l)); // mov reg,[exp]
+ else
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS(&drcbe->state.exp.l)); // mov eax,[exp]
+ emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax
+ }
+
+ return dst;
+}
+
+
+
+/***************************************************************************
+ INTEGER OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_load1u - process a LOAD1U opcode
+-------------------------------------------------*/
+
+static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movzx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movzx dstreg,[basep + 1*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movzx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movzx dstreg,[basep + 1*indp]
+ }
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load1s - process a LOAD1S opcode
+-------------------------------------------------*/
+
+static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movsx eax,[basep + 1*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movsx eax,[basep + 1*indp]
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* general case */
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load2u - process a LOAD2U opcode
+-------------------------------------------------*/
+
+static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movzx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movzx dstreg,[basep + 2*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movzx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movzx dstreg,[basep + 2*indp]
+ }
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load2s - process a LOAD2S opcode
+-------------------------------------------------*/
+
+static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_movsx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movsx eax,[basep + 2*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_movsx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movsx eax,[basep + 2*indp]
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* general case */
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load4u - process a LOAD4U opcode
+-------------------------------------------------*/
+
+static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp]
+ }
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load4s - process a LOAD4S opcode
+-------------------------------------------------*/
+
+static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_m32(&dst, REG_EAX, MABS(basep.value + 4*indp.value)); // mov eax,[basep + 4*indp]
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_mov_r32_m32(&dst, REG_EAX, MISD(indreg, 4, basep.value)); // movsx eax,[basep + 4*indp]
+ }
+
+ /* general case */
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_load8u - process a LOAD8U opcode
+-------------------------------------------------*/
+
+static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4]
+ emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp]
+ }
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4]
+ emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp]
+ }
+
+ /* general case */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store1 - process a STORE1 opcode
+-------------------------------------------------*/
+
+static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int srcreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+ if (srcreg & 4)
+ srcreg = REG_EAX;
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m8_imm(&dst, MABS(basep.value + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m8_r8(&dst, MABS(basep.value + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m8_imm(&dst, MISD(indreg, 1, basep.value), srcp.value); // mov [basep + 1*ecx],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m8_r8(&dst, MISD(indreg, 1, basep.value), srcreg); // mov [basep + 1*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store2 - process a STORE2 opcode
+-------------------------------------------------*/
+
+static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int srcreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m16_imm(&dst, MABS(basep.value + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m16_r16(&dst, MABS(basep.value + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m16_imm(&dst, MISD(indreg, 2, basep.value), srcp.value); // mov [basep + 2*ecx],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m16_r16(&dst, MISD(indreg, 2, basep.value), srcreg); // mov [basep + 2*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store4 - process a STORE4 opcode
+-------------------------------------------------*/
+
+static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int srcreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(&dst, MABS(basep.value + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m32_r32(&dst, MABS(basep.value + indp.value), srcreg); // mov [basep + 4*indp],srcreg
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(&dst, MISD(indreg, 4, basep.value), srcp.value); // mov [basep + 4*ecx],srcp
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp
+ emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), srcreg); // mov [basep + 4*ecx],srcreg
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_store8 - process a STORE8 opcode
+-------------------------------------------------*/
+
+static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+ int srcreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* pick a source register for the general case */
+ srcreg = param_select_register(REG_EAX, &srcp, NULL);
+
+ /* degenerate case: constant index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp
+ emit_mov_m32_imm(&dst, MABS(basep.value + 4 + 8*indp.value), srcp.value >> 32);
+ // mov [basep + 4 + 8*indp],srcp >> 32
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp
+ emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg
+ emit_mov_m32_r32(&dst, MABS(basep.value + 4 + 8*indp.value), REG_EDX); // mov [basep + 8*indp + 4],edx
+ }
+ }
+
+ /* normal case: variable index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value), srcp.value); // mov [basep + 8*ecx],srcp
+ emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value + 4), srcp.value >> 32); // mov [basep + 8*ecx + 4],srcp >> 32
+ }
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp
+ emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value), srcreg); // mov [basep + 8*ecx],srcreg
+ emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value + 4), REG_EDX); // mov [basep + 4 + 8*ecx],edx
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read1u - process a READ1U opcode
+-------------------------------------------------*/
+
+static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read byte handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_byte);// call read_byte
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+ emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read1s - process a READ1S opcode
+-------------------------------------------------*/
+
+static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read byte handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_byte);// call read_byte
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+ emit_movsx_r32_r8(&dst, dstreg, REG_AL); // movsx dstreg,al
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* general case */
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read2u - process a READ2U opcode
+-------------------------------------------------*/
+
+static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read word handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word);// call read_word
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+ emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read2s - process a READ2S opcode
+-------------------------------------------------*/
+
+static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read word handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word);// call read_word
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+ emit_movsx_r32_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* general case */
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read2m - process a READ2M opcode
+-------------------------------------------------*/
+
+static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp, maskp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* set up a call to the read dword masked handler */
+ emit_push_p32(drcbe, &dst, &maskp); // push maskp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word_masked);
+ // call read_word_masked
+ emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8
+ emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read4u - process a READ4U opcode
+-------------------------------------------------*/
+
+static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read dword handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read4s - process a READ4S opcode
+-------------------------------------------------*/
+
+static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read dword handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+
+ /* 64-bit form */
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read4m - process a READ4M opcode
+-------------------------------------------------*/
+
+static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp, maskp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI);
+
+ /* set up a call to the read dword masked handler */
+ emit_push_p32(drcbe, &dst, &maskp); // push maskp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword_masked);
+ // call read_dword_masked
+ emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8
+
+ /* store low 32 bits */
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+
+ /* 64-bit form stores upper 32 bits */
+ if (inst->size == 8)
+ {
+ /* general case */
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read8u - process a READ8U opcode
+-------------------------------------------------*/
+
+static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read qword handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword);// call read_qword
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+
+ /* 64-bit form */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_read8m - process a READ8M opcode
+-------------------------------------------------*/
+
+static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp, maskp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI);
+
+ /* set up a call to the read qword masked handler */
+ emit_push_p64(drcbe, &dst, &maskp); // push maskp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword_masked);
+ // call read_qword_masked
+ emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12
+
+ /* 64-bit form */
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write1 - process a WRITE1 opcode
+-------------------------------------------------*/
+
+static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write byte handler */
+ emit_push_p32(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_byte);// call write_byte
+ emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write2 - process a WRITE2 opcode
+-------------------------------------------------*/
+
+static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_push_p32(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_word);// call write_word
+ emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_writ2m - process a WRIT2M opcode
+-------------------------------------------------*/
+
+static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, maskp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_push_p32(drcbe, &dst, &maskp); // push maskp
+ emit_push_p32(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_word_masked);
+ // call write_word_masked
+ emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write4 - process a WRITE4 opcode
+-------------------------------------------------*/
+
+static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write dword handler */
+ emit_push_p32(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword);// call write_dword
+ emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_writ4m - process a WRIT4M opcode
+-------------------------------------------------*/
+
+static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, maskp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_push_p32(drcbe, &dst, &maskp); // push maskp
+ emit_push_p32(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword_masked);
+ // call write_dword_masked
+ emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_write8 - process a WRITE8 opcode
+-------------------------------------------------*/
+
+static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write qword handler */
+ emit_push_p64(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword);// call write_qword
+
+ emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_writ8m - process a WRIT8M opcode
+-------------------------------------------------*/
+
+static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, maskp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI);
+
+ /* set up a call to the write word handler */
+ emit_push_p64(drcbe, &dst, &maskp); // push maskp
+ emit_push_p64(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword_masked);
+ // call write_qword_masked
+ emit_add_r32_imm(&dst, REG_ESP, 20); // add esp,20
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_flags - process a FLAGS opcode
+-------------------------------------------------*/
+
+static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, maskp, tablep;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &maskp, PTYPE_I, &tablep, PTYPE_M);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_ECX, &dstp, NULL);
+
+ /* translate live flags into UML flags */
+ emit_pushf(&dst); // pushf
+ emit_pop_r32(&dst, REG_EAX); // pop eax
+ emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5
+ emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_EAX, flags_map)); // movzx eax,[flags_map]
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* no masking */
+ if (maskp.value == 0xffffffff)
+ {
+ emit_mov_r32_m32(&dst, dstreg, MISD(REG_EAX, 4, tablep.value)); // mov dstreg,[eax*4+table]
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp
+ emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 4, tablep.value)); // mov edx,[eax*4+table]
+ emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask
+ emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask
+ emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* no masking */
+ if (maskp.value == U64(0xffffffffffffffff))
+ {
+ emit_mov_r32_m32(&dst, dstreg, MISD(REG_EAX, 8, tablep.value)); // mov dstreg,[eax*4+table]
+ emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 8, tablep.value + 4)); // mov edx,[eax*4+table+4]
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dst,edx:dstreg
+ }
+
+ /* general case */
+ else
+ {
+ if ((UINT32)maskp.value != 0)
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp
+ emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 8, tablep.value)); // mov edx,[eax*8+table]
+ emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask
+ emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask
+ emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg.lo
+ }
+ if ((UINT32)(maskp.value >> 32) != 0)
+ {
+ if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_r32_m32(&dst, REG_ECX, MABS(drcbe->reghi[dstp.value])); // mov ecx,dstp.hi
+ else
+ emit_mov_r32_m32(&dst, REG_ECX, MABS(dstp.value + 4)); // mov ecx,dstp.hi
+ emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EDX, 8, tablep.value+4)); // mov edx,[eax*8+table+4]
+ emit_and_r32_imm(&dst, REG_ECX, ~maskp.value); // and ecx,~mask
+ emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask
+ emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or ecx,edx
+ if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_ECX); // mov dstp.hi,ecx
+ else
+ emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_ECX); // mov dstp.hi,ecx
+ }
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_mov - process a MOV opcode
+-------------------------------------------------*/
+
+static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ x86code *savedst = dst;
+ emit_link skip = { 0 };
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters, but only if we got here directly */
+ /* other opcodes call through here with pre-normalized parameters */
+ if (inst->opcode == DRCUML_OP_MOV)
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+ else
+ {
+ dstp = inst->param[0];
+ srcp = inst->param[1];
+ }
+
+ /* degenerate case: dest and source are equal */
+ if (dstp.type == srcp.type && dstp.value == srcp.value)
+ return dst;
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* always start with a jmp */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* register to memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_r32(&dst, MABS(dstp.value), srcp.value); // mov [dstp],srcp
+
+ /* immediate to memory */
+ else if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_m32_imm(&dst, MABS(dstp.value), srcp.value); // mov [dstp],srcp
+
+ /* conditional memory to register */
+ else if (inst->condflags != 0 && dstp.type == DRCUML_PTYPE_INT_REGISTER && srcp.type == DRCUML_PTYPE_MEMORY)
+ {
+ dst = savedst;
+ skip.target = NULL;
+ emit_cmovcc_r32_m32(&dst, X86_CONDITION(inst->condflags), dstp.value, MABS(srcp.value));
+ // cmovcc dstp,[srcp]
+ }
+
+ /* conditional register to register */
+ else if (inst->condflags != 0 && dstp.type == DRCUML_PTYPE_INT_REGISTER && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ dst = savedst;
+ skip.target = NULL;
+ emit_cmovcc_r32_r32(&dst, X86_CONDITION(inst->condflags), dstp.value, srcp.value);
+ // cmovcc dstp,srcp
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &srcp); // mov dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* register to memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS(drcbe->reghi[srcp.value])); // mov eax,reghi[srcp]
+ emit_mov_m32_r32(&dst, MABS(dstp.value), srcp.value); // mov [dstp],srcp
+ emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EAX); // mov [dstp+4],eax
+ }
+
+ /* immediate to memory */
+ else if (dstp.type == DRCUML_PTYPE_MEMORY && srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_mov_m32_imm(&dst, MABS(dstp.value), srcp.value); // mov [dstp],srcp
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), srcp.value >> 32); // mov [dstp+4],srcp >> 32
+ }
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &srcp); // mov edx:dstreg,srcp
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg
+ }
+ }
+
+ /* resolve the jump */
+ if (skip.target != NULL)
+ resolve_link(&dst, &skip);
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_zext1 - process a ZEXT1 opcode
+-------------------------------------------------*/
+
+static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT8)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* convert 8-bit source registers */
+ if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4))
+ {
+ emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp
+ srcp.value = REG_EAX;
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movzx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movzx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_zext2 - process a ZEXT2 opcode
+-------------------------------------------------*/
+
+static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT16)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movzx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movzx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_zext4 - process a ZEXT4 opcode
+-------------------------------------------------*/
+
+static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 64-bit form */
+ if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &srcp); // mov dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sext1 - process a SEXT1 opcode
+-------------------------------------------------*/
+
+static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* convert 8-bit source registers */
+ if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4))
+ {
+ emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp
+ srcp.value = REG_EAX;
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r32_m8(&dst, REG_EAX, MABS(srcp.value)); // movsx eax,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r32_r8(&dst, REG_EAX, srcp.value); // movsx eax,srcp
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sext2 - process a SEXT2 opcode
+-------------------------------------------------*/
+
+static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_movsx_r32_m16(&dst, REG_EAX, MABS(srcp.value)); // movsx eax,[srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_movsx_r32_r16(&dst, REG_EAX, srcp.value); // movsx eax,srcp
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sext4 - process a SEXT4 opcode
+-------------------------------------------------*/
+
+static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value);
+
+ /* 64-bit form */
+ if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &srcp); // mov eax,srcp
+ emit_cdq(&dst); // cdq
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_add - process a ADD opcode
+-------------------------------------------------*/
+
+static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value + src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
+ emit_add_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // add [dstp],src2p
+
+ /* reg = reg + imm */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ emit_lea_r32_m32(&dst, dstp.value, MBD(src1p.value, src2p.value)); // lea dstp,[src1p+src2p]
+
+ /* reg = reg + reg */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_INT_REGISTER && inst->condflags == 0)
+ emit_lea_r32_m32(&dst, dstp.value, MBISD(src1p.value, src2p.value, 1, 0)); // lea dstp,[src1p+src2p]
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_add_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // add dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_add_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // add [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_add_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // add dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_addc - process a ADDC opcode
+-------------------------------------------------*/
+
+static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_adc_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // adc [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_adc_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // adc dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_adc_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // adc [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_adc_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // adc dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sub - process a SUB opcode
+-------------------------------------------------*/
+
+static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value - src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (dstp.type == DRCUML_PTYPE_MEMORY && src1p.type == DRCUML_PTYPE_MEMORY && src1p.value == dstp.value)
+ emit_sub_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // sub [dstp],src2p
+
+ /* reg = reg - imm */
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER && src1p.type == DRCUML_PTYPE_INT_REGISTER && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ emit_lea_r32_m32(&dst, dstp.value, MBD(src1p.value, -src2p.value)); // lea dstp,[src1p-src2p]
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sub_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // sub dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sub_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // sub [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_sub_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // sub dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_subc - process a SUBC opcode
+-------------------------------------------------*/
+
+static x86code *op_subc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // sbb [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sbb_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // sbb dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sbb_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // sbb [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_sbb_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // sbb dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_cmp - process a CMP opcode
+-------------------------------------------------*/
+
+static x86code *op_cmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter src1p, src2p;
+ emit_link skip;
+ int src1reg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && src1p.value == src2p.value)
+ {
+ emit_cmp_r32_r32(&dst, REG_EAX, REG_EAX); // cmp eax,eax
+ return dst;
+ }
+
+ /* pick a target register for the general case */
+ src1reg = param_select_register(REG_EAX, &src1p, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* memory versus anything */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_cmp_m32_p32(drcbe, &dst, MABS(src1p.value), &src2p, inst); // cmp [dstp],src2p
+
+ /* general case */
+ else
+ {
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_imm(&dst, src1reg, src1p.value); // mov src1reg,imm
+ emit_cmp_r32_p32(drcbe, &dst, src1reg, &src2p, inst); // cmp src1reg,src2p
+ }
+ }
+
+ /* 64-bit form */
+ else
+ {
+ /* memory versus anything */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ {
+ emit_cmp_m32_p32hi(drcbe, &dst, MABS(src1p.value + 4), &src2p, inst); // cmp [dstp],src2p.hi
+ emit_jcc_short_link(&dst, COND_NE, &skip); // jne skip
+ emit_cmp_m32_p32(drcbe, &dst, MABS(src1p.value), &src2p, inst); // cmp [dstp],src2p
+ resolve_link(&dst, &skip); // skip:
+ }
+
+ /* general case */
+ else
+ {
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_imm(&dst, REG_EAX, src1p.value >> 32); // mov eax,imm >> 32
+ else if (src1p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mov_r32_m32(&dst, REG_EAX, MABS(drcbe->reghi[src1p.value])); // mov eax,reghi[src1p]
+ emit_cmp_r32_p32hi(drcbe, &dst, REG_EAX, &src2p, inst); // cmp eax,src2p.hi
+ emit_jcc_short_link(&dst, COND_NE, &skip); // jne skip
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE)
+ emit_mov_r32_imm(&dst, src1reg, src1p.value); // mov src1reg,imm
+ emit_cmp_r32_p32(drcbe, &dst, src1reg, &src2p, inst); // cmp src1reg,src2p
+ resolve_link(&dst, &skip); // skip:
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_mulu - process a MULU opcode
+-------------------------------------------------*/
+
+static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_hi;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4_commutative(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_hi = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if (!compute_hi)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value * (UINT32)src2p.value);
+ else
+ {
+ UINT64 result = (UINT64)(UINT32)src1p.value * (UINT64)(UINT32)src2p.value;
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, result & 0xffffffff);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, result >> 32);
+ }
+ }
+ else if (inst->size == 8)
+ {
+ UINT64 reslo, reshi;
+ if (!compute_hi)
+ {
+ dmulu(&reslo, &reslo, src1p.value, src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ }
+ else
+ {
+ dmulu(&reslo, &reshi, src1p.value, src2p.value);
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reshi);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_mul_m32(&dst, MABS(src2p.value)); // mul [src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_mul_r32(&dst, src2p.value); // mul src2p
+ else if (src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r32_imm(&dst, REG_EDX, src2p.value); // mov edx,src2p
+ emit_mul_r32(&dst, REG_EDX); // mul edx
+ }
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ if (compute_hi)
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_push_p64(drcbe, &dst, &src2p); // push src2p
+ emit_push_p64(drcbe, &dst, &src1p); // push src1p
+ if (!compute_hi)
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ else
+ emit_push_imm(&dst, (FPTR)&drcbe->reshi); // push &reshi
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ emit_call(&dst, (x86code *)dmulu); // call dmulu
+ emit_add_r32_imm(&dst, REG_ESP, 24); // add esp,24
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ if (inst->condflags != 0)
+ emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx
+ if (compute_hi)
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_muls - process a MULS opcode
+-------------------------------------------------*/
+
+static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_hi;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4_commutative(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_hi = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if (!compute_hi)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value * (INT32)src2p.value);
+ else
+ {
+ UINT64 result = (INT64)(INT32)src1p.value * (INT64)(INT32)src2p.value;
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, result & 0xffffffff);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, result >> 32);
+ }
+ }
+ else if (inst->size == 8)
+ {
+ UINT64 reslo, reshi;
+ if (!compute_hi)
+ {
+ dmuls(&reslo, &reslo, src1p.value, src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ }
+ else
+ {
+ dmuls(&reslo, &reshi, src1p.value, src2p.value);
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reshi);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* 32-bit destination with memory/immediate or register/immediate */
+ if (!compute_hi && src1p.type != DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_r32_m32_imm(&dst, REG_EAX, MABS(src1p.value), src2p.value); // imul eax,[src1p],src2p
+ else if (src1p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r32_r32_imm(&dst, REG_EAX, src1p.value, src2p.value); // imul eax,src1p,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ }
+
+ /* 32-bit destination, general case */
+ else if (!compute_hi)
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_r32_m32(&dst, REG_EAX, MABS(src2p.value)); // imul eax,[src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r32_r32(&dst, REG_EAX, src2p.value); // imul eax,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ }
+
+ /* 64-bit destination, general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ if (src2p.type == DRCUML_PTYPE_MEMORY)
+ emit_imul_m32(&dst, MABS(src2p.value)); // imul [src2p]
+ else if (src2p.type == DRCUML_PTYPE_INT_REGISTER)
+ emit_imul_r32(&dst, src2p.value); // imul src2p
+ else if (src2p.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_r32_imm(&dst, REG_EDX, src2p.value); // mov edx,src2p
+ emit_imul_r32(&dst, REG_EDX); // imul edx
+ }
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_push_p64(drcbe, &dst, &src2p); // push src2p
+ emit_push_p64(drcbe, &dst, &src1p); // push src1p
+ if (!compute_hi)
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ else
+ emit_push_imm(&dst, (FPTR)&drcbe->reshi); // push &reshi
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ emit_call(&dst, (x86code *)dmuls); // call dmuls
+ emit_add_r32_imm(&dst, REG_ESP, 24); // add esp,24
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ if (inst->condflags != 0)
+ emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx
+ if (compute_hi)
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_divu - process a DIVU opcode
+-------------------------------------------------*/
+
+static x86code *op_divu(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_rem;
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_rem = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if ((UINT32)src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value / (UINT32)src2p.value);
+ else
+ {
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value / (UINT32)src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)src1p.value % (UINT32)src2p.value);
+ }
+ }
+ else if (inst->size == 8)
+ {
+ UINT64 reslo, reshi;
+ if (src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ {
+ ddivu(&reslo, &reslo, src1p.value, src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ }
+ else
+ {
+ ddivu(&reslo, &reshi, src1p.value, src2p.value);
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reshi);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_ECX, &src2p); // mov ecx,src2p
+ emit_jecxz_link(&dst, &skip); // jecxz skip
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ emit_xor_r32_r32(&dst, REG_EDX, REG_EDX); // xor edx,edx
+ emit_div_r32(&dst, REG_ECX); // div ecx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ if (compute_rem)
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ resolve_link(&dst, &skip); // skip:
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_push_p64(drcbe, &dst, &src2p); // push src2p
+ emit_push_p64(drcbe, &dst, &src1p); // push src1p
+ if (!compute_rem)
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ else
+ emit_push_imm(&dst, (FPTR)&drcbe->reshi); // push &reshi
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ emit_call(&dst, (x86code *)ddivu); // call ddivu
+ emit_add_r32_imm(&dst, REG_ESP, 24); // add esp,24
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ if (inst->condflags != 0)
+ emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx
+ if (compute_rem)
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_divs - process a DIVS opcode
+-------------------------------------------------*/
+
+static x86code *op_divs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, edstp, src1p, src2p;
+ int compute_rem;
+ emit_link skip;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &edstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+ compute_rem = (dstp.type != edstp.type || dstp.value != edstp.value);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ {
+ if ((INT32)src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value / (INT32)src2p.value);
+ else
+ {
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value / (INT32)src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value % (INT32)src2p.value);
+ }
+ }
+ else if (inst->size == 8)
+ {
+ UINT64 reslo, reshi;
+ if (src2p.value == 0)
+ return dst;
+ if (!compute_rem)
+ {
+ ddivs(&reslo, &reslo, src1p.value, src2p.value);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ }
+ else
+ {
+ ddivs(&reslo, &reshi, src1p.value, src2p.value);
+ dst = convert_to_mov_imm(drcbe, dst, inst, &dstp, reslo);
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, reshi);
+ }
+ }
+ }
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* general case */
+ emit_mov_r32_p32(drcbe, &dst, REG_ECX, &src2p); // mov ecx,src2p
+ emit_jecxz_link(&dst, &skip); // jecxz skip
+ emit_mov_r32_p32(drcbe, &dst, REG_EAX, &src1p); // mov eax,src1p
+ emit_cdq(&dst); // cdq
+ emit_idiv_r32(&dst, REG_ECX); // idiv ecx
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ if (compute_rem)
+ emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx
+ resolve_link(&dst, &skip); // skip:
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_push_p64(drcbe, &dst, &src2p); // push src2p
+ emit_push_p64(drcbe, &dst, &src1p); // push src1p
+ if (!compute_rem)
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ else
+ emit_push_imm(&dst, (FPTR)&drcbe->reshi); // push &reshi
+ emit_push_imm(&dst, (FPTR)&drcbe->reslo); // push &reslo
+ emit_call(&dst, (x86code *)ddivs); // call ddivs
+ emit_add_r32_imm(&dst, REG_ESP, 24); // add esp,24
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+ if (inst->condflags != 0)
+ emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx
+ if (compute_rem)
+ {
+ emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo
+ emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi
+ emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_and - process a AND opcode
+-------------------------------------------------*/
+
+static x86code *op_and(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value & src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && (src2p.value & size_to_mask[inst->size]) == size_to_mask[inst->size] && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_and_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // and [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_and_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // and dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_and_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // and [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_and_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // and dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_test - process a TEST opcode
+-------------------------------------------------*/
+
+static x86code *op_test(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter src1p, src2p;
+ int src1reg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_2_commutative(drcbe, inst, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* pick a target register for the general case */
+ src1reg = param_select_register(REG_EAX, &src1p, NULL);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* src1p in memory */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_test_m32_p32(drcbe, &dst, MABS(src1p.value), &src2p, inst); // test [src1p],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, src1reg, &src1p); // mov src1reg,src1p
+ emit_test_r32_p32(drcbe, &dst, src1reg, &src2p, inst); // test src1reg,src2p
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* src1p in memory */
+ if (src1p.type == DRCUML_PTYPE_MEMORY)
+ emit_test_m64_p64(drcbe, &dst, MABS(src1p.value), &src2p, inst); // test [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, src1reg, REG_EDX, &src1p); // mov src1reg:dstp,[src1p]
+ emit_test_r64_p64(drcbe, &dst, src1reg, REG_EDX, &src2p, inst); // test src1reg:dstp,src2p
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_or - process a OR opcode
+-------------------------------------------------*/
+
+static x86code *op_or(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value | src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_or_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // or [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_or_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // or dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_or_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // or [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_or_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // or dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_xor - process a XOR opcode
+-------------------------------------------------*/
+
+static x86code *op_xor(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3_commutative(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value & src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_xor_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // xor [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_xor_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // xor dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_xor_m64_p64(drcbe, &dst, MABS(dstp.value), &src2p, inst); // xor [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_xor_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // xor dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_shl - process a SHL opcode
+-------------------------------------------------*/
+
+static x86code *op_shl(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, src1p.value << src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_shl_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // shl [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_shl_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // shl dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_shl_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // shl dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_shr - process a SHR opcode
+-------------------------------------------------*/
+
+static x86code *op_shr(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_shr_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // shr [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_shr_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // shr dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_shr_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // shr dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_sar - process a SAR opcode
+-------------------------------------------------*/
+
+static x86code *op_sar(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ {
+ if (inst->size == 4)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)src1p.value >> src2p.value);
+ else if (inst->size == 8)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT64)src1p.value >> src2p.value);
+ }
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_sar_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // sar [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_sar_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // sar dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_sar_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // sar dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_rol - process a rol opcode
+-------------------------------------------------*/
+
+static x86code *op_rol(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rol_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // rol [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rol_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // rol dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_rol_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // rol dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ror - process a ROR opcode
+-------------------------------------------------*/
+
+static x86code *op_ror(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_ror_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // ror [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_ror_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // ror dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_ror_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // ror dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_rolc - process a ROLC opcode
+-------------------------------------------------*/
+
+static x86code *op_rolc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcl_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // rcl [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rcl_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // rcl dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_rcl_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // rcl dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_rorc - process a RORC opcode
+-------------------------------------------------*/
+
+static x86code *op_rorc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+ int dstreg;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &src1p, PTYPE_MRI, &src2p, PTYPE_MRI);
+
+ /* degenerate cases -- convert to a move */
+ if (src1p.type == DRCUML_PTYPE_IMMEDIATE && src2p.type == DRCUML_PTYPE_IMMEDIATE && inst->condflags == 0)
+ return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT64)src1p.value >> src2p.value);
+ if (src2p.type == DRCUML_PTYPE_IMMEDIATE && src2p.value == 0 && inst->condflags == 0)
+ return convert_to_mov_src1(drcbe, dst, inst, &dstp, &src1p);
+
+ /* pick a target register for the general case */
+ dstreg = param_select_register(REG_EAX, &dstp, &src2p);
+
+ /* 32-bit form */
+ if (inst->size == 4)
+ {
+ /* dstp == src1p in memory */
+ if (src1p.type == dstp.type && src1p.value == dstp.value && dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_rcr_m32_p32(drcbe, &dst, MABS(dstp.value), &src2p, inst); // rcr [dstp],src2p
+
+ /* general case */
+ else
+ {
+ emit_mov_r32_p32(drcbe, &dst, dstreg, &src1p); // mov dstreg,src1p
+ emit_rcr_r32_p32(drcbe, &dst, dstreg, &src2p, inst); // rcr dstreg,src2p
+ emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg
+ }
+ }
+
+ /* 64-bit form */
+ else if (inst->size == 8)
+ {
+ /* general case */
+ emit_mov_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src1p); // mov dstreg:dstp,[src1p]
+ emit_rcr_r64_p64(drcbe, &dst, dstreg, REG_EDX, &src2p, inst); // rcr dstreg:dstp,src2p
+ emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,dstreg:eax
+ }
+ return dst;
+}
+
+
+
+/***************************************************************************
+ FLOATING POINT OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ op_fload - process a FLOAD opcode
+-------------------------------------------------*/
+
+static x86code *op_fload(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, basep, indp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &basep, PTYPE_M, &indp, PTYPE_MRI);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->size == 4)
+ emit_fld_m32(&dst, MABS(basep.value + 4*indp.value)); // fld [basep + 4*indp]
+ else if (inst->size == 8)
+ emit_fld_m64(&dst, MABS(basep.value + 8*indp.value)); // fld [basep + 8*indp]
+ }
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ if (inst->size == 4)
+ emit_fld_m32(&dst, MISD(indreg, 4, basep.value)); // fld [basep + 4*indp]
+ else if (inst->size == 8)
+ emit_fld_m64(&dst, MISD(indreg, 8, basep.value)); // fld [basep + 8*indp]
+ }
+
+ /* general case */
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fstore - process a FSTORE opcode
+-------------------------------------------------*/
+
+static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter srcp, basep, indp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp);
+
+ /* immediate index */
+ if (indp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ if (inst->size == 4)
+ emit_fstp_m32(&dst, MABS(basep.value + 4*indp.value)); // fstp [basep + 4*indp]
+ else if (inst->size == 8)
+ emit_fstp_m64(&dst, MABS(basep.value + 8*indp.value)); // fstp [basep + 8*indp]
+ }
+
+ /* other index */
+ else
+ {
+ int indreg = param_select_register(REG_ECX, &indp, NULL);
+ emit_mov_r32_p32(drcbe, &dst, indreg, &indp);
+ if (inst->size == 4)
+ emit_fstp_m32(&dst, MISD(indreg, 4, basep.value)); // fstp [basep + 4*indp]
+ else if (inst->size == 8)
+ emit_fstp_m64(&dst, MISD(indreg, 8, basep.value)); // fstp [basep + 8*indp]
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fread - process a FREAD opcode
+-------------------------------------------------*/
+
+static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, spacep, addrp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &spacep, PTYPE_I, &addrp, PTYPE_MRI);
+
+ /* set up a call to the read dword/qword handler */
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ if (inst->size == 4)
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword
+ else if (inst->size == 8)
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword);// call read_qword
+ emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4
+
+ /* store result */
+ if (inst->size == 4)
+ emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax
+ else if (inst->size == 8)
+ emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fwrite - process a FWRITE opcode
+-------------------------------------------------*/
+
+static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter spacep, addrp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MF);
+
+ /* set up a call to the write dword/qword handler */
+ if (inst->size == 4)
+ emit_push_p32(drcbe, &dst, &srcp); // push srcp
+ else if (inst->size == 8)
+ emit_push_p64(drcbe, &dst, &srcp); // push srcp
+ emit_push_p32(drcbe, &dst, &addrp); // push addrp
+ if (inst->size == 4)
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword);// call write_dword
+ else if (inst->size == 8)
+ emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword);// call write_qword
+ emit_add_r32_imm(&dst, REG_ESP, 4 + inst->size); // add esp,8
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fmov - process a FMOV opcode
+-------------------------------------------------*/
+
+static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+ emit_link skip = { 0 };
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS || (inst->condflags >= COND_Z && inst->condflags < DRCUML_COND_MAX));
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* always start with a jmp */
+ if (inst->condflags != DRCUML_COND_ALWAYS)
+ emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ /* resolve the jump */
+ if (skip.target != NULL)
+ resolve_link(&dst, &skip); // skip:
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4 - process a FTOI4 opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4t - process a FTOI4T opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fisttp_m32(&dst, MABS(dstp.value)); // fisttp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fisttp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4r - process a FTOI4R opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* save and set the control word */
+ emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave]
+ emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_ROUND])); // fldcw fpcontrol[DRCUML_FMOD_ROUND]
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+
+ /* restore control word and proceed */
+ emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4f - process a FTOI4F opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* save and set the control word */
+ emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave]
+ emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_FLOOR])); // fldcw fpcontrol[DRCUML_FMOD_FLOOR]
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+
+ /* restore control word and proceed */
+ emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi4c - process a FTOI4C opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* save and set the control word */
+ emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave]
+ emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_CEIL])); // fldcw fpcontrol[DRCUML_FMOD_CEIL]
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+
+ /* restore control word and proceed */
+ emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8 - process a FTOI8 opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8t - process a FTOI8T opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fisttp_m64(&dst, MABS(dstp.value)); // fisttp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fisttp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8r - process a FTOI8R opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* save and set the control word */
+ emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave]
+ emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_ROUND])); // fldcw fpcontrol[DRCUML_FMOD_ROUND]
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+
+ /* restore control word and proceed */
+ emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8f - process a FTOI8F opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* save and set the control word */
+ emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave]
+ emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_FLOOR])); // fldcw fpcontrol[DRCUML_FMOD_FLOOR]
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+
+ /* restore control word and proceed */
+ emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ftoi8c - process a FTOI8C opcode
+-------------------------------------------------*/
+
+static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF);
+
+ /* save and set the control word */
+ emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave]
+ emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_CEIL])); // fldcw fpcontrol[DRCUML_FMOD_CEIL]
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ if (dstp.type == DRCUML_PTYPE_MEMORY)
+ emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp]
+ else if (dstp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp]
+ emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp]
+ }
+
+ /* restore control word and proceed */
+ emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffrfs - process a FFRFS opcode
+-------------------------------------------------*/
+
+static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_m32(&dst, MABS(srcp.value)); // fld [srcp]
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffrfd - process a FFRFD opcode
+-------------------------------------------------*/
+
+static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_m64(&dst, MABS(srcp.value)); // fld [srcp]
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffri4 - process a FFRI4 opcode
+-------------------------------------------------*/
+
+static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp
+ emit_fild_m32(&dst, MABS(&drcbe->fptemp)); // fild [fptemp]
+ }
+ else if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_fild_m32(&dst, MABS(srcp.value)); // fild [srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp
+ emit_fild_m32(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp]
+ }
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_ffri8 - process a FFRI8 opcode
+-------------------------------------------------*/
+
+static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI);
+
+ /* general case */
+ if (srcp.type == DRCUML_PTYPE_IMMEDIATE)
+ {
+ emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp
+ emit_mov_m32_imm(&dst, MABS((UINT8 *)&drcbe->fptemp + 4), srcp.value); // mov [fptemp+4],srcp
+ emit_fild_m64(&dst, MABS(&drcbe->fptemp)); // fild [fptemp]
+ }
+ else if (srcp.type == DRCUML_PTYPE_MEMORY)
+ emit_fild_m64(&dst, MABS(srcp.value)); // fild [srcp]
+ else if (srcp.type == DRCUML_PTYPE_INT_REGISTER)
+ {
+ emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp
+ emit_fild_m64(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp]
+ }
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp]
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fadd - process a FADD opcode
+-------------------------------------------------*/
+
+static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &src1p); // fld src1p
+ emit_fld_p(&dst, inst->size, &src2p); // fld src2p
+ emit_faddp(&dst); // faddp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fsub - process a FSUB opcode
+-------------------------------------------------*/
+
+static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &src1p); // fld src1p
+ emit_fld_p(&dst, inst->size, &src2p); // fld src2p
+ emit_fsubp(&dst); // fsubp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fcmp - process a FCMP opcode
+-------------------------------------------------*/
+
+static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter src1p, src2p;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert((inst->condflags & ~(DRCUML_FLAG_C | DRCUML_FLAG_V | DRCUML_FLAG_Z | DRCUML_FLAG_S)) == 0);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &src2p); // fld src2p
+ emit_fld_p(&dst, inst->size, &src1p); // fld src1p
+ emit_fcompp(&dst); // fcompp
+ emit_fstsw_ax(&dst); // fnstsw ax
+ emit_sahf(&dst); // sahf
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fmul - process a FMUL opcode
+-------------------------------------------------*/
+
+static x86code *op_fmul(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &src1p); // fld src1p
+ emit_fld_p(&dst, inst->size, &src2p); // fld src2p
+ emit_fmulp(&dst); // fmulp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fdiv - process a FDIV opcode
+-------------------------------------------------*/
+
+static x86code *op_fdiv(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, src1p, src2p;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &src1p, PTYPE_MF, &src2p, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &src1p); // fld src1p
+ emit_fld_p(&dst, inst->size, &src2p); // fld src2p
+ emit_fdivp(&dst); // fdivp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fneg - process a FNEG opcode
+-------------------------------------------------*/
+
+static x86code *op_fneg(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ emit_fchs(&dst); // fchs
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fabs - process a FABS opcode
+-------------------------------------------------*/
+
+static x86code *op_fabs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ emit_fabs(&dst); // fabs
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_fsqrt - process a FSQRT opcode
+-------------------------------------------------*/
+
+static x86code *op_fsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ emit_fsqrt(&dst); // fsqrt
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_frecip - process a FRECIP opcode
+-------------------------------------------------*/
+
+static x86code *op_frecip(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld1(&dst); // fld1
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ emit_fdivp(&dst); // fdivp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ op_frsqrt - process a FRSQRT opcode
+-------------------------------------------------*/
+
+static x86code *op_frsqrt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst)
+{
+ drcuml_parameter dstp, srcp;
+
+ /* validate instruction */
+ assert(inst->size == 4 || inst->size == 8);
+ assert(inst->condflags == DRCUML_COND_ALWAYS);
+
+ /* normalize parameters */
+ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF);
+
+ /* general case */
+ emit_fld1(&dst); // fld1
+ emit_fld_p(&dst, inst->size, &srcp); // fld srcp
+ emit_fsqrt(&dst); // fsqrt
+ emit_fdivp(&dst); // fdivp
+ emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp
+
+ return dst;
+}
+
+
+
+/***************************************************************************
+ MISCELLAENOUS FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ dmulu - perform a double-wide unsigned multiply
+-------------------------------------------------*/
+
+static void dmulu(UINT64 *dstlo, UINT64 *dsthi, UINT64 src1, UINT64 src2)
+{
+ UINT64 lo, hi, prevlo;
+ UINT64 a, b, temp;
+
+ /* shortcut if we don't care about the high bits */
+ if (dstlo == dsthi)
+ {
+ *dstlo = src1 * src2;
+ return;
+ }
+
+ /* fetch source values */
+ a = src1;
+ b = src2;
+ if (a == 0 || b == 0)
+ {
+ *dsthi = *dstlo = 0;
+ return;
+ }
+
+ /* compute high and low parts first */
+ lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0);
+ hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32);
+
+ /* compute middle parts */
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ /* store the results */
+ *dsthi = hi;
+ *dstlo = lo;
+}
+
+
+/*-------------------------------------------------
+ dmuls - perform a double-wide signed multiply
+-------------------------------------------------*/
+
+static void dmuls(UINT64 *dstlo, UINT64 *dsthi, INT64 src1, INT64 src2)
+{
+ UINT64 lo, hi, prevlo;
+ UINT64 a, b, temp;
+
+ /* shortcut if we don't care about the high bits */
+ if (dstlo == dsthi)
+ {
+ *dstlo = src1 * src2;
+ return;
+ }
+
+ /* fetch absolute source values */
+ a = src1; if ((INT64)a < 0) a = -a;
+ b = src2; if ((INT64)b < 0) b = -b;
+ if (a == 0 || b == 0)
+ {
+ *dsthi = *dstlo = 0;
+ return;
+ }
+
+ /* compute high and low parts first */
+ lo = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 0);
+ hi = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 32);
+
+ /* compute middle parts */
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 32) * (UINT64)(UINT32)(b >> 0);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = (UINT64)(UINT32)(a >> 0) * (UINT64)(UINT32)(b >> 32);
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ /* adjust for signage */
+ if ((INT64)(src1 ^ src2) < 0)
+ {
+ hi = ~hi + (lo == 0);
+ lo = ~lo + 1;
+ }
+
+ /* store the results */
+ *dsthi = hi;
+ *dstlo = lo;
+}
+
+
+/*-------------------------------------------------
+ ddivu - perform a double-wide unsigned divide
+-------------------------------------------------*/
+
+static void ddivu(UINT64 *dstlo, UINT64 *dsthi, UINT64 src1, UINT64 src2)
+{
+ /* do nothing if src2 == 0 */
+ if (src2 == 0)
+ return;
+
+ /* shortcut if no remainder */
+ *dstlo = src1 / src2;
+ if (dstlo != dsthi)
+ *dsthi = src1 % src2;
+}
+
+
+/*-------------------------------------------------
+ ddivs - perform a double-wide signed divide
+-------------------------------------------------*/
+
+static void ddivs(UINT64 *dstlo, UINT64 *dsthi, INT64 src1, INT64 src2)
+{
+ /* do nothing if src2 == 0 */
+ if (src2 == 0)
+ return;
+
+ /* shortcut if no remainder */
+ *dstlo = src1 / src2;
+ if (dstlo != dsthi)
+ *dsthi = src1 % src2;
+}
diff --git a/src/emu/cpu/drccache.c b/src/emu/cpu/drccache.c
new file mode 100644
index 00000000000..83b00da4907
--- /dev/null
+++ b/src/emu/cpu/drccache.c
@@ -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;
+}
diff --git a/src/emu/cpu/drccache.h b/src/emu/cpu/drccache.h
new file mode 100644
index 00000000000..8fa7c82da1e
--- /dev/null
+++ b/src/emu/cpu/drccache.h
@@ -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
diff --git a/src/emu/cpu/drcfe.c b/src/emu/cpu/drcfe.c
index 05dbe43b5c4..d528a5d13f3 100644
--- a/src/emu/cpu/drcfe.c
+++ b/src/emu/cpu/drcfe.c
@@ -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 */
diff --git a/src/emu/cpu/drcfe.h b/src/emu/cpu/drcfe.h
index a2fefe04834..0041bfb2cc9 100644
--- a/src/emu/cpu/drcfe.h
+++ b/src/emu/cpu/drcfe.h
@@ -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
-*/
/***************************************************************************
diff --git a/src/emu/cpu/drcuml.c b/src/emu/cpu/drcuml.c
new file mode 100644
index 00000000000..ff89fc87aa8
--- /dev/null
+++ b/src/emu/cpu/drcuml.c
@@ -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
diff --git a/src/emu/cpu/drcuml.h b/src/emu/cpu/drcuml.h
new file mode 100644
index 00000000000..a4cfc570dab
--- /dev/null
+++ b/src/emu/cpu/drcuml.h
@@ -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
diff --git a/src/emu/cpu/drcumld.c b/src/emu/cpu/drcumld.c
new file mode 100644
index 00000000000..fb2d3b4ef49
--- /dev/null
+++ b/src/emu/cpu/drcumld.c
@@ -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, &param);
+ }
+}
+
+
+
+/***************************************************************************
+ 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);
+}
diff --git a/src/emu/cpu/drcumld.h b/src/emu/cpu/drcumld.h
new file mode 100644
index 00000000000..a8ef4fbac25
--- /dev/null
+++ b/src/emu/cpu/drcumld.h
@@ -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
diff --git a/src/emu/cpu/drcumlsh.h b/src/emu/cpu/drcumlsh.h
new file mode 100644
index 00000000000..b2ead90943c
--- /dev/null
+++ b/src/emu/cpu/drcumlsh.h
@@ -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
diff --git a/src/emu/cpu/mips/mdrc64.c b/src/emu/cpu/mips/mdrc64.c
deleted file mode 100644
index 52afd04f269..00000000000
--- a/src/emu/cpu/mips/mdrc64.c
+++ /dev/null
@@ -1,5730 +0,0 @@
-/***************************************************************************
-
- mdrc64.c
-
- x64 MIPS III recompiler.
-
- Copyright Aaron Giles
- Released for general use under the MAME license
- Visit http://mamedev.org for licensing and usage restrictions.
-
-****************************************************************************
-
- Conventions/rules:
-
- * Instructions are grouped into sequences by mips3fe; each
- sequence of instructions is guaranteed to not contain any
- branches to any instructions within the sequence apart from
- the first.
-
- * Because of the above rule, assumptions are made during the
- execution of a sequence in order to optimize the generated
- code.
-
- * Because some state may be live and not flushed to memory at
- the time an exception is generated, all exception-generating
- instructions must jump to stub code that is appended to each
- group of instructions which cleans up live registers before
- running the exception code.
-
- * Page faults are trickier because they are detected in a
- subroutine. In order to handle this, special markers are added
- to the code consisting of one qword EXCEPTION_ADDRESS_COOKIE
- followed by the return address of the call. When a page fault
- needs to be generated, the common code scans forward from
- the return address for this cookie/address pair and jumps to
- the code immediately following.
-
- * Convention: jumps to non-constant addresses have their target
- PC stored at [sp+SPOFFS_NEXTPC]
-
-****************************************************************************
-
- Future improvements:
- * problem:
- lui r3,$b000
- lw r3,$100(r3)
- if exception happens, then r3 is trashed
-
- * register allocator can use non-volatile registers if the
- lifetime is only for this one instruction (only for
- registers where (gpr.used & ~gpr.modified)
-
- * spec says if registers aren't sign-extended, then 32-bit ops have
- undefined results; this can simplify our code
-
- * track which results are 32-bit sign extended versus 64-bit and
- only promote when necessary
-
- * register aliasing - move from one to another either doesn't do
- anything and tracks both, or else shifts ownership to new
- target
-
- * generic drc:
- * common code to load registers prior to instruction
- - each register has a callback that generates the load
- * generate code
- * common code to write registers afterwards
- * common register allocation routines (64 integer, 64 FPU)
- * common OOB mechanism
- * common self-mod code detection (via write bitmask)
- * common code validation routines
-
-****************************************************************************
-
- Temporary stack usage:
- [esp+32].b = storage for CL in LWL/LWR/SWL/SWR
- [esp+36].l = storage for new target PC in JR/JALR
-
-***************************************************************************/
-
-#include "mips3fe.h"
-#include "deprecat.h"
-
-
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
-
-#define DISABLE_FIXED_RAM_LOAD (0)
-#define DISABLE_FIXED_RAM_STORE (0)
-#define FLUSH_AFTER_EACH_INSTRUCTION (0)
-#define PRINTF_EXCEPTIONS (0)
-#define PROBE_ADDRESS (0)
-#define LOG_HOTSPOTS (0)
-
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* extra "conditions" used to augment the basic conditions for OOB handlers */
-#define COND_NONE 16
-#define COND_NO_JUMP 17
-
-/* 64-bit cookie that is scanned for during exception processing */
-#define EXCEPTION_ADDRESS_COOKIE U64(0xcc90cc90cc90cc90)
-
-/* append_readwrite flags */
-#define ARW_READ 0x0000
-#define ARW_WRITE 0x0001
-#define ARW_UNSIGNED 0x0000
-#define ARW_SIGNED 0x0002
-#define ARW_MASKED 0x0004
-#define ARW_CACHED 0x0008
-#define ARW_UNCACHED 0x0010
-
-/* compiler_register_allocate flags */
-#define ALLOC_SRC 0x0001
-#define ALLOC_DST 0x0002
-#define ALLOC_DIRTY 0x0004
-
-/* x86 register tracking flags */
-#define X86REG_LIVE 0x80 /* register is live and contains something */
-#define X86REG_MIPSMASK 0x3f /* low 6 bits indicate which MIPS register we hold */
-
-/* MIPS register tracking flags */
-#define MIPSREG_CONSTANT 0x8000 /* register is constant; low 10 bits select which one */
-#define MIPSREG_DIRTY 0x4000 /* register has been modified and needs to be flushed */
-#define MIPSREG_LIVE 0x2000 /* register is live in an x86 register */
-#define MIPSREG_X86MASK 0x000f /* low 4 bits indicate which x86 register holds us */
-
-
-
-/***************************************************************************
- MACROS
-***************************************************************************/
-
-#define SPOFFS_SAVECL 32
-#define SPOFFS_NEXTPC 36
-
-#define REGADDR(reg) MDRC(&mips3.core->r[reg])
-#define HIADDR MDRC(&mips3.core->r[REG_HI])
-#define LOADDR MDRC(&mips3.core->r[REG_LO])
-#define CPR0ADDR(reg) MDRC(&mips3.core->cpr[0][reg])
-#define CCR0ADDR(reg) MDRC(&mips3.core->ccr[0][reg])
-#define CPR1ADDR(reg) MDRC(&mips3.core->cpr[1][reg])
-#define CCR1ADDR(reg) MDRC(&mips3.core->ccr[1][reg])
-#define CPR2ADDR(reg) MDRC(&mips3.core->cpr[2][reg])
-#define CCR2ADDR(reg) MDRC(&mips3.core->ccr[2][reg])
-#define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg])
-#define FPR32ADDR(reg) MDRC(FPR32(reg))
-#define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg])
-#define FPR64ADDR(reg) MDRC(FPR64(reg))
-#define CF1ADDR(which) MDRC(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)])
-#define PCADDR MDRC(&mips3.core->pc)
-#define ICOUNTADDR MDRC(&mips3.core->icount)
-#define COREADDR MDRC(mips3.core)
-
-/* macros for querying/accessing the tracking flags */
-#define ISCONST(x) (((x) & MIPSREG_CONSTANT) != 0)
-#define ISDIRTY(x) (((x) & MIPSREG_DIRTY) != 0)
-#define ISLIVE(x) (((x) & MIPSREG_LIVE) != 0)
-#define CONSTVAL(x) ((INT32)((x) >> 32))
-#define X86REG(x) ((x) & MIPSREG_X86MASK)
-
-/* macro for defining a small positivec constant inline */
-#define MAKE_CONST(x) (MIPSREG_CONSTANT | ((INT64)(x) << 32))
-#define MAKE_DESTREG(x) (MIPSREG_DIRTY | ((x) & MIPSREG_X86MASK))
-
-
-
-/***************************************************************************
- TYPEDEFS
-***************************************************************************/
-
-typedef struct _readwrite_handlers readwrite_handlers;
-struct _readwrite_handlers
-{
- x86code * read_byte_signed;
- x86code * read_byte_unsigned;
- x86code * read_half_signed;
- x86code * read_half_unsigned;
- x86code * read_word_signed;
- x86code * read_word_unsigned;
- x86code * read_word_masked;
- x86code * read_double;
- x86code * read_double_masked;
- x86code * write_byte;
- x86code * write_half;
- x86code * write_word;
- x86code * write_word_masked;
- x86code * write_double;
- x86code * write_double_masked;
-};
-
-
-typedef INT64 mipsreg_state;
-typedef UINT8 x86reg_state;
-
-
-typedef struct _compiler_state compiler_state;
-struct _compiler_state
-{
- UINT32 cycles; /* accumulated cycles */
- x86reg_state x86regs[REG_MAX]; /* tracking what is in the x86 registers */
- mipsreg_state mipsregs[35]; /* tracking what is in the MIPS registers */
-};
-
-
-typedef struct _oob_handler oob_handler;
-
-typedef void (*oob_callback_func)(drc_core *drc, oob_handler *oob, void *param);
-
-struct _oob_handler
-{
- oob_callback_func callback; /* pointer to callback function */
- void * param; /* callback parameter */
- const opcode_desc * desc; /* pointer to description of relevant instruction */
- emit_link link; /* link to source of the branch */
- compiler_state compiler; /* state of the compiler at this time */
-};
-
-
-struct _mips3drc_data
-{
- /* misc data */
- UINT64 abs64mask[2];
- UINT32 abs32mask[4];
-
- /* C functions */
- x86code * activecpu_gettotalcycles;
- x86code * mips3com_update_cycle_counting;
- x86code * mips3com_tlbr;
- x86code * mips3com_tlbwi;
- x86code * mips3com_tlbwr;
- x86code * mips3com_tlbp;
-
- /* internal functions */
- x86code * generate_interrupt_exception;
- x86code * generate_cop_exception;
- x86code * generate_overflow_exception;
- x86code * generate_invalidop_exception;
- x86code * generate_syscall_exception;
- x86code * generate_break_exception;
- x86code * generate_trap_exception;
- x86code * generate_tlbload_exception;
- x86code * generate_tlbstore_exception;
- x86code * handle_pc_tlb_mismatch;
- x86code * find_exception_handler;
- x86code * explode_ccr31;
- x86code * recover_ccr31;
-
- /* read/write handlers */
- readwrite_handlers general;
- readwrite_handlers cached;
- readwrite_handlers uncached;
-
- /* out of bounds handlers */
- oob_handler ooblist[COMPILE_MAX_INSTRUCTIONS*2];
- int oobcount;
-
- /* C functions */
- x86code * execute_c_version;
-
- /* hotspot tracking */
-#if LOG_HOTSPOTS
- struct
- {
- offs_t pc;
- UINT32 opcode;
- UINT64 count;
- } hotspot[100000];
- int next_hotspot;
-#endif
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static void drc_reset_callback(drc_core *drc);
-static void drc_recompile_callback(drc_core *drc);
-static void drc_entrygen_callback(drc_core *drc);
-
-static void compile_one(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-
-static void oob_exception_cleanup(drc_core *drc, oob_handler *oob, void *param);
-static void oob_interrupt_cleanup(drc_core *drc, oob_handler *oob, void *param);
-
-static void compiler_register_set_constant(compiler_state *compiler, UINT8 mipsreg, UINT64 constval);
-static mipsreg_state compiler_register_allocate(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT8 flags);
-static void compiler_register_flush(drc_core *drc, compiler_state *compiler, UINT8 mipsreg, int free);
-static void compiler_register_flush_all(drc_core *drc, compiler_state *compiler);
-
-static void probe_printf(void);
-
-static void generate_read_write_handlers(drc_core *drc, readwrite_handlers *handlers, const char *type, UINT8 flags);
-static void append_generate_exception(drc_core *drc, UINT8 exception);
-static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags, UINT32 ptroffs);
-static void append_handle_pc_tlb_mismatch(drc_core *drc);
-static void append_find_exception_handler(drc_core *drc);
-static void append_explode_ccr31(drc_core *drc);
-static void append_recover_ccr31(drc_core *drc);
-static void append_check_interrupts(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-//static void append_check_sw_interrupts(drc_core *drc, int inline_generate);
-
-static void emit_update_cycles_pc_and_flush(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, offs_t destpc);
-
-static int compile_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-static int compile_special(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-static int compile_regimm(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-static int compile_idt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-static int compile_cop0(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-static int compile_cop1(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-static int compile_cop1x(drc_core *drc, compiler_state *compiler, const opcode_desc *desc);
-
-static int compile_shift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable);
-static int compile_dshift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable, int shift_const_plus32);
-static int compile_movzn(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_movn);
-static int compile_trapcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int immediate);
-static int compile_branchcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition);
-static int compile_branchcz(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int link);
-static int compile_add(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate);
-static int compile_dadd(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate);
-static int compile_sub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions);
-static int compile_dsub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions);
-static int compile_mult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
-static int compile_dmult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
-static int compile_div(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
-static int compile_ddiv(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned);
-static int compile_logical(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int operation, int immediate);
-static int compile_slt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned, int immediate);
-static int compile_load(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, int is_unsigned);
-static int compile_load_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest);
-static int compile_loadx_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest);
-static int compile_load_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
-static int compile_load_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
-static int compile_store(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size);
-static int compile_store_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src);
-static int compile_storex_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src);
-static int compile_store_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
-static int compile_store_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right);
-
-
-
-/***************************************************************************
- PRIVATE GLOBAL VARIABLES
-***************************************************************************/
-
-static const UINT8 nvreg[] = { REG_NV0, REG_NV1, REG_NV2, REG_NV3, REG_NV4, REG_NV5, REG_NV6 };
-
-static const char *const x86regname[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
-
-
-
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- oob_request_callback - request an out-of-
- bounds callback for later
--------------------------------------------------*/
-
-INLINE void oob_request_callback(drc_core *drc, UINT8 condition, oob_callback_func callback, const compiler_state *compiler, const opcode_desc *desc, void *param)
-{
- oob_handler *oob = &mips3.drcdata->ooblist[mips3.drcdata->oobcount++];
-
- /* fill in the next handler */
- oob->callback = callback;
- oob->desc = desc;
- oob->compiler = *compiler;
- oob->param = param;
-
- /* emit an appropriate jump */
- if (condition == COND_NO_JUMP)
- {
- oob->link.size = 0;
- oob->link.target = drc->cache_top;
- }
- else if (condition == COND_NONE)
- emit_jmp_near_link(DRCTOP, &oob->link); // jmp <target>
- else
- emit_jcc_near_link(DRCTOP, condition, &oob->link); // jcc <target>
-}
-
-
-/*-------------------------------------------------
- compiler_state_reset - reset the compiler
- state
--------------------------------------------------*/
-
-INLINE void compiler_state_reset(compiler_state *compiler)
-{
- memset(compiler, 0, sizeof(*compiler));
- compiler_register_set_constant(compiler, 0, 0);
-}
-
-
-
-/***************************************************************************
- CORE RECOMPILER SYSTEMS
-***************************************************************************/
-
-/*-------------------------------------------------
- mips3drc_init - initialize the drc-specific
- state
--------------------------------------------------*/
-
-static void mips3drc_init(void)
-{
- drc_config drconfig;
-
- /* fill in the config */
- memset(&drconfig, 0, sizeof(drconfig));
- drconfig.cache_base = mips3.cache;
- drconfig.cache_size = CACHE_SIZE;
- drconfig.max_instructions = (512 + 128) / 4;
- drconfig.address_bits = 32;
- drconfig.lsbs_to_ignore = 2;
- drconfig.baseptr = &mips3.core->r[17];
- drconfig.pcptr = (UINT32 *)&mips3.core->pc;
- drconfig.cb_reset = drc_reset_callback;
- drconfig.cb_recompile = drc_recompile_callback;
- drconfig.cb_entrygen = drc_entrygen_callback;
-
- /* initialize the compiler */
- mips3.drc = drc_init(cpu_getactivecpu(), &drconfig);
- mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS;
-
- /* allocate our data out of the cache */
- mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata) + 16);
- mips3.drcdata = (mips3drc_data *)((((FPTR)mips3.drcdata + 15) >> 4) << 4);
- memset(mips3.drcdata, 0, sizeof(*mips3.drcdata));
-
- /* set up constants */
- mips3.drcdata->abs64mask[0] = U64(0x7fffffffffffffff);
- mips3.drcdata->abs32mask[0] = 0x7fffffff;
-
- /* get pointers to C functions */
- mips3.drcdata->activecpu_gettotalcycles = (x86code *)activecpu_gettotalcycles;
- mips3.drcdata->mips3com_update_cycle_counting = (x86code *)mips3com_update_cycle_counting;
- mips3.drcdata->mips3com_tlbr = (x86code *)mips3com_tlbr;
- mips3.drcdata->mips3com_tlbwi = (x86code *)mips3com_tlbwi;
- mips3.drcdata->mips3com_tlbwr = (x86code *)mips3com_tlbwr;
- mips3.drcdata->mips3com_tlbp = (x86code *)mips3com_tlbp;
-
-#if COMPARE_AGAINST_C
- mips3.drcdata->execute_c_version = (x86code *)execute_c_version;
-#endif
-}
-
-
-/*-------------------------------------------------
- mips3drc_exit - clean up the drc-specific
- state
--------------------------------------------------*/
-
-static void mips3drc_exit(void)
-{
- printf("Final code size = %d\n", (int)(mips3.drc->cache_top - mips3.drc->cache_base));
-#if LOG_HOTSPOTS
- /* print top hotspots */
- {
- int maxspot = 0;
- int hotnum;
- int count;
-
- for (count = 0; count < 10; count++)
- {
- for (hotnum = 1; hotnum < mips3.drcdata->next_hotspot; hotnum++)
- if (mips3.drcdata->hotspot[hotnum].count > mips3.drcdata->hotspot[maxspot].count)
- maxspot = hotnum;
- printf("%08X%08X hits: add_speedup(0x%08X, 0x%08X);\n",
- (UINT32)(mips3.drcdata->hotspot[maxspot].count >> 32),
- (UINT32)mips3.drcdata->hotspot[maxspot].count,
- mips3.drcdata->hotspot[maxspot].pc,
- mips3.drcdata->hotspot[maxspot].opcode);
- mips3.drcdata->hotspot[maxspot].count = 0;
- }
- }
-#endif
- drc_exit(mips3.drc);
-}
-
-
-
-/***************************************************************************
- RECOMPILER CALLBACKS
-***************************************************************************/
-
-/*------------------------------------------------------------------
- drc_reset_callback
-------------------------------------------------------------------*/
-
-static void drc_reset_callback(drc_core *drc)
-{
- if (LOG_CODE)
- {
- x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->exit_point);
- x86log_disasm_code_range(mips3.log, "exit_point:", drc->exit_point, drc->recompile);
- x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch);
- x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush);
- x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top);
- }
-
- mips3.drcdata->generate_interrupt_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_INTERRUPT);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top);
-
- mips3.drcdata->generate_cop_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_BADCOP);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top);
-
- mips3.drcdata->generate_overflow_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_OVERFLOW);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top);
-
- mips3.drcdata->generate_invalidop_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_INVALIDOP);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top);
-
- mips3.drcdata->generate_syscall_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_SYSCALL);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top);
-
- mips3.drcdata->generate_break_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_BREAK);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top);
-
- mips3.drcdata->generate_trap_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_TRAP);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top);
-
- mips3.drcdata->generate_tlbload_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_TLBLOAD);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top);
-
- mips3.drcdata->generate_tlbstore_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_TLBSTORE);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top);
-
- mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top;
- append_handle_pc_tlb_mismatch(drc);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top);
-
- mips3.drcdata->find_exception_handler = drc->cache_top;
- append_find_exception_handler(drc);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "find_exception_handler:", mips3.drcdata->find_exception_handler, drc->cache_top);
-
- mips3.drcdata->explode_ccr31 = drc->cache_top;
- append_explode_ccr31(drc);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "explode_ccr31:", mips3.drcdata->explode_ccr31, drc->cache_top);
-
- mips3.drcdata->recover_ccr31 = drc->cache_top;
- append_recover_ccr31(drc);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "recover_ccr31:", mips3.drcdata->recover_ccr31, drc->cache_top);
-
- generate_read_write_handlers(drc, &mips3.drcdata->general, "general", 0);
- generate_read_write_handlers(drc, &mips3.drcdata->cached, "cached", ARW_CACHED);
- generate_read_write_handlers(drc, &mips3.drcdata->uncached, "uncached", ARW_UNCACHED);
-}
-
-
-/*------------------------------------------------------------------
- drc_recompile_callback
-------------------------------------------------------------------*/
-
-static void drc_recompile_callback(drc_core *drc)
-{
- int compiled_last_sequence = FALSE;
- const opcode_desc *seqhead, *seqlast;
- const opcode_desc *desclist;
- void *start = drc->cache_top;
- int override = FALSE;
- int oobnum;
-
- (void)start;
-
- /* begin the sequence */
- drc_begin_sequence(drc, mips3.core->pc);
- mips3.drcdata->oobcount = 0;
-
- /* get a description of this sequence */
- desclist = drcfe_describe_code(mips3.drcfe, mips3.core->pc);
- if (LOG_CODE)
- log_opcode_desc(mips3.log, desclist, 0);
-
- /* loop until we get through all instruction sequences */
- for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
- {
- const opcode_desc *curdesc;
- compiler_state compiler;
-
- /* determine the last instruction in this sequence */
- for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
- if (seqlast->flags & OPFLAG_END_SEQUENCE)
- break;
- assert(seqlast != NULL);
-
- /* add this as an entry point */
- if (drc_add_entry_point(drc, seqhead->pc, override) && !override)
- {
- /* if this is the first sequence, it is a recompile request; allow overrides */
- if (seqhead == desclist)
- {
- override = TRUE;
- drc_add_entry_point(drc, seqhead->pc, override);
- }
-
- /* otherwise, just emit a jump to existing code */
- else
- {
- if (compiled_last_sequence)
- drc_append_fixed_dispatcher(drc, seqhead->pc, TRUE);
- compiled_last_sequence = FALSE;
- continue;
- }
- }
- compiled_last_sequence = TRUE;
-
- /* add a code log entry */
- if (LOG_CODE)
- x86log_add_comment(mips3.log, drc->cache_top, "-------------------------");
-
- /* validate this code block if we're not pointing into ROM */
- /* note that we assume P1 still contains the PC */
- if (memory_get_write_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, seqhead->physpc) != NULL)
- {
- if (LOG_CODE)
- x86log_add_comment(mips3.log, drc->cache_top, "[Validation for %08X]", seqhead->pc);
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)seqhead->opptr.v); // mov rax,seqhead->opptr
- for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
- {
- emit_cmp_m32_imm(DRCTOP, MBD(REG_RAX, curdesc->opptr.b - seqhead->opptr.b), *curdesc->opptr.l);
- // cmp [code],val
- emit_jcc(DRCTOP, COND_NE, mips3.drc->recompile); // jne recompile
- }
- }
-
- /* initialize the compiler state */
- compiler_state_reset(&compiler);
-
-#if LOG_HOTSPOTS
- /* add hotspot tracking */
- {
- int hotnum;
-
- drc_register_code_at_cache_top(drc, seqhead->pc);
-
- for (hotnum = 0; hotnum < mips3.drcdata->next_hotspot; hotnum++)
- if (mips3.drcdata->hotspot[hotnum].pc == seqhead->pc && mips3.drcdata->hotspot[hotnum].opcode == *seqhead->opptr.l)
- break;
- if (hotnum == mips3.drcdata->next_hotspot)
- {
- assert(hotnum < ARRAY_LENGTH(mips3.drcdata->hotspot));
- mips3.drcdata->hotspot[hotnum].pc = seqhead->pc;
- mips3.drcdata->hotspot[hotnum].opcode = *seqhead->opptr.l;
- mips3.drcdata->hotspot[hotnum].count = 0;
- mips3.drcdata->next_hotspot++;
- }
- emit_add_m64_imm(DRCTOP, MDRC(&mips3.drcdata->hotspot[hotnum].count), 1);
- }
-#endif
-
- /* iterate over instructions in the sequence and compile them */
- for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
- compile_one(drc, &compiler, curdesc);
-
- /* at the end of the sequence; update the PC in memory and check cycle counts */
- if (!(seqlast->flags & (OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_WILL_CAUSE_EXCEPTION)))
- {
- UINT32 nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
- emit_update_cycles_pc_and_flush(drc, &compiler, NULL, nextpc);
- }
-
- /* if this is a likely branch, the fall through case needs to skip the next instruction */
- if ((seqlast->flags & OPFLAG_IS_CONDITIONAL_BRANCH) && seqlast->skipslots > 0)
- if (seqlast->next != NULL && seqlast->next->pc != seqlast->pc + 8)
- {
- compiler_register_flush_all(drc, &compiler);
- drc_append_tentative_fixed_dispatcher(drc, seqlast->pc + 8, TRUE); // jmp <pc+8>
- }
-
- /* if we need a redispatch, do it now */
- if (seqlast->flags & OPFLAG_REDISPATCH)
- {
- UINT32 nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
- compiler_register_flush_all(drc, &compiler);
- drc_append_tentative_fixed_dispatcher(drc, nextpc, TRUE); // jmp <nextpc>
- }
-
- /* if we need to return to the start, do it */
- if (seqlast->flags & OPFLAG_RETURN_TO_START)
- {
- compiler_register_flush_all(drc, &compiler);
- drc_append_tentative_fixed_dispatcher(drc, mips3.core->pc, FALSE); // jmp <startpc>
- }
- }
-
- /* end the sequence */
- drc_end_sequence(drc);
-
- /* run the out-of-bounds handlers */
- for (oobnum = 0; oobnum < mips3.drcdata->oobcount; oobnum++)
- {
- oob_handler *oob = &mips3.drcdata->ooblist[oobnum];
- (*oob->callback)(drc, oob, oob->param);
- }
-
- /* log the generated code */
- if (LOG_CODE)
- {
- char label[60];
- sprintf(label, "Code @ %08X (%08X physical)", desclist->pc, desclist->physpc);
- x86log_disasm_code_range(mips3.log, label, start, drc->cache_top);
- }
-}
-
-
-/*------------------------------------------------------------------
- drc_entrygen_callback
-------------------------------------------------------------------*/
-
-static void drc_entrygen_callback(drc_core *drc)
-{
- append_check_interrupts(drc, NULL, NULL);
-}
-
-
-
-/***************************************************************************
- RECOMPILER CORE
-***************************************************************************/
-
-/*------------------------------------------------------------------
- compile_one
-------------------------------------------------------------------*/
-
-static void compile_one(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- int hotnum;
-
- /* register this instruction */
- if (!(desc->flags & OPFLAG_IN_DELAY_SLOT))
- drc_register_code_at_cache_top(drc, desc->pc);
-
- /* add an entry for the log */
- if (LOG_CODE)
- log_add_disasm_comment(mips3.log, drc->cache_top, desc->pc, *desc->opptr.l);
-
- /* if we want a probe, add it here */
- if (desc->pc == PROBE_ADDRESS)
- {
- emit_mov_m32_imm(DRCTOP, PCADDR, desc->pc); // mov [pc],desc->pc
- compiler_register_flush_all(drc, compiler);
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)probe_printf);
- emit_call_r64(DRCTOP, REG_RAX);
- }
-
- /* if we are debugging, call the debugger */
- if (Machine->debug_mode || COMPARE_AGAINST_C)
- {
- emit_mov_m32_imm(DRCTOP, PCADDR, desc->pc); // mov [pc],desc->pc
- if (COMPARE_AGAINST_C && !(desc->flags & OPFLAG_IN_DELAY_SLOT))
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->execute_c_version));
- if (Machine->debug_mode)
- drc_append_call_debugger(drc); // <call debugger>
- }
-
- /* validate our TLB entry at this PC; if we fail, we need to recompile */
- if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
- {
- emit_cmp_m32_imm(DRCTOP, MDRC(&mips3.core->tlb_table[desc->pc >> 12]), mips3.core->tlb_table[desc->pc >> 12]);
- // cmp tlb_table[pc>>12],<original value>
- oob_request_callback(drc, COND_NE, oob_exception_cleanup, compiler, desc, mips3.drcdata->handle_pc_tlb_mismatch);
- // jne handle_pc_tlb_mismatch
- }
-
- /* accumulate total cycles */
- compiler->cycles += desc->cycles;
-
- /* is this a hotspot? */
- for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
- if (desc->pc == mips3.hotspot[hotnum].pc && *desc->opptr.l == mips3.hotspot[hotnum].opcode)
- {
- compiler->cycles += mips3.hotspot[hotnum].cycles;
- break;
- }
-
- /* if this is an invalid opcode, generate the exception now */
- if (desc->flags & OPFLAG_INVALID_OPCODE)
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_invalidop_exception);
-
- /* otherwise, it's a regular instruction */
- else
- {
- /* compile the instruction */
- if (!compile_instruction(drc, compiler, desc))
- fatalerror("Unimplemented op %08X (%02X,%02X)", *desc->opptr.l, *desc->opptr.l >> 26, *desc->opptr.l & 0x3f);
-
- /* flush */
- if (FLUSH_AFTER_EACH_INSTRUCTION)
- compiler_register_flush_all(drc, compiler);
- }
-}
-
-
-
-/***************************************************************************
- OUT-OF-BOUNDS CODEGEN
-***************************************************************************/
-
-/*-------------------------------------------------
- oob_exception_cleanup - out-of-bounds code
- generator for cleaning up and generating an
- exception with the EPC pointing to the
- current instruction
--------------------------------------------------*/
-
-static void oob_exception_cleanup(drc_core *drc, oob_handler *oob, void *param)
-{
- /* if this is non-jumping error, emit a unique signature */
- if (oob->link.size == 0)
- {
- /* align to an 8-byte boundary */
- while (((UINT64)drc->cache_top & 7) != 0)
- emit_int_3(DRCTOP);
-
- /* logging */
- if (LOG_CODE)
- {
- x86log_add_comment(mips3.log, drc->cache_top, "[Exception path for %08X]", oob->desc->pc);
- x86log_mark_as_data(mips3.log, drc->cache_top, drc->cache_top + 15, 8);
- }
-
- /* output a pair of qwords */
- emit_qword(DRCTOP, EXCEPTION_ADDRESS_COOKIE);
- emit_qword(DRCTOP, (UINT64)oob->link.target);
- }
-
- /* otherwise, just resolve the link */
- else
- {
- resolve_link(DRCTOP, &oob->link);
- if (LOG_CODE)
- x86log_add_comment(mips3.log, drc->cache_top, "[Exception path for %08X]", oob->desc->pc);
- }
-
- /* adjust for cycles */
- if (oob->compiler.cycles != 0)
- emit_sub_m32_imm(DRCTOP, ICOUNTADDR, oob->compiler.cycles); // sub [icount],cycles
-
- /* update the PC with the instruction PC */
- if (!(oob->desc->flags & OPFLAG_IN_DELAY_SLOT))
- emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc); // mov p1,pc
- else
- emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc | 1); // mov p1,pc | 1
-
- /* flush any dirty registers */
- compiler_register_flush_all(drc, &oob->compiler); // <flush registers>
-
- /* jump to the exception generator */
- emit_jmp(DRCTOP, param); // jmp <generate exception>
-}
-
-
-/*-------------------------------------------------
- oob_interrupt_cleanup - out-of-bounds code
- generator for cleaning up and generating an
- interrupt with the EPC pointing to the
- following instruction
--------------------------------------------------*/
-
-static void oob_interrupt_cleanup(drc_core *drc, oob_handler *oob, void *param)
-{
- /* resolve the link */
- resolve_link(DRCTOP, &oob->link);
-
- /* add a code log entry */
- if (LOG_CODE)
- x86log_add_comment(mips3.log, drc->cache_top, "[Interrupt path for %08X]", oob->desc->pc);
-
- /* adjust for cycles */
- if (oob->compiler.cycles != 0)
- emit_sub_m32_imm(DRCTOP, ICOUNTADDR, oob->compiler.cycles); // sub [icount],cycles
-
- /* update the PC with the following instruction PC */
- if (!(oob->desc->flags & OPFLAG_IN_DELAY_SLOT))
- {
- assert(!(oob->desc->flags & OPFLAG_IS_BRANCH));
- emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->pc + 4); // mov p1,pc + 4
- }
- else
- {
- assert(oob->desc->branch != NULL);
- if (oob->desc->branch->targetpc != BRANCH_TARGET_DYNAMIC)
- emit_mov_r32_imm(DRCTOP, REG_P1, oob->desc->branch->targetpc); // mov p1,<targetpc>
- else
- emit_mov_r32_m32(DRCTOP, REG_P1, MBD(REG_RSP, SPOFFS_NEXTPC)); // mov p1,[rsp + nextpc]
- }
-
- /* flush any dirty registers */
- compiler_register_flush_all(drc, &oob->compiler); // <flush registers>
-
- /* jump to the exception generator */
- emit_jmp(DRCTOP, param); // jmp <generate exception>
-}
-
-
-
-/***************************************************************************
- REGISTER ALLOCATION ROUTINES
-***************************************************************************/
-
-/*-------------------------------------------------
- compiler_register_set_constant - set a MIPS
- register to a constant value
--------------------------------------------------*/
-
-static void compiler_register_set_constant(compiler_state *compiler, UINT8 mipsreg, UINT64 constval)
-{
- mipsreg_state reg = compiler->mipsregs[mipsreg];
-
- assert((INT32)constval == (INT64)constval);
-
- /* if the register was previously live, free it */
- if (ISLIVE(reg))
- {
- assert(compiler->x86regs[X86REG(reg)] & X86REG_LIVE);
- compiler->x86regs[X86REG(reg)] = 0;
- }
-
- /* set up the constant */
- compiler->mipsregs[mipsreg] = MAKE_CONST(constval) | ((mipsreg == 0) ? 0 : MIPSREG_DIRTY);
-}
-
-
-/*-------------------------------------------------
- compiler_register_allocate - allocate an x86
- register to hold a MIPS register
--------------------------------------------------*/
-
-static mipsreg_state compiler_register_allocate(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT8 flags)
-{
- UINT8 regindex, regnum = 0;
- UINT64 livemask = 0;
-
- /* register 0 is always constant */
- if (mipsreg == 0)
- return MAKE_CONST(0);
-
- /* first see if we are already allocated */
- if (ISLIVE(compiler->mipsregs[mipsreg]))
- {
- /* if we're not a source, make sure we are marked dirty */
- if (flags & ALLOC_DIRTY)
- compiler->mipsregs[mipsreg] |= MIPSREG_DIRTY;
- return compiler->mipsregs[mipsreg];
- }
-
- /* if we just want a source register, return a constant directly */
- if (flags == ALLOC_SRC && ISCONST(compiler->mipsregs[mipsreg]))
- return compiler->mipsregs[mipsreg];
-
- /* first look for a free entry */
- for (regindex = 0; regindex < NUM_NVREG; regindex++)
- {
- regnum = nvreg[regindex];
- if (!(compiler->x86regs[regnum] & X86REG_LIVE))
- goto allocateit;
- else
- livemask |= (UINT64)1 << (compiler->x86regs[regnum] & X86REG_MIPSMASK);
- }
-
- /* can't have anything we need for this instruction, however */
- livemask &= ~desc->gpr.used & ~desc->gpr.modified;
- desc = desc->next;
-
- /* next loop over the registers, figuring out who has the longest until being used */
- while (desc != NULL && livemask != 0)
- {
- /* if this instruction uses the last remaining register, we have to pick from among those */
- if ((livemask & ~desc->gpr.used) == 0)
- break;
- livemask &= ~desc->gpr.used;
-
- /* if this instruction modifies any of the registers, we want those */
- if ((livemask & desc->gpr.modified) != 0)
- {
- livemask &= desc->gpr.modified;
- break;
- }
-
- /* advance to the next instruction; stop if we hit end-of-sequence */
- if (desc->flags & OPFLAG_END_SEQUENCE)
- break;
- desc = desc->next;
- }
-
- /* pick the first one */
- for (regindex = 0; regindex < NUM_NVREG; regindex++)
- {
- regnum = nvreg[regindex];
- if (livemask & ((UINT64)1 << (compiler->x86regs[regnum] & X86REG_MIPSMASK)))
- break;
- }
- assert(regindex != NUM_NVREG);
-
- /* flush it */
- compiler_register_flush(drc, compiler, compiler->x86regs[regnum] & X86REG_MIPSMASK, TRUE);
-
-allocateit:
- /* load the contents if we are a source */
- if (LOG_CODE)
- x86log_add_comment(mips3.log, drc->cache_top, "allocate r%d (%s)", mipsreg, x86regname[regnum]);
- if (flags & ALLOC_SRC)
- {
- mipsreg_state state = compiler->mipsregs[mipsreg];
- if (ISCONST(state))
- emit_mov_r64_imm(DRCTOP, regnum, CONSTVAL(state)); // mov <x86reg>,constant
- else
- emit_mov_r64_m64(DRCTOP, regnum, REGADDR(mipsreg)); // mov <x86reg>,[reg]
- }
-
- /* mark it allocated */
- assert(!(compiler->x86regs[regnum] & X86REG_LIVE));
- compiler->x86regs[regnum] = X86REG_LIVE | mipsreg;
- compiler->mipsregs[mipsreg] = MIPSREG_LIVE | regnum | ((flags & ALLOC_DIRTY) ? MIPSREG_DIRTY : 0);
- return compiler->mipsregs[mipsreg];
-}
-
-
-/*-------------------------------------------------
- compiler_register_flush - flush and optionally
- free a single MIPS register
--------------------------------------------------*/
-
-static void compiler_register_flush(drc_core *drc, compiler_state *compiler, UINT8 mipsreg, int free)
-{
- mipsreg_state reg = compiler->mipsregs[mipsreg];
-
- assert(ISCONST(reg) || ISLIVE(reg));
-
- /* flush the value if dirty */
- if (ISDIRTY(reg))
- {
- if (LOG_CODE)
- x86log_add_comment(mips3.log, drc->cache_top, "flush r%d (%s)", mipsreg, ISCONST(reg) ? "constant" : x86regname[X86REG(reg)]);
-
- /* flush a constant value */
- if (ISCONST(reg))
- emit_mov_m64_imm(DRCTOP, REGADDR(mipsreg), CONSTVAL(reg)); // mov [reg],constant
-
- /* flush a live value */
- else if (ISLIVE(reg))
- emit_mov_m64_r64(DRCTOP, REGADDR(mipsreg), X86REG(reg)); // mov [reg],<x86reg>
- }
-
- /* clear the dirty flag */
- if (!free)
- compiler->mipsregs[mipsreg] &= ~MIPSREG_DIRTY;
- else
- {
- if (ISLIVE(reg))
- compiler->x86regs[X86REG(reg)] = 0;
- compiler->mipsregs[mipsreg] = 0;
- }
-}
-
-
-/*-------------------------------------------------
- compiler_register_flush_all - flush all dirty
- registers
--------------------------------------------------*/
-
-static void compiler_register_flush_all(drc_core *drc, compiler_state *compiler)
-{
- int mipsreg;
-
- /* flush all dirty registers */
- for (mipsreg = 1; mipsreg < 35; mipsreg++)
- if (ISDIRTY(compiler->mipsregs[mipsreg]))
- compiler_register_flush(drc, compiler, mipsreg, FALSE);
-}
-
-
-
-/***************************************************************************
- COMPILER CALLBACKS
-***************************************************************************/
-
-/*-------------------------------------------------
- probe_printf - print the current CPU state
- and return
--------------------------------------------------*/
-
-static void probe_printf(void)
-{
- printf(" PC=%08X r1=%08X%08X r2=%08X%08X r3=%08X%08X\n",
- mips3.core->pc,
- (UINT32)(mips3.core->r[1] >> 32), (UINT32)mips3.core->r[1],
- (UINT32)(mips3.core->r[2] >> 32), (UINT32)mips3.core->r[2],
- (UINT32)(mips3.core->r[3] >> 32), (UINT32)mips3.core->r[3]);
- printf(" r4=%08X%08X r5=%08X%08X r6=%08X%08X r7=%08X%08X\n",
- (UINT32)(mips3.core->r[4] >> 32), (UINT32)mips3.core->r[4],
- (UINT32)(mips3.core->r[5] >> 32), (UINT32)mips3.core->r[5],
- (UINT32)(mips3.core->r[6] >> 32), (UINT32)mips3.core->r[6],
- (UINT32)(mips3.core->r[7] >> 32), (UINT32)mips3.core->r[7]);
- printf(" r8=%08X%08X r9=%08X%08X r10=%08X%08X r11=%08X%08X\n",
- (UINT32)(mips3.core->r[8] >> 32), (UINT32)mips3.core->r[8],
- (UINT32)(mips3.core->r[9] >> 32), (UINT32)mips3.core->r[9],
- (UINT32)(mips3.core->r[10] >> 32), (UINT32)mips3.core->r[10],
- (UINT32)(mips3.core->r[11] >> 32), (UINT32)mips3.core->r[11]);
- printf("r12=%08X%08X r13=%08X%08X r14=%08X%08X r15=%08X%08X\n",
- (UINT32)(mips3.core->r[12] >> 32), (UINT32)mips3.core->r[12],
- (UINT32)(mips3.core->r[13] >> 32), (UINT32)mips3.core->r[13],
- (UINT32)(mips3.core->r[14] >> 32), (UINT32)mips3.core->r[14],
- (UINT32)(mips3.core->r[15] >> 32), (UINT32)mips3.core->r[15]);
- printf("r16=%08X%08X r17=%08X%08X r18=%08X%08X r19=%08X%08X\n",
- (UINT32)(mips3.core->r[16] >> 32), (UINT32)mips3.core->r[16],
- (UINT32)(mips3.core->r[17] >> 32), (UINT32)mips3.core->r[17],
- (UINT32)(mips3.core->r[18] >> 32), (UINT32)mips3.core->r[18],
- (UINT32)(mips3.core->r[19] >> 32), (UINT32)mips3.core->r[19]);
- printf("r20=%08X%08X r21=%08X%08X r22=%08X%08X r23=%08X%08X\n",
- (UINT32)(mips3.core->r[20] >> 32), (UINT32)mips3.core->r[20],
- (UINT32)(mips3.core->r[21] >> 32), (UINT32)mips3.core->r[21],
- (UINT32)(mips3.core->r[22] >> 32), (UINT32)mips3.core->r[22],
- (UINT32)(mips3.core->r[23] >> 32), (UINT32)mips3.core->r[23]);
- printf("r24=%08X%08X r25=%08X%08X r26=%08X%08X r27=%08X%08X\n",
- (UINT32)(mips3.core->r[24] >> 32), (UINT32)mips3.core->r[24],
- (UINT32)(mips3.core->r[25] >> 32), (UINT32)mips3.core->r[25],
- (UINT32)(mips3.core->r[26] >> 32), (UINT32)mips3.core->r[26],
- (UINT32)(mips3.core->r[27] >> 32), (UINT32)mips3.core->r[27]);
- printf("r28=%08X%08X r29=%08X%08X r30=%08X%08X r31=%08X%08X\n",
- (UINT32)(mips3.core->r[28] >> 32), (UINT32)mips3.core->r[28],
- (UINT32)(mips3.core->r[29] >> 32), (UINT32)mips3.core->r[29],
- (UINT32)(mips3.core->r[30] >> 32), (UINT32)mips3.core->r[30],
- (UINT32)(mips3.core->r[31] >> 32), (UINT32)mips3.core->r[31]);
- printf(" hi=%08X%08X lo=%08X%08X\n",
- (UINT32)(mips3.core->r[REG_HI] >> 32), (UINT32)mips3.core->r[REG_HI],
- (UINT32)(mips3.core->r[REG_LO] >> 32), (UINT32)mips3.core->r[REG_LO]);
-}
-
-
-/*-------------------------------------------------
- exception_trap - log any exceptions that
- aren't interrupts
--------------------------------------------------*/
-
-static void exception_trap(void)
-{
- if ((mips3.core->cpr[0][COP0_Cause] & 0xff) != 0)
- printf("Exception: EPC=%08X Cause=%08X BadVAddr=%08X Jmp=%08X\n", (UINT32)mips3.core->cpr[0][COP0_EPC], (UINT32)mips3.core->cpr[0][COP0_Cause], (UINT32)mips3.core->cpr[0][COP0_BadVAddr], mips3.core->pc);
-}
-
-
-
-/***************************************************************************
- COMMON ROUTINES
-***************************************************************************/
-
-/*------------------------------------------------------------------
- generate_read_write_handlers
-------------------------------------------------------------------*/
-
-static void generate_read_write_handlers(drc_core *drc, readwrite_handlers *handlers, const char *type, UINT8 flags)
-{
- char buffer[100];
-
- handlers->read_byte_signed = drc->cache_top;
- append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_byte_signed));
- sprintf(buffer, "%s.read_byte_signed:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_byte_signed, drc->cache_top);
-
- handlers->read_byte_unsigned = drc->cache_top;
- append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_byte_unsigned));
- sprintf(buffer, "%s.read_byte_unsigned:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_byte_unsigned, drc->cache_top);
-
- handlers->read_half_signed = drc->cache_top;
- append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_half_signed));
- sprintf(buffer, "%s.read_half_signed:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_half_signed, drc->cache_top);
-
- handlers->read_half_unsigned = drc->cache_top;
- append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_half_unsigned));
- sprintf(buffer, "%s.read_half_unsigned:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_half_unsigned, drc->cache_top);
-
- handlers->read_word_signed = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_READ | ARW_SIGNED | flags, offsetof(readwrite_handlers, read_word_signed));
- sprintf(buffer, "%s.read_word_signed:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_signed, drc->cache_top);
-
- handlers->read_word_unsigned = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_READ | ARW_UNSIGNED | flags, offsetof(readwrite_handlers, read_word_unsigned));
- sprintf(buffer, "%s.read_word_unsigned:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_unsigned, drc->cache_top);
-
- handlers->read_word_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_READ | ARW_UNSIGNED | ARW_MASKED | flags, offsetof(readwrite_handlers, read_word_masked));
- sprintf(buffer, "%s.read_word_masked:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_word_masked, drc->cache_top);
-
- handlers->read_double = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_READ | flags, offsetof(readwrite_handlers, read_double));
- sprintf(buffer, "%s.read_double:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_double, drc->cache_top);
-
- handlers->read_double_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED | flags, offsetof(readwrite_handlers, read_double_masked));
- sprintf(buffer, "%s.read_double_masked:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->read_double_masked, drc->cache_top);
-
- handlers->write_byte = drc->cache_top;
- append_readwrite_and_translate(drc, 1, ARW_WRITE | flags, offsetof(readwrite_handlers, write_byte));
- sprintf(buffer, "%s.write_byte:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->write_byte, drc->cache_top);
-
- handlers->write_half = drc->cache_top;
- append_readwrite_and_translate(drc, 2, ARW_WRITE | flags, offsetof(readwrite_handlers, write_half));
- sprintf(buffer, "%s.write_half:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->write_half, drc->cache_top);
-
- handlers->write_word = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_WRITE | flags, offsetof(readwrite_handlers, write_word));
- sprintf(buffer, "%s.write_word:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->write_word, drc->cache_top);
-
- handlers->write_word_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED | flags, offsetof(readwrite_handlers, write_word_masked));
- sprintf(buffer, "%s.write_word_masked:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->write_word_masked, drc->cache_top);
-
- handlers->write_double = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_WRITE | flags, offsetof(readwrite_handlers, write_double));
- sprintf(buffer, "%s.write_double:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->write_double, drc->cache_top);
-
- handlers->write_double_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED | flags, offsetof(readwrite_handlers, write_double_masked));
- sprintf(buffer, "%s.write_double_masked:", type);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, buffer, handlers->write_double_masked, drc->cache_top);
-}
-
-
-/*------------------------------------------------------------------
- append_generate_exception
-------------------------------------------------------------------*/
-
-static void append_generate_exception(drc_core *drc, UINT8 exception)
-{
- UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180;
- emit_link link1, link2;
-
- if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
- {
- /* assumes failed address is in P2 */
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_P2); // mov [BadVAddr],p2
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff
- emit_and_r32_imm(DRCTOP, REG_P2, 0xffffe000); // and p2,0xffffe000
- emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_P2); // or [EntryHi],p2
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000
- emit_shr_r32_imm(DRCTOP, REG_P2, 9); // shr p2,9
- emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_P2); // or [Context],p2
- }
-
- /* on entry, exception PC must be in REG_P1, and low bit set if in a delay slot */
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[Cause]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff
- emit_test_r32_imm(DRCTOP, REG_P1, 1); // test p1,1
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000
- emit_sub_r32_imm(DRCTOP, REG_P1, 5); // sub p1,5
-
- resolve_link(DRCTOP, &link1); // skip:
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_P1); // mov [EPC],p1
- if (exception)
- emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [Cause],eax
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[SR]
- emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL
- emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [SR],eax
- emit_mov_r32_imm(DRCTOP, REG_P1, 0xbfc00200 + offset); // mov p1,0xbfc00200+offset
- emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2
- emit_mov_r32_imm(DRCTOP, REG_P1, 0x80000000 + offset); // mov p1,0x80000000+offset
-
- resolve_link(DRCTOP, &link2); // skip2:
- if (PRINTF_EXCEPTIONS)
- {
- emit_mov_m32_r32(DRCTOP, PCADDR, REG_P1); // mov [PC],p1
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)exception_trap); // mov rax,exception_trap
- emit_call_r64(DRCTOP, REG_RAX); // call rax
- emit_mov_r32_m32(DRCTOP, REG_P1, PCADDR); // mov p1,[PC]
- }
- drc_append_dispatcher(drc); // dispatch
-}
-
-
-/*------------------------------------------------------------------
- append_handle_pc_tlb_mismatch
-------------------------------------------------------------------*/
-
-static void append_handle_pc_tlb_mismatch(drc_core *drc)
-{
-#if 0
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_R15D); // mov eax,edi
- emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12
- emit_mov_r32_m32(DRCTOP, REG_EDX, MISD(REG_EAX, 4, &mips3.core->tlb_table)); // mov edx,tlb_table[eax*4]
- emit_test_r32_imm(DRCTOP, REG_EDX, 2); // test edx,2
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_R15D); // mov eax,edi
- emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception
- emit_mov_m32bd_r32(DRCTOP, drc->pcptr, REG_R15D); // mov [pcptr],edi
- emit_jmp(DRCTOP, drc->recompile); // call recompile
-#endif
-}
-
-
-/*------------------------------------------------------------------
- append_find_exception_handler
-------------------------------------------------------------------*/
-
-static void append_find_exception_handler(drc_core *drc)
-{
- x86code *loop;
-
- emit_mov_r64_m64(DRCTOP, REG_RAX, MBD(REG_RSP, 0)); // mov rax,[rsp]
- emit_mov_r64_imm(DRCTOP, REG_V5, EXCEPTION_ADDRESS_COOKIE); // mov v5,EXCEPTION_ADDRESS_COOKIE
- emit_mov_r64_r64(DRCTOP, REG_V6, REG_RAX); // mov v6,rax
- emit_and_r64_imm(DRCTOP, REG_RAX, ~7); // and rax,~7
- emit_add_r64_imm(DRCTOP, REG_RSP, 8); // add rsp,8
- emit_add_r64_imm(DRCTOP, REG_RAX, 8); // add rax,8
- loop = drc->cache_top; // loop:
- emit_cmp_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_V5); // cmp [rax],v5
- emit_lea_r64_m64(DRCTOP, REG_RAX, MBD(REG_RAX, 8)); // lea rax,[rax+8]
- emit_jcc(DRCTOP, COND_NE, loop); // jne loop
- emit_cmp_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_V6); // cmp [rax],v6
- emit_lea_r64_m64(DRCTOP, REG_RAX, MBD(REG_RAX, 8)); // lea rax,[rax+8]
- emit_jcc(DRCTOP, COND_NE, loop); // jne loop
- emit_jmp_r64(DRCTOP, REG_RAX); // jmp rax
-}
-
-
-/*------------------------------------------------------------------
- append_direct_ram_read
-------------------------------------------------------------------*/
-
-static void append_direct_ram_read(drc_core *drc, int size, UINT8 flags, void *rambase, offs_t ramstart)
-{
- void *adjbase = (UINT8 *)rambase - ramstart;
- INT64 adjdisp = (UINT8 *)adjbase - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)adjdisp != adjdisp);
-
- /* if we can't fit the delta to adjbase within an INT32, load RAX with the full address here */
- if (raxrel)
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)adjbase);
-
- /* fast RAM byte read */
- if (size == 1)
- {
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_P1, 3); // xor p1,3
-
- /* read rax-relative */
- if (raxrel)
- {
- if (flags & ARW_SIGNED)
- emit_movsx_r64_m8(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsx rax,byte ptr [p1 + rax]
- else
- emit_movzx_r64_m8(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movzx rax,byte ptr [p1 + rax]
- }
-
- /* read drc-relative */
- else
- {
- if (flags & ARW_SIGNED)
- emit_movsx_r64_m8(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsx rax,byte ptr [p1 + adjbase]
- else
- emit_movzx_r64_m8(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movzx rax,byte ptr [p1 + adjbase]
- }
- }
-
- /* fast RAM halfword read */
- else if (size == 2)
- {
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_P1, 2); // xor p1,2
-
- /* read rax-relative */
- if (raxrel)
- {
- if (flags & ARW_SIGNED)
- emit_movsx_r64_m16(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsx rax,word ptr [p1 + rax]
- else
- emit_movzx_r64_m16(DRCTOP, REG_EAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movzx rax,word ptr [p1 + rax]
- }
-
- /* read drc-relative */
- else
- {
- if (flags & ARW_SIGNED)
- emit_movsx_r64_m16(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsx rax,word ptr [p1 + adjbase]
- else
- emit_movzx_r64_m16(DRCTOP, REG_EAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movzx rax,word ptr [p1 + adjbase]
- }
- }
-
- /* fast RAM dword read */
- else if (size == 4)
- {
- /* read rax-relative */
- if (raxrel)
- {
- if (flags & ARW_SIGNED)
- emit_movsxd_r64_m32(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // movsxd rax,dword ptr [p1 + rax]
- else
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBISD(REG_RAX, REG_P1, 1, 0)); // mov eax,word ptr [p1 + rax]
- }
-
- /* read drc-relative */
- else
- {
- if (flags & ARW_SIGNED)
- emit_movsxd_r64_m32(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // movsxd rax,dword ptr [p1 + adjbase]
- else
- emit_mov_r32_m32(DRCTOP, REG_EAX, MDRCISD(adjbase, REG_P1, 1, 0)); // mov eax,word ptr [p1 + adjbase]
- }
- }
-
- /* fast RAM qword read */
- else if (size == 8)
- {
- /* read rax-relative */
- if (raxrel)
- emit_mov_r64_m64(DRCTOP, REG_RAX, MBISD(REG_RAX, REG_P1, 1, 0)); // mov rax,[p1 + rax]
-
- /* read drc-relative */
- else
- emit_mov_r64_m64(DRCTOP, REG_RAX, MDRCISD(adjbase, REG_P1, 1, 0)); // mov rax,[p1 + adjbase]
-
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_ror_r64_imm(DRCTOP, REG_RAX, 32); // ror rax,32
- }
-}
-
-
-/*------------------------------------------------------------------
- append_direct_ram_write
-------------------------------------------------------------------*/
-
-static void append_direct_ram_write(drc_core *drc, int size, UINT8 flags, void *rambase, offs_t ramstart)
-{
- void *adjbase = (UINT8 *)rambase - ramstart;
- INT64 adjdisp = (UINT8 *)adjbase - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)adjdisp != adjdisp);
-
- /* if we can't fit the delta to adjbase within an INT32, load RAX with the full address here */
- if (raxrel)
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)adjbase);
-
- /* fast RAM byte write */
- if (size == 1)
- {
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_P1, 3); // xor p1,3
-
- /* write either rax-relative or drc-relative */
- if (raxrel)
- emit_mov_m8_r8(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
- else
- emit_mov_m8_r8(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
- }
-
- /* fast RAM halfword write */
- else if (size == 2)
- {
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_P1, 2); // xor p1,2
-
- /* write either rax-relative or drc-relative */
- if (raxrel)
- emit_mov_m16_r16(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
- else
- emit_mov_m16_r16(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
- }
-
- /* fast RAM dword write */
- else if (size == 4)
- {
- /* unmasked */
- if (!(flags & ARW_MASKED))
- {
- if (raxrel)
- emit_mov_m32_r32(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
- else
- emit_mov_m32_r32(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
- }
-
- /* masked */
- else
- {
- emit_mov_r32_r32(DRCTOP, REG_P4, REG_P3); // mov p4,p3
- emit_not_r32(DRCTOP, REG_P3); // not p3
- emit_and_r32_r32(DRCTOP, REG_P4, REG_P2); // and p4,p2
- if (raxrel)
- emit_and_r32_m32(DRCTOP, REG_P3, MBISD(REG_RAX, REG_P1, 1, 0)); // and p3,[p1 + rax]
- else
- emit_and_r32_m32(DRCTOP, REG_P3, MDRCISD(adjbase, REG_P1, 1, 0)); // and p3,[p1 + adjbase]
- emit_or_r32_r32(DRCTOP, REG_P4, REG_P3); // or p4,p3
- if (raxrel)
- emit_mov_m32_r32(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P4); // mov [p1 + rax],p4
- else
- emit_mov_m32_r32(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P4); // mov [p1 + adjbase],p4
- }
- }
-
- /* fast RAM qword write */
- else if (size == 8)
- {
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_ror_r64_imm(DRCTOP, REG_P2, 32); // ror p2,32
-
- /* unmasked */
- if (!(flags & ARW_MASKED))
- {
- if (raxrel)
- emit_mov_m64_r64(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P2); // mov [p1 + rax],p2
- else
- emit_mov_m64_r64(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P2); // mov [p1 + adjbase],p2
- }
-
- /* masked */
- else
- {
- if (mips3.core->bigendian)
- emit_ror_r64_imm(DRCTOP, REG_P3, 32); // ror p3,32
- emit_mov_r64_r64(DRCTOP, REG_P4, REG_P3); // mov p4,p3
- emit_not_r64(DRCTOP, REG_P3); // not p3
- emit_and_r64_r64(DRCTOP, REG_P4, REG_P2); // and p4,p2
- if (raxrel)
- emit_and_r64_m64(DRCTOP, REG_P3, MBISD(REG_RAX, REG_P1, 1, 0)); // and p3,[p1 + rax]
- else
- emit_and_r64_m64(DRCTOP, REG_P3, MDRCISD(adjbase, REG_P1, 1, 0)); // and p3,[p1 + adjbase]
- emit_or_r64_r64(DRCTOP, REG_P4, REG_P3); // or p4,p3
- if (raxrel)
- emit_mov_m64_r64(DRCTOP, MBISD(REG_RAX, REG_P1, 1, 0), REG_P4); // mov [p1 + rax],p4
- else
- emit_mov_m64_r64(DRCTOP, MDRCISD(adjbase, REG_P1, 1, 0), REG_P4); // mov [p1 + adjbase],p4
- }
- }
-}
-
-
-/*------------------------------------------------------------------
- append_readwrite_and_translate
-------------------------------------------------------------------*/
-
-static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags, UINT32 ptroffs)
-{
- UINT32 base = ((flags & ARW_CACHED) ? 0x80000000 : (flags & ARW_UNCACHED) ? 0xa0000000 : 0);
- emit_link page_fault = { 0 }, handle_kernel = { 0 }, wrong_handler = { 0 };
- x86code *continue_mapped = NULL;
- int ramnum;
-
- /* if the base is 0, this is a general case which may be paged; perform the translation first */
- /* the result of the translation produces the physical address inline in P1 */
- /* if a page fault occurs, we have to keep an original copy of the address in EAX */
- /* note that we use RAX and P4 as scratch registers */
- if (base == 0)
- {
- emit_test_r32_r32(DRCTOP, REG_P1, REG_P1); // test p1,p1
- emit_mov_r32_r32(DRCTOP, REG_P4, REG_P1); // mov p4,p1d
- emit_jcc_near_link(DRCTOP, COND_S, &handle_kernel); // js handle_kernel
- continue_mapped = drc->cache_top; // continue_mapped:
- emit_mov_r32_r32(DRCTOP, REG_V5, REG_P1); // mov v5,p1
- emit_shr_r32_imm(DRCTOP, REG_P1, 12); // shr p1,12
- emit_mov_r32_m32(DRCTOP, REG_P1, MDRCISD(mips3.core->tlb_table, REG_P1, 4, 0)); // mov p1,tlb_table[p1*4]
- emit_and_r32_imm(DRCTOP, REG_P4, 0xfff); // and p4,0xfff
- emit_shr_r32_imm(DRCTOP, REG_P1, (flags & ARW_WRITE) ? 1 : 2); // shr p1,2/1 (read/write)
- emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(REG_P4, REG_P1, (flags & ARW_WRITE) ? 2 : 4, 0));
- // lea p1,[p4 + p1 * 4/2 (read/write)]
- emit_jcc_near_link(DRCTOP, COND_C, &page_fault); // jc page_fault
- }
-
- /* if the base is non-zero, this is a cached/uncached direct-mapped case; no translation necessary */
- /* just subtract the base from the address to get the physcial address */
- else
- emit_sub_r32_imm(DRCTOP, REG_P1, base); // sub p1,base
-
- /* iterate over all fast RAM ranges looking for matches that can be handled directly */
- for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++)
- {
- const fast_ram_info *raminfo = &mips3.fastram[ramnum];
- if (!COMPARE_AGAINST_C && !Machine->debug_mode && raminfo->base != NULL && (!(flags & ARW_WRITE) || !raminfo->readonly))
- {
- emit_link notram1 = { 0 }, notram2 = { 0 };
-
- /* if we have an end, check it first */
- if (raminfo->end != 0xffffffff)
- {
- emit_cmp_r32_imm(DRCTOP, REG_P1, raminfo->end); // cmp p1,fastram_end
- emit_jcc_short_link(DRCTOP, COND_A, &notram1); // ja notram1
- }
-
- /* if we have a non-0 start, check it next */
- if (raminfo->start != 0x00000000)
- {
- emit_cmp_r32_imm(DRCTOP, REG_P1, raminfo->start); // cmp p1,fastram_start
- emit_jcc_short_link(DRCTOP, COND_B, &notram2); // jb notram2
- }
-
- /* handle a fast RAM read */
- if (!(flags & ARW_WRITE))
- {
- append_direct_ram_read(drc, size, flags, raminfo->base, raminfo->start); // <direct read>
- emit_ret(DRCTOP); // ret
- }
-
- /* handle a fast RAM write */
- else
- {
- append_direct_ram_write(drc, size, flags, raminfo->base, raminfo->start); // <direct write>
- emit_ret(DRCTOP); // ret
- }
-
- /* resolve links that skipped over us */
- if (raminfo->end != 0xffffffff)
- resolve_link(DRCTOP, &notram1); // notram1:
- if (raminfo->start != 0x00000000)
- resolve_link(DRCTOP, &notram2); // notram2:
- }
- }
-
- /* failed to find it in fast RAM; make sure we are within our expected range */
- if (base != 0)
- {
- emit_cmp_r32_imm(DRCTOP, REG_P1, 0x20000000); // cmp p1,0x20000000
- emit_jcc_short_link(DRCTOP, COND_AE, &wrong_handler); // jae wrong_handler
- }
-
- /* handle a write */
- if (flags & ARW_WRITE)
- {
- if (size == 1)
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writebyte)); // jmp writebyte
- else if (size == 2)
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writehalf)); // jmp writehalf
- else if (size == 4)
- {
- if (!(flags & ARW_MASKED))
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writeword)); // jmp writeword
- else
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writeword_masked)); // jmp writeword_masked
- }
- else
- {
- if (!(flags & ARW_MASKED))
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writedouble)); // jmp writedouble
- else
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.writedouble_masked)); // jmp writedouble_masked
- }
- }
-
- /* handle a read */
- else
- {
- if (size == 1)
- {
- emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28
- emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readbyte)); // call readbyte
- if (flags & ARW_SIGNED)
- emit_movsx_r64_r8(DRCTOP, REG_RAX, REG_AL); // movsx rax,al
- else
- emit_movzx_r64_r8(DRCTOP, REG_RAX, REG_AL); // movzx rax,al
- emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28
- emit_ret(DRCTOP); // ret
- }
- else if (size == 2)
- {
- emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28
- emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readhalf)); // call readhalf
- if (flags & ARW_SIGNED)
- emit_movsx_r64_r16(DRCTOP, REG_RAX, REG_AX); // movsx rax,ax
- else
- emit_movzx_r64_r16(DRCTOP, REG_RAX, REG_AX); // movzx rax,ax
- emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28
- emit_ret(DRCTOP); // ret
- }
- else if (size == 4)
- {
- if (!(flags & ARW_MASKED))
- {
- if (!(flags & ARW_SIGNED))
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readword)); // jmp readword
- else
- {
- emit_sub_r64_imm(DRCTOP, REG_RSP, 0x28); // sub rsp,0x28
- emit_call_m64(DRCTOP, MDRC(&mips3.core->memory.readword)); // call readword
- emit_movsxd_r64_r32(DRCTOP, REG_RAX, REG_EAX); // movsxd rax,eax
- emit_add_r64_imm(DRCTOP, REG_RSP, 0x28); // add rsp,0x28
- emit_ret(DRCTOP); // ret
- }
- }
- else
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readword_masked)); // jmp readword_masked
- }
- else
- {
- if (!(flags & ARW_MASKED))
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readdouble)); // jmp readdouble
- else
- emit_jmp_m64(DRCTOP, MDRC(&mips3.core->memory.readdouble_masked)); // jmp readdouble_masked
- }
- }
-
- /* handle wrong handlers */
- if (base == 0)
- {
- resolve_link(DRCTOP, &handle_kernel); // handle_kernel:
- emit_cmp_r32_imm(DRCTOP, REG_P1, 0xc0000000); // cmp p1,0xc0000000
- emit_jcc(DRCTOP, COND_AE, continue_mapped); // jae continue_mapped
- emit_test_r32_imm(DRCTOP, REG_P1, 0x20000000); // test p1,0x20000000
- emit_cmovcc_r64_m64(DRCTOP, COND_Z, REG_RAX, MDRCD(&mips3.drcdata->cached, ptroffs));
- // mov rax,<cached version>
- emit_cmovcc_r64_m64(DRCTOP, COND_NZ, REG_RAX, MDRCD(&mips3.drcdata->uncached, ptroffs));
- // mov rax,<uncached version>
- emit_mov_r64_m64(DRCTOP, REG_P4, MBD(REG_RSP, 0)); // mov p4,[rsp]
- emit_push_r64(DRCTOP, REG_RAX); // push rax
- emit_sub_r64_r64(DRCTOP, REG_RAX, REG_P4); // sub rax,p4
- emit_mov_m32_r32(DRCTOP, MBD(REG_P4, -4), REG_EAX); // mov [p4-4],eax
- emit_ret(DRCTOP); // ret
- }
- else
- {
- resolve_link(DRCTOP, &wrong_handler); // wrong_handler:
- emit_mov_r64_m64(DRCTOP, REG_RAX, MDRCD(&mips3.drcdata->general, ptroffs));
- // mov rax,<general version>
- emit_mov_r64_m64(DRCTOP, REG_P4, MBD(REG_RSP, 0)); // mov p4,[rsp]
- emit_push_r64(DRCTOP, REG_RAX); // push rax
- emit_sub_r64_r64(DRCTOP, REG_RAX, REG_P4); // sub rax,p4
- emit_mov_m32_r32(DRCTOP, MBD(REG_P4, -4), REG_EAX); // mov [p4-4],eax
- emit_add_r32_imm(DRCTOP, REG_P1, base); // add p1,base
- emit_ret(DRCTOP); // ret
- }
-
- /* handle page faults */
- if (base == 0)
- {
- resolve_link(DRCTOP, &page_fault); // page_fault:
- emit_mov_r32_r32(DRCTOP, REG_P2, REG_V5); // mov p2,v5
- emit_jmp(DRCTOP, mips3.drcdata->find_exception_handler); // jmp find_exception_handler
- }
-}
-
-
-/*------------------------------------------------------------------
- append_explode_ccr31
-------------------------------------------------------------------*/
-
-static void append_explode_ccr31(drc_core *drc)
-{
- emit_link link1;
- int i;
-
- /* new CCR31 value in EAX */
- emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1 << 23
- emit_mov_m32_r32(DRCTOP, CCR1ADDR(31), REG_EAX); // mov ccr[31],eax
- emit_setcc_m8(DRCTOP, COND_NZ, CF1ADDR(0)); // setnz fcc[0]
- if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
- for (i = 1; i <= 7; i++)
- {
- emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24 + i)); // test eax,1 << (24+i)
- emit_setcc_m8(DRCTOP, COND_NZ, CF1ADDR(i)); // setnz fcc[i]
- }
- emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3
- emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2
- resolve_link(DRCTOP, &link1); // skip:
- drc_append_set_sse_rounding(drc, REG_EAX); // set_rounding(EAX)
- emit_ret(DRCTOP); // ret
-}
-
-
-/*------------------------------------------------------------------
- append_recover_ccr31
-------------------------------------------------------------------*/
-
-static void append_recover_ccr31(drc_core *drc)
-{
- int i;
-
- emit_movsxd_r64_m32(DRCTOP, REG_RAX, CCR1ADDR(31)); // movsxd rax,ccr1[rd]
- emit_and_r64_imm(DRCTOP, REG_RAX, ~0xfe800000); // and rax,~0xfe800000
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_cmp_m8_imm(DRCTOP, CF1ADDR(0), 0); // cmp fcc[0],0
- emit_setcc_r8(DRCTOP, COND_NZ, REG_DL); // setnz dl
- emit_shl_r32_imm(DRCTOP, REG_EDX, 23); // shl edx,23
- emit_or_r64_r64(DRCTOP, REG_RAX, REG_RDX); // or rax,rdx
- if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
- for (i = 1; i <= 7; i++)
- {
- emit_cmp_m8_imm(DRCTOP, CF1ADDR(i), 0); // cmp fcc[i],0
- emit_setcc_r8(DRCTOP, COND_NZ, REG_DL); // setnz dl
- emit_shl_r32_imm(DRCTOP, REG_EDX, 24+i); // shl edx,24+i
- emit_or_r64_r64(DRCTOP, REG_RAX, REG_RDX); // or rax,rdx
- }
- emit_ret(DRCTOP); // ret
-}
-
-
-/*------------------------------------------------------------------
- append_check_interrupts
-------------------------------------------------------------------*/
-
-static void append_check_interrupts(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- emit_link link1, link2, link3 = { 0 };
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[Cause]
- emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[Status]
- emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [Status],SR_IE
- emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [Status],SR_EXL | SR_ERL
- if (desc == NULL)
- {
- emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc]
- emit_jcc_short_link(DRCTOP, COND_NZ, &link3); // jnz skip
- emit_jmp_m64(DRCTOP, MDRC(&mips3.drcdata->generate_interrupt_exception)); // jmp generate_interrupt_exception
- }
- else
- oob_request_callback(drc, COND_Z, oob_interrupt_cleanup, compiler, desc, mips3.drcdata->generate_interrupt_exception);
- resolve_link(DRCTOP, &link1); // skip:
- resolve_link(DRCTOP, &link2);
- if (desc == NULL)
- resolve_link(DRCTOP, &link3);
-}
-
-
-
-/***************************************************************************
- RECOMPILATION HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- emit_load_register_value - load a register
- either as a constant or as a register
--------------------------------------------------*/
-
-static void emit_load_register_value(drc_core *drc, compiler_state *compiler, UINT8 dstreg, mipsreg_state regstate)
-{
- /* must be live or constant */
- assert(ISCONST(regstate) || ISLIVE(regstate));
-
- /* if the register is constant, do an immediate load */
- if (ISCONST(regstate))
- {
- INT32 mipsval = CONSTVAL(regstate);
- if (mipsval != 0)
- emit_mov_r64_imm(DRCTOP, dstreg, mipsval);
- else
- emit_xor_r32_r32(DRCTOP, dstreg, dstreg);
- }
-
- /* otherwise, load from the allocated register, but only if different */
- else
- {
- UINT8 srcreg = X86REG(regstate);
- if (dstreg != srcreg)
- emit_mov_r64_r64(DRCTOP, dstreg, srcreg);
- }
-}
-
-
-/*-------------------------------------------------
- emit_set_constant_value - set a constant
- value; if it is too large, allocate a
- register and populate it
--------------------------------------------------*/
-
-static void emit_set_constant_value(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 mipsreg, UINT64 constval)
-{
- /* ignore reigster 0 destination */
- if (mipsreg == 0)
- return;
-
- /* if we fit in 32-bits, just continue the constant charade */
- if ((INT32)constval == (INT64)constval)
- compiler_register_set_constant(compiler, mipsreg, constval);
-
- /* otherwise, allocate a new register and move the result into it */
- else
- {
- mipsreg_state resultreg = compiler_register_allocate(drc, compiler, desc, mipsreg, ALLOC_DST | ALLOC_DIRTY);
- emit_mov_r64_imm(DRCTOP, X86REG(resultreg), constval); // mov <rt>,result
- }
-}
-
-
-/*------------------------------------------------------------------
- emit_flush_cycles_before_instruction
-------------------------------------------------------------------*/
-
-static void emit_flush_cycles_before_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT32 cycles_to_leave)
-{
- /* if we have cycles, subtract them now */
- if (compiler->cycles - cycles_to_leave != 0)
- emit_sub_m32_imm(DRCTOP, ICOUNTADDR, compiler->cycles - cycles_to_leave); // sub [icount],cycles
-
- /* clear out compiler counts */
- compiler->cycles = cycles_to_leave;
-}
-
-
-/*------------------------------------------------------------------
- emit_update_cycles_pc_and_flush
-------------------------------------------------------------------*/
-
-static void emit_update_cycles_pc_and_flush(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, offs_t destpc)
-{
- /* if we have cycles, subtract them now */
- emit_sub_m32_imm(DRCTOP, ICOUNTADDR, compiler->cycles); // sub [icount],cycles
-
- /* clear out compiler counts */
- compiler->cycles = 0;
-
- /* if we have an opcode descriptor, make this an oob */
- if (desc != NULL)
- oob_request_callback(drc, COND_S, oob_interrupt_cleanup, compiler, desc, mips3.drc->exit_point);
-
- /* otherwise, do it inline */
- else
- {
- /* load the target PC into P1 */
- if (destpc != BRANCH_TARGET_DYNAMIC)
- emit_mov_r32_imm(DRCTOP, REG_P1, destpc); // mov p1,destpc
- else
- emit_mov_r32_m32(DRCTOP, REG_P1, MBD(REG_RSP, SPOFFS_NEXTPC)); // mov p1,[esp+nextpc]
-
- /* flush any live registers */
- compiler_register_flush_all(drc, compiler);
-
- /* if we subtracted cycles and went negative, time to exit */
- emit_jcc(DRCTOP, COND_S, mips3.drc->exit_point); // js exit_point
- }
-}
-
-
-/*------------------------------------------------------------------
- emit_delay_slot_and_branch
-------------------------------------------------------------------*/
-
-static void emit_delay_slot_and_branch(drc_core *drc, const compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg)
-{
- compiler_state compiler_temp = *compiler;
-
- /* set the link if needed */
- if (linkreg != 0)
- compiler_register_set_constant(&compiler_temp, linkreg, (INT32)(desc->pc + 8)); // <link> = pc + 8
-
- /* compile the delay slot using temporary compiler state */
- assert(desc->delay != NULL);
- compile_one(drc, &compiler_temp, desc->delay); // <next instruction>
-
- /* update the cycles and load the new PC in case we need to stop here */
- emit_update_cycles_pc_and_flush(drc, &compiler_temp, NULL, desc->targetpc);
-
- /* otherwise, append a dispatcher */
- if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
- drc_append_tentative_fixed_dispatcher(drc, desc->targetpc, FALSE); // <redispatch>
- else
- drc_append_dispatcher(drc); // <redispatch>
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_byte_read
-------------------------------------------------------------------*/
-
-static int emit_fixed_byte_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address)
-{
- void *fastram = fastram_ptr(address, 1, FALSE);
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address); // mov p1,address
- if (is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_byte_unsigned); // call read_byte_unsigned
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_byte_signed); // call read_byte_signed
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- if (destreg != REG_RAX)
- emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (is_unsigned)
- emit_movzx_r64_m8(DRCTOP, destreg, MBD(REG_RAX, 0)); // movzx destreg,byte ptr [rax]
- else
- emit_movsx_r64_m8(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsx destreg,byte ptr [rax]
- }
-
- /* read drc-relative */
- else
- {
- if (is_unsigned)
- emit_movzx_r64_m8(DRCTOP, destreg, MDRC(fastram)); // movzx destreg,byte ptr [p1 + adjbase]
- else
- emit_movsx_r64_m8(DRCTOP, destreg, MDRC(fastram)); // movsx destreg,byte ptr [p1 + adjbase]
- }
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_half_read
-------------------------------------------------------------------*/
-
-static int emit_fixed_half_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address)
-{
- void *fastram = fastram_ptr(address & ~1, 2, FALSE);
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address & ~1); // mov p1,address & ~1
- if (is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_half_unsigned); // call read_half_unsigned
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_half_signed); // call read_half_signed
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- if (destreg != REG_RAX)
- emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* read rax-relative */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (is_unsigned)
- emit_movzx_r64_m16(DRCTOP, destreg, MBD(REG_RAX, 0)); // movzx destreg,word ptr [rax]
- else
- emit_movsx_r64_m16(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsx destreg,word ptr [rax]
- }
-
- /* read drc-relative */
- else
- {
- if (is_unsigned)
- emit_movzx_r64_m16(DRCTOP, destreg, MDRC(fastram)); // movzx destreg,word ptr [p1 + adjbase]
- else
- emit_movsx_r64_m16(DRCTOP, destreg, MDRC(fastram)); // movsx destreg,word ptr [p1 + adjbase]
- }
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_word_read
-------------------------------------------------------------------*/
-
-static int emit_fixed_word_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, int is_unsigned, offs_t address, UINT32 mask)
-{
- void *fastram = fastram_ptr(address & ~3, 4, FALSE);
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address & ~3); // mov p1,address & ~3
- if (mask != 0xffffffff)
- {
- emit_mov_r32_imm(DRCTOP, REG_P2, (INT32)mask); // mov p2,mask
- emit_call(DRCTOP, mips3.drcdata->general.read_word_masked); // call read_word_masked
- }
- else if (is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call read_word_unsigned
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_word_signed); // call read_word_signed
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- if (destreg != REG_RAX)
- emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (is_unsigned)
- emit_mov_r32_m32(DRCTOP, destreg, MBD(REG_RAX, 0)); // mov destreg,word ptr [rax]
- else
- emit_movsxd_r64_m32(DRCTOP, destreg, MBD(REG_RAX, 0)); // movsxd destreg,dword ptr [rax]
- }
-
- /* read drc-relative */
- else
- {
- if (is_unsigned)
- emit_mov_r32_m32(DRCTOP, destreg, MDRC(fastram)); // mov destreg,word ptr [p1 + adjbase]
- else
- emit_movsxd_r64_m32(DRCTOP, destreg, MDRC(fastram)); // movsxd destreg,dword ptr [p1 + adjbase]
- }
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_double_read
-------------------------------------------------------------------*/
-
-static int emit_fixed_double_read(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 destreg, offs_t address, UINT64 mask)
-{
- void *fastram = fastram_ptr(address & ~7, 8, FALSE);
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address & ~7); // mov p1,address & ~7
- if (mask != U64(0xffffffffffffffff))
- {
- emit_mov_r64_imm(DRCTOP, REG_P2, mask); // mov p2,mask
- emit_call(DRCTOP, mips3.drcdata->general.read_double_masked); // call read_double_masked
- }
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_double); // call read_double
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- if (destreg != REG_RAX)
- emit_mov_r64_r64(DRCTOP, destreg, REG_RAX); // mov <rt>,rax
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- emit_mov_r64_m64(DRCTOP, destreg, MBD(REG_RAX, 0)); // mov destreg,[rax]
- }
-
- /* read drc-relative */
- else
- emit_mov_r64_m64(DRCTOP, destreg, MDRC(fastram)); // mov destreg,[p1 + adjbase]
-
- /* adjust for endianness */
- if (mips3.core->bigendian)
- emit_ror_r64_imm(DRCTOP, destreg, 32); // ror destreg,32
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_byte_write
-------------------------------------------------------------------*/
-
-static int emit_fixed_byte_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address)
-{
- void *fastram = fastram_ptr(address, 1, TRUE);
-
- assert(ISCONST(srcreg) || X86REG(srcreg != REG_P1));
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address); // mov p1,address
- if (ISCONST(srcreg))
- emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,<srcreg>
- else if (X86REG(srcreg) != REG_P2)
- emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,<srcreg>
- emit_call(DRCTOP, mips3.drcdata->general.write_byte); // call write_byte
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (ISCONST(srcreg))
- emit_mov_m8_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval
- else
- emit_mov_m8_r8(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],<srcreg>
- }
-
- /* write drc-relative */
- else
- {
- if (ISCONST(srcreg))
- emit_mov_m8_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval
- else
- emit_mov_m8_r8(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
- }
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_half_write
-------------------------------------------------------------------*/
-
-static int emit_fixed_half_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address)
-{
- void *fastram = fastram_ptr(address & ~1, 2, TRUE);
-
- assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1);
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address & ~1); // mov p1,address & ~1
- if (ISCONST(srcreg))
- emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval
- else if (X86REG(srcreg) != REG_P2)
- emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
- emit_call(DRCTOP, mips3.drcdata->general.write_half); // call write_half
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (ISCONST(srcreg))
- emit_mov_m16_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval
- else
- emit_mov_m16_r16(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg
- }
-
- /* write drc-relative */
- else
- {
- if (ISCONST(srcreg))
- emit_mov_m16_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval
- else
- emit_mov_m16_r16(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
- }
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_word_write
-------------------------------------------------------------------*/
-
-static int emit_fixed_word_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address, UINT32 mask)
-{
- void *fastram = fastram_ptr(address & ~3, 4, TRUE);
-
- assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1);
- assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P3);
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address & ~3); // mov p1,address & ~3
- if (ISCONST(srcreg))
- emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval
- else if (X86REG(srcreg) != REG_P2)
- emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
- if (mask == 0xffffffff)
- emit_call(DRCTOP, mips3.drcdata->general.write_word); // call write_word
- else
- {
- emit_mov_r32_imm(DRCTOP, REG_P3, mask); // mov p3,mask
- emit_call(DRCTOP, mips3.drcdata->general.write_word_masked); // call write_word_masked
- }
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
-
- /* non-masked case */
- if (mask == 0xffffffff)
- {
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (ISCONST(srcreg))
- emit_mov_m32_imm(DRCTOP, MBD(REG_RAX, 0), CONSTVAL(srcreg)); // mov [rax],constval
- else
- emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg
- }
-
- /* write drc-relative */
- else
- {
- if (ISCONST(srcreg))
- emit_mov_m32_imm(DRCTOP, MDRC(fastram), CONSTVAL(srcreg)); // mov [fastram],constval
- else
- emit_mov_m32_r32(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
- }
- }
-
- /* masked case */
- else
- {
- if (raxrel)
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- else
- emit_lea_r64_m64(DRCTOP, REG_RAX, MDRC(fastram)); // lea rax,[fastram]
-
- /* always write rax-relative */
- if (ISCONST(srcreg))
- {
- emit_mov_r32_m32(DRCTOP, REG_P2, MBD(REG_RAX, 0)); // mov p2,[rax]
- emit_and_r32_imm(DRCTOP, REG_P2, ~mask); // and p2,~mask
- emit_or_r32_imm(DRCTOP, REG_P2, CONSTVAL(srcreg) & mask); // or p2,constval & mask
- emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), REG_P2); // mov [rax],p2
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_P3, MBD(REG_RAX, 0)); // mov p3,[rax]
- if (X86REG(srcreg) != REG_P2)
- emit_mov_r32_r32(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
- emit_and_r32_imm(DRCTOP, REG_P3, ~mask); // and p3,~mask
- emit_and_r32_imm(DRCTOP, REG_P2, mask); // and p2,mask
- emit_or_r32_r32(DRCTOP, REG_P3, REG_P2); // or p3,p2
- emit_mov_m32_r32(DRCTOP, MBD(REG_RAX, 0), REG_P3); // mov [rax],p3
- }
- }
- }
- return (fastram != NULL);
-}
-
-
-/*------------------------------------------------------------------
- emit_fixed_double_write
-------------------------------------------------------------------*/
-
-static int emit_fixed_double_write(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, mipsreg_state srcreg, offs_t address, UINT64 mask)
-{
- void *fastram = fastram_ptr(address & ~7, 8, TRUE);
-
- assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P1);
- assert(ISCONST(srcreg) || X86REG(srcreg) != REG_P3);
- assert((INT32)CONSTVAL(srcreg) == (INT64)CONSTVAL(srcreg));
-
- /* if we can't do fast RAM, we need to make the call */
- if (fastram == NULL)
- {
- emit_mov_r32_imm(DRCTOP, REG_P1, address & ~7); // mov p1,address & ~7
- if (ISCONST(srcreg))
- emit_mov_r64_imm(DRCTOP, REG_P2, CONSTVAL(srcreg)); // mov p2,constval
- else if (X86REG(srcreg) != REG_P2)
- emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
- if (mask == U64(0xffffffffffffffff))
- emit_call(DRCTOP, mips3.drcdata->general.write_double); // call write_double
- else
- {
- emit_mov_r64_imm(DRCTOP, REG_P3, mask); // mov p3,mask
- emit_call(DRCTOP, mips3.drcdata->general.write_double_masked); // call write_double_masked
- }
-
- /* handle exceptions */
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* if we can do fastram, emit the right form */
- else
- {
- INT64 fastdisp = (UINT8 *)fastram - (UINT8 *)drc->baseptr;
- int raxrel = ((INT32)fastdisp != fastdisp);
- INT64 constval = CONSTVAL(srcreg);
-
- /* adjust values for endianness */
- if (mips3.core->bigendian)
- {
- if (ISCONST(srcreg))
- constval = (constval << 32) | (constval >> 32);
- else
- {
- emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
- emit_ror_r64_imm(DRCTOP, REG_P2, 32); // ror p2,32
- srcreg = REG_P2;
- }
- mask = (mask << 32) | (mask >> 32);
- }
-
- /* non-masked case */
- if (mask == U64(0xffffffffffffffff))
- {
- /* if we can't fit the delta to fastram within an INT32, load RAX with the full address here */
- if (raxrel)
- {
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- if (ISCONST(srcreg))
- emit_mov_m64_imm(DRCTOP, MBD(REG_RAX, 0), constval); // mov [rax],constval
- else
- emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), X86REG(srcreg)); // mov [rax],srcreg
- }
-
- /* write drc-relative */
- else
- {
- if (ISCONST(srcreg))
- emit_mov_m64_imm(DRCTOP, MDRC(fastram), constval); // mov [fastram],constval
- else
- emit_mov_m64_r64(DRCTOP, MDRC(fastram), X86REG(srcreg)); // mov [fastram],srcreg
- }
- }
-
- /* masked case */
- else
- {
- if (raxrel)
- emit_mov_r64_imm(DRCTOP, REG_RAX, (UINT64)fastram); // mov rax,fastram
- else
- emit_lea_r64_m64(DRCTOP, REG_RAX, MDRC(fastram)); // lea rax,[fastram]
- emit_mov_r64_imm(DRCTOP, REG_P4, ~mask); // mov p4,~mask
-
- /* always write rax-relative */
- if (ISCONST(srcreg))
- {
- emit_and_r64_m64(DRCTOP, REG_P4, MBD(REG_RAX, 0)); // and p4,[rax]
- emit_mov_r64_imm(DRCTOP, REG_P3, constval & mask); // mov p3,constval & mask
- emit_or_r64_r64(DRCTOP, REG_P4, REG_P3); // or p4,p3
- emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_P4); // mov [rax],p4
- }
- else
- {
- emit_mov_r64_m64(DRCTOP, REG_P3, MBD(REG_RAX, 0)); // mov p3,[rax]
- if (X86REG(srcreg) != REG_P2)
- emit_mov_r64_r64(DRCTOP, REG_P2, X86REG(srcreg)); // mov p2,srcreg
- emit_and_r64_r64(DRCTOP, REG_P3, REG_P4); // and p3,p4
- emit_not_r64(DRCTOP, REG_P4); // not p4
- emit_and_r64_r64(DRCTOP, REG_P2, REG_P4); // and p2,p4
- emit_or_r64_r64(DRCTOP, REG_P3, REG_P2); // or p3,p2
- emit_mov_m64_r64(DRCTOP, MBD(REG_RAX, 0), REG_P3); // mov [rax],p3
- }
- }
- }
- return (fastram != NULL);
-}
-
-
-
-/***************************************************************************
- CORE RECOMPILATION
-***************************************************************************/
-
-/*-------------------------------------------------
- compile_instruction - master switch statement
- for compiling a given opcode
--------------------------------------------------*/
-
-static int compile_instruction(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 opswitch = op >> 26;
-
- switch (opswitch)
- {
- /* ----- sub-groups ----- */
-
- case 0x00: /* SPECIAL */
- return compile_special(drc, compiler, desc);
-
- case 0x01: /* REGIMM */
- return compile_regimm(drc, compiler, desc);
-
- case 0x1c: /* IDT-specific */
- return compile_idt(drc, compiler, desc);
-
-
- /* ----- jumps and branches ----- */
-
- case 0x02: /* J */
- case 0x03: /* JAL */
- emit_delay_slot_and_branch(drc, compiler, desc, (opswitch == 0x02) ? 0 : 31); // <next instruction + redispatch>
- return TRUE;
-
- case 0x04: /* BEQ */
- case 0x14: /* BEQL */
- case 0x05: /* BNE */
- case 0x15: /* BNEL */
- return compile_branchcc(drc, compiler, desc, (opswitch & 1) ? COND_NE : COND_E);
-
- case 0x06: /* BLEZ */
- case 0x16: /* BLEZL */
- case 0x07: /* BGTZ */
- case 0x17: /* BGTZL */
- return compile_branchcz(drc, compiler, desc, (opswitch & 1) ? COND_G : COND_LE, FALSE);
-
-
- /* ----- immediate arithmetic ----- */
-
- case 0x0f: /* LUI */
- if (RTREG != 0)
- emit_set_constant_value(drc, compiler, desc, RTREG, SIMMVAL << 16);
- return TRUE;
-
- case 0x08: /* ADDI */
- case 0x09: /* ADDIU */
- return compile_add(drc, compiler, desc, opswitch & 1, TRUE);
-
- case 0x18: /* DADDI */
- case 0x19: /* DADDIU */
- return compile_dadd(drc, compiler, desc, opswitch & 1, TRUE);
-
- case 0x0c: /* ANDI */
- case 0x0d: /* ORI */
- case 0x0e: /* XORI */
- return compile_logical(drc, compiler, desc, opswitch & 3, TRUE);
-
- case 0x0a: /* SLTI */
- case 0x0b: /* SLTIU */
- return compile_slt(drc, compiler, desc, opswitch & 1, TRUE);
-
-
- /* ----- memory load operations ----- */
-
- case 0x20: /* LB */
- case 0x21: /* LH */
- case 0x23: /* LW */
- case 0x24: /* LBU */
- case 0x25: /* LHU */
- case 0x27: /* LWU */
- return compile_load(drc, compiler, desc, (opswitch & 3) + 1, opswitch & 4);
-
- case 0x37: /* LD */
- return compile_load(drc, compiler, desc, 8, FALSE);
-
- case 0x31: /* LWC1 */
- return compile_load_cop(drc, compiler, desc, 4, FPR32(RTREG));
-
- case 0x35: /* LDC1 */
- return compile_load_cop(drc, compiler, desc, 8, FPR64(RTREG));
-
- case 0x32: /* LWC2 */
- case 0x36: /* LDC2 */
- return compile_load_cop(drc, compiler, desc, (opswitch & 4) ? 8 : 4, &mips3.core->cpr[2][RTREG]);
-
- case 0x1a: /* LDL */
- case 0x1b: /* LDR */
- return compile_load_double_partial(drc, compiler, desc, opswitch & 1);
-
- case 0x22: /* LWL */
- case 0x26: /* LWR */
- return compile_load_word_partial(drc, compiler, desc, opswitch & 4);
-
-
- /* ----- memory store operations ----- */
-
- case 0x28: /* SB */
- case 0x29: /* SH */
- case 0x2b: /* SW */
- return compile_store(drc, compiler, desc, (opswitch & 3) + 1);
-
- case 0x3f: /* SD */
- return compile_store(drc, compiler, desc, 8);
-
- case 0x39: /* SWC1 */
- return compile_store_cop(drc, compiler, desc, 4, FPR32(RTREG));
-
- case 0x3d: /* SDC1 */
- return compile_store_cop(drc, compiler, desc, 8, FPR64(RTREG));
-
- case 0x3a: /* SWC2 */
- return compile_store_cop(drc, compiler, desc, (opswitch & 4) ? 8 : 4, &mips3.core->cpr[2][RTREG]);
-
- case 0x2a: /* SWL */
- case 0x2e: /* SWR */
- return compile_store_word_partial(drc, compiler, desc, opswitch & 4);
-
- case 0x2c: /* SDL */
- case 0x2d: /* SDR */
- return compile_store_double_partial(drc, compiler, desc, opswitch & 1);
-
-
- /* ----- effective no-ops ----- */
-
- case 0x2f: /* CACHE */
- case 0x33: /* PREF */
- return TRUE;
-
-
- /* ----- coprocessor instructions ----- */
-
- case 0x10: /* COP0 */
- return compile_cop0(drc, compiler, desc);
-
- case 0x11: /* COP1 */
- return compile_cop1(drc, compiler, desc);
-
- case 0x13: /* COP1X - R5000 */
- return compile_cop1x(drc, compiler, desc);
-
- case 0x12: /* COP2 */
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_invalidop_exception);
- // jmp generate_invalidop_exception
- return TRUE;
-
-
- /* ----- unimplemented/illegal instructions ----- */
-
-// case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break;
-// case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break;
-// case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break;
-// case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break;
-// case 0x3b: /* SWC3 */ invalid_instruction(op); break;
-// default: /* ??? */ invalid_instruction(op); break;
- }
-
- return FALSE;
-}
-
-
-/*-------------------------------------------------
- compile_special - compile opcodes in the
- 'SPECIAL' group
--------------------------------------------------*/
-
-static int compile_special(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 opswitch = op & 63;
- emit_link link1 = { 0 };
-
- switch (opswitch)
- {
- /* ----- shift instructions ----- */
-
- case 0x00: /* SLL - MIPS I */
- case 0x02: /* SRL - MIPS I */
- case 0x03: /* SRA - MIPS I */
- case 0x04: /* SLLV - MIPS I */
- case 0x06: /* SRLV - MIPS I */
- case 0x07: /* SRAV - MIPS I */
- return compile_shift(drc, compiler, desc, opswitch & 0x03, opswitch & 0x04);
-
- case 0x14: /* DSLLV - MIPS III */
- case 0x16: /* DSRLV - MIPS III */
- case 0x17: /* DSRAV - MIPS III */
- case 0x38: /* DSLL - MIPS III */
- case 0x3a: /* DSRL - MIPS III */
- case 0x3b: /* DSRA - MIPS III */
- case 0x3c: /* DSLL32 - MIPS III */
- case 0x3e: /* DSRL32 - MIPS III */
- case 0x3f: /* DSRA32 - MIPS III */
- return compile_dshift(drc, compiler, desc, opswitch & 0x03, ~opswitch & 0x20, opswitch & 0x04);
-
-
- /* ----- basic arithmetic ----- */
-
- case 0x20: /* ADD - MIPS I */
- case 0x21: /* ADDU - MIPS I */
- return compile_add(drc, compiler, desc, opswitch & 1, FALSE);
-
- case 0x2c: /* DADD - MIPS III */
- case 0x2d: /* DADDU - MIPS III */
- return compile_dadd(drc, compiler, desc, opswitch & 1, FALSE);
-
- case 0x22: /* SUB - MIPS I */
- case 0x23: /* SUBU - MIPS I */
- return compile_sub(drc, compiler, desc, opswitch & 1);
-
- case 0x2e: /* DSUB - MIPS III */
- case 0x2f: /* DSUBU - MIPS III */
- return compile_dsub(drc, compiler, desc, opswitch & 1);
-
- case 0x18: /* MULT - MIPS I */
- case 0x19: /* MULTU - MIPS I */
- return compile_mult(drc, compiler, desc, opswitch & 1);
-
- case 0x1c: /* DMULT - MIPS III */
- case 0x1d: /* DMULTU - MIPS III */
- return compile_dmult(drc, compiler, desc, opswitch & 1);
-
- case 0x1a: /* DIV - MIPS I */
- case 0x1b: /* DIVU - MIPS I */
- return compile_div(drc, compiler, desc, opswitch & 1);
-
- case 0x1e: /* DDIV - MIPS III */
- case 0x1f: /* DDIVU - MIPS III */
- return compile_ddiv(drc, compiler, desc, opswitch & 1);
-
-
- /* ----- basic logical ops ----- */
-
- case 0x24: /* AND - MIPS I */
- case 0x25: /* OR - MIPS I */
- case 0x26: /* XOR - MIPS I */
- case 0x27: /* NOR - MIPS I */
- return compile_logical(drc, compiler, desc, opswitch & 3, FALSE);
-
-
- /* ----- basic comparisons ----- */
-
- case 0x2a: /* SLT - MIPS I */
- case 0x2b: /* SLTU - MIPS I */
- return compile_slt(drc, compiler, desc, opswitch & 1, FALSE);
-
-
- /* ----- conditional traps ----- */
-
- case 0x30: /* TGE - MIPS II */
- case 0x31: /* TGEU - MIPS II */
- case 0x32: /* TLT - MIPS II */
- case 0x33: /* TLTU - MIPS II */
- case 0x34: /* TEQ - MIPS II */
- case 0x36: /* TNE - MIPS II */
- return compile_trapcc(drc, compiler, desc, opswitch & 7, FALSE);
-
-
- /* ----- conditional moves ----- */
-
- case 0x0a: /* MOVZ - MIPS IV */
- case 0x0b: /* MOVN - MIPS IV */
- return compile_movzn(drc, compiler, desc, opswitch & 1);
-
- case 0x01: /* MOVF - MIPS IV */
- if (RDREG != 0)
- {
- mipsreg_state rs, rd;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
-
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[x],0
- emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip
- emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
- }
- resolve_link(DRCTOP, &link1); // skip:
- return TRUE;
-
-
- /* ----- jumps and branches ----- */
-
- case 0x08: /* JR - MIPS I */
- case 0x09: /* JALR - MIPS I */
- {
- mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- if (ISCONST(rs))
- emit_mov_m32_imm(DRCTOP, MBD(REG_RSP, SPOFFS_NEXTPC), CONSTVAL(rs)); // mov [esp+nextpc],rs
- else
- emit_mov_m32_r32(DRCTOP, MBD(REG_RSP, SPOFFS_NEXTPC), X86REG(rs)); // mov [esp+nextpc],rs
- emit_delay_slot_and_branch(drc, compiler, desc, (opswitch == 0x09) ? RDREG : 0);
- // <next instruction + redispatch>
- }
- return TRUE;
-
-
- /* ----- system calls ----- */
-
- case 0x0c: /* SYSCALL - MIPS I */
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_syscall_exception);
- // jmp generate_syscall_exception
- return TRUE;
-
- case 0x0d: /* BREAK - MIPS I */
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_break_exception);
- // jmp generate_break_exception
- return TRUE;
-
-
- /* ----- effective no-ops ----- */
-
- case 0x0f: /* SYNC - MIPS II */
- return TRUE;
-
-
- /* ----- hi/lo register access ----- */
-
- case 0x10: /* MFHI - MIPS I */
- if (RDREG != 0)
- {
- mipsreg_state hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_SRC);
- mipsreg_state rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
- emit_load_register_value(drc, compiler, X86REG(rd), hi); // mov <rd>,<hi>
- }
- return TRUE;
-
- case 0x11: /* MTHI - MIPS I */
- if (RSREG != 0)
- {
- mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- mipsreg_state hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
- emit_load_register_value(drc, compiler, X86REG(hi), rs); // mov hi,<rs>
- }
- return TRUE;
-
- case 0x12: /* MFLO - MIPS I */
- if (RDREG != 0)
- {
- mipsreg_state lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_SRC);
- mipsreg_state rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
- emit_load_register_value(drc, compiler, X86REG(rd), lo); // mov <rd>,<lo>
- }
- return TRUE;
-
- case 0x13: /* MTLO - MIPS I */
- if (RSREG != 0)
- {
- mipsreg_state rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- mipsreg_state lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
- emit_load_register_value(drc, compiler, X86REG(lo), rs); // mov lo,<rs>
- }
- return TRUE;
- }
- return FALSE;
-}
-
-
-/*-------------------------------------------------
- compile_regimm - compile opcodes in the
- 'REGIMM' group
--------------------------------------------------*/
-
-static int compile_regimm(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 opswitch = RTREG;
-
- switch (opswitch)
- {
- case 0x00: /* BLTZ */
- case 0x01: /* BGEZ */
- case 0x02: /* BLTZL */
- case 0x03: /* BGEZL */
- case 0x10: /* BLTZAL */
- case 0x11: /* BGEZAL */
- case 0x12: /* BLTZALL */
- case 0x13: /* BGEZALL */
- return compile_branchcz(drc, compiler, desc, (opswitch & 1) ? COND_GE : COND_L, opswitch & 0x10);
-
- case 0x08: /* TGEI */
- case 0x09: /* TGEIU */
- case 0x0a: /* TLTI */
- case 0x0b: /* TLTIU */
- case 0x0c: /* TEQI */
- case 0x0e: /* TNEI */
- return compile_trapcc(drc, compiler, desc, opswitch & 7, TRUE);
- }
- return FALSE;
-}
-
-
-/*-------------------------------------------------
- compile_idt - compile opcodes in the IDT-
- specific group
--------------------------------------------------*/
-
-static int compile_idt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- fatalerror("Unimplemented IDT instructions");
-#if 0
- UINT32 op = *desc->opptr.l;
- UINT8 opswitch = op & 0x1f;
-
- switch (opswitch)
- {
- case 0: /* MAD */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
- emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg]
- emit_imul_r32(DRCTOP, REG_EDX); // imul edx
- emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo]
- emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi]
- emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EAX); // mov [lo],edx:eax
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EAX); // mov [hi],edx:eax
- }
- return compile_SUCCESSFUL_CP(3,4);
-
- case 1: /* MADU */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
- emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg]
- emit_mul_r32(DRCTOP, REG_EDX); // mul edx
- emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo]
- emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi]
- emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- }
- return compile_SUCCESSFUL_CP(3,4);
-
- case 2: /* MUL */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
- emit_imul_r32_m32(REG_EAX, REGADDR(RTREG)); // imul eax,[rtreg]
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(REG_ESI, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rd],edx:eax
- }
- else
- emit_zero_m64(REG_ESI, REGADDR(RDREG));
- }
- return compile_SUCCESSFUL_CP(3,4);
- }
-#endif
- return FALSE;
-}
-
-
-
-/***************************************************************************
- COP0 RECOMPILATION
-***************************************************************************/
-
-/*-------------------------------------------------
- compile_set_cop0_reg - generate code to
- handle special COP0 registers
--------------------------------------------------*/
-
-static int compile_set_cop0_reg(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 reg)
-{
- emit_link link1;
-
- switch (reg)
- {
- case COP0_Cause:
- emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Cause)); // mov edx,[Cause]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00
- emit_and_r32_imm(DRCTOP, REG_EDX, 0xfc00); // and edx,0xfc00
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); // or eax,edx
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [Cause],eax
- emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[SR]
- emit_test_r32_imm(DRCTOP, REG_EAX, 0x300); // test eax,0x300
- oob_request_callback(drc, COND_NZ, oob_interrupt_cleanup, compiler, desc, mips3.drcdata->generate_interrupt_exception);
- // jnz generate_interrupt_exception
- return TRUE;
-
- case COP0_Status:
- emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
- emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Status)); // mov edx,[Status]
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [Status],eax
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EAX); // xor edx,eax
- emit_test_r32_imm(DRCTOP, REG_EDX, SR_IMEX5); // test edx,0x8000
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting
- resolve_link(DRCTOP, &link1); // skip:
- append_check_interrupts(drc, compiler, desc); // <check interrupts>
- return TRUE;
-
- case COP0_Count:
- emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [Count],eax
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles)); // call activecpu_gettotalcycles
- emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Count)); // mov edx,[Count]
- emit_sub_r64_r64(DRCTOP, REG_RAX, REG_RDX); // sub rax,rdx
- emit_sub_r64_r64(DRCTOP, REG_RAX, REG_RDX); // sub rax,rdx
- emit_mov_m64_r64(DRCTOP, MDRC(&mips3.core->count_zero_time), REG_RAX); // mov [count_zero_time],rax
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting
- return TRUE;
-
- case COP0_Compare:
- emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [Compare],eax
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [Cause],~0x8000
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_update_cycle_counting)); // call mips3com_update_cycle_counting
- return TRUE;
-
- case COP0_PRId:
- return TRUE;
-
- case COP0_Config:
- emit_mov_r32_m32(DRCTOP, REG_EDX, CPR0ADDR(COP0_Config)); // mov edx,[Config]
- emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007
- emit_and_r32_imm(DRCTOP, REG_EDX, ~0x0007); // and edx,~0x0007
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EDX); // or eax,edx
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [Config],eax
- return TRUE;
-
- default:
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov cpr0[reg],eax
- return TRUE;
- }
-}
-
-
-/*-------------------------------------------------
- compile_get_cop0_reg - generate code to
- read special COP0 registers
--------------------------------------------------*/
-
-static int compile_get_cop0_reg(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, UINT8 reg)
-{
- emit_link link1, link2;
-
- switch (reg)
- {
- case COP0_Count:
- compiler->cycles += MIPS3_COUNT_READ_CYCLES;
- emit_flush_cycles_before_instruction(drc, compiler, desc, MIPS3_COUNT_READ_CYCLES);
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles)); // call activecpu_gettotalcycles
- emit_sub_r64_m64(DRCTOP, REG_RAX, MDRC(&mips3.core->count_zero_time)); // sub rax,[count_zero_time]
- emit_shr_r64_imm(DRCTOP, REG_RAX, 1); // shr rax,1
- emit_movsxd_r64_r32(DRCTOP, REG_RAX, REG_EAX); // movsxd rax,eax
- return TRUE;
-
- case COP0_Cause:
- compiler->cycles += MIPS3_CAUSE_READ_CYCLES;
- emit_movsxd_r64_m32(DRCTOP, REG_RAX, CPR0ADDR(COP0_Cause)); // movsxd rax,[Cause]
- return TRUE;
-
- case COP0_Random:
- emit_flush_cycles_before_instruction(drc, compiler, desc, 1);
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->activecpu_gettotalcycles)); // call activecpu_gettotalcycles
- emit_mov_r32_m32(DRCTOP, REG_ECX, CPR0ADDR(COP0_Wired)); // mov ecx,[Wired]
- emit_mov_r32_imm(DRCTOP, REG_R8D, 48); // mov r8d,48
- emit_and_r32_imm(DRCTOP, REG_ECX, 0x3f); // and ecx,0x3f
- emit_sub_r64_m64(DRCTOP, REG_RAX, MDRC(&mips3.core->count_zero_time)); // sub rax,[count_zero_time]
- emit_sub_r32_r32(DRCTOP, REG_R8D, REG_ECX); // sub r8d,ecx
- emit_jcc_short_link(DRCTOP, COND_BE, &link1); // jbe link1
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_div_r64(DRCTOP, REG_R8); // div r8
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx
- emit_add_r32_r32(DRCTOP, REG_EAX, REG_ECX); // add eax,ecx
- emit_and_r32_imm(DRCTOP, REG_EAX, 0x3f); // and eax,0x3f
- emit_jmp_short_link(DRCTOP, &link2); // jmp link2
- resolve_link(DRCTOP, &link1); // link1:
- emit_mov_r32_imm(DRCTOP, REG_EAX, 47); // mov eax,47
- resolve_link(DRCTOP, &link2); // link2:
- return TRUE;
-
- default:
- emit_movsxd_r64_m32(DRCTOP, REG_RAX, CPR0ADDR(reg)); // movsxd rax,cpr0[reg]
- return TRUE;
- }
-}
-
-
-/*-------------------------------------------------
- compile_cop0 - compile COP0 opcodes
--------------------------------------------------*/
-
-static int compile_cop0(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 opswitch = RSREG;
-
- /* generate an exception if COP0 is disabled or we are not in kernel mode */
- if (mips3.drcoptions & MIPS3DRC_STRICT_COP0)
- {
- emit_link checklink;
-
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [SR],SR_KSU_MASK
- emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [SR],SR_COP0
- oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception);
- // jz generate_cop_exception
- resolve_link(DRCTOP, &checklink); // okay:
- }
-
- switch (opswitch)
- {
- case 0x00: /* MFCz */
- case 0x01: /* DMFCz */
- if (RTREG != 0)
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
- compile_get_cop0_reg(drc, compiler, desc, RDREG); // mov eax,cpr0[rd])
- if (!(opswitch & 1))
- emit_movsxd_r64_r32(DRCTOP, X86REG(rt), REG_EAX); // movsxd <rt>,eax
- else
- emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov <rt>,rax
- }
- return TRUE;
-
- case 0x02: /* CFCz */
- if (RTREG != 0)
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
- emit_movsxd_r64_m32(DRCTOP, X86REG(rt), CCR0ADDR(RDREG)); // movsxd <rt>,ccr1[rd]
- }
- return TRUE;
-
- case 0x04: /* MTCz */
- case 0x05: /* DMTCz */
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
- emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt>
- compile_set_cop0_reg(drc, compiler, desc, RDREG); // mov cpr0[rd],rax
- }
- return TRUE;
-
- case 0x06: /* CTCz */
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
- emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt>
- emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov ccr1[rd],eax
- }
- return TRUE;
-
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x13:
- case 0x14:
- case 0x15:
- case 0x16:
- case 0x17:
- case 0x18:
- case 0x19:
- case 0x1a:
- case 0x1b:
- case 0x1c:
- case 0x1d:
- case 0x1e:
- case 0x1f: /* COP */
- switch (op & 0x01ffffff)
- {
- case 0x01: /* TLBR */
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbr)); // call mips3com_tlbr
- return TRUE;
-
- case 0x02: /* TLBWI */
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbwi)); // call mips3com_tlbwi
- return TRUE;
-
- case 0x06: /* TLBWR */
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbwr)); // call mips3com_tlbwr
- return TRUE;
-
- case 0x08: /* TLBP */
- emit_lea_r64_m64(DRCTOP, REG_P1, COREADDR); // lea p1,[mips3.core]
- emit_call_m64(DRCTOP, MDRC(&mips3.drcdata->mips3com_tlbp)); // call mips3com_tlbp
- return TRUE;
-
- case 0x18: /* ERET */
- emit_mov_r32_m32(DRCTOP, REG_P1, CPR0ADDR(COP0_EPC)); // mov p1,[EPC]
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [SR],~SR_EXL
- compiler_register_flush_all(drc, compiler); // <flush registers>
- drc_append_dispatcher(drc); // <dispatch>
- return TRUE;
-
- case 0x20: /* WAIT */
- return TRUE;
- }
- break;
- }
-
- return FALSE;
-}
-
-
-
-/***************************************************************************
- COP1 RECOMPILATION
-***************************************************************************/
-
-/*-------------------------------------------------
- compile_cop1 - compile COP1 opcodes
--------------------------------------------------*/
-
-static int compile_cop1(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- UINT32 op = *desc->opptr.l;
- emit_link link1;
-
- /* generate an exception if COP1 is disabled */
- if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
- {
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [mips3.core->cpr[0][COP0_Status]],SR_COP1
- oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception);
- // jz generate_cop_exception
- }
-
- switch (RSREG)
- {
- case 0x00: /* MFCz */
- if (RTREG != 0)
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
- emit_movsxd_r64_m32(DRCTOP, X86REG(rt), FPR32ADDR(RDREG)); // movsxd <rt>,cpr[rd]
- }
- return TRUE;
-
- case 0x01: /* DMFCz */
- if (RTREG != 0)
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
- emit_mov_r64_m64(DRCTOP, X86REG(rt), FPR64ADDR(RDREG)); // mov <rt>,cpr[rd]
- }
- return TRUE;
-
- case 0x02: /* CFCz */
- if (RTREG != 0)
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST | ALLOC_DIRTY);
- if (RDREG != 31)
- emit_movsxd_r64_m32(DRCTOP, X86REG(rt), CCR1ADDR(RDREG)); // movsxd <rt>,ccr1[rd]
- else
- {
- emit_call(DRCTOP, mips3.drcdata->recover_ccr31); // call recover_ccr31
- emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov [X86REG(rt)],rax
- }
- }
- return TRUE;
-
- case 0x04: /* MTCz */
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
- UINT8 tempreg = ISCONST(rt) ? REG_EAX : X86REG(rt);
- emit_load_register_value(drc, compiler, tempreg, rt); // mov <tempreg>,<rt>
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), tempreg); // mov cpr1[rd],<tempreg>
- }
- return TRUE;
-
- case 0x05: /* DMTCz */
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
- UINT8 tempreg = ISCONST(rt) ? REG_EAX : X86REG(rt);
- emit_load_register_value(drc, compiler, tempreg, rt); // mov <tempreg>,<rt>
- emit_mov_m64_r64(DRCTOP, FPR64ADDR(RDREG), tempreg); // mov cpr1[rd],<tempreg>
- }
- return TRUE;
-
- case 0x06: /* CTCz */
- {
- mipsreg_state rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
- emit_load_register_value(drc, compiler, REG_EAX, rt); // mov eax,<rt>
- if (RDREG != 31)
- emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov ccr1[rd],eax
- else
- emit_call(DRCTOP, mips3.drcdata->explode_ccr31); // call explode_ccr31
- }
- return TRUE;
-
- case 0x08: /* BC */
- switch ((op >> 16) & 3)
- {
- case 0x00: /* BCzF */
- case 0x02: /* BCzFL */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1
- emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return TRUE;
-
- case 0x01: /* BCzT */
- case 0x03: /* BCzTL */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1
- emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return TRUE;
- }
- break;
-
- default:
- switch (op & 0x3f)
- {
- case 0x00:
- if (IS_SINGLE(op)) /* ADD.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* ADD.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x01:
- if (IS_SINGLE(op)) /* SUB.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* SUB.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x02:
- if (IS_SINGLE(op)) /* MUL.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* MUL.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x03:
- if (IS_SINGLE(op)) /* DIV.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* DIV.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x04:
- if (IS_SINGLE(op)) /* SQRT.S */
- {
- emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* SQRT.D */
- {
- emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x05:
- if (IS_SINGLE(op)) /* ABS.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_andps_r128_m128(DRCTOP, REG_XMM0, MDRC(mips3.drcdata->abs32mask));
- // andps xmm0,[abs32mask]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* ABS.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_andps_r128_m128(DRCTOP, REG_XMM0, MDRC(mips3.drcdata->abs64mask));
- // andpd xmm0,[abs64mask]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x06:
- if (IS_SINGLE(op)) /* MOV.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* MOV.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x07:
- if (IS_SINGLE(op)) /* NEG.S */
- {
- emit_xorps_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // xorps xmm0,xmm0
- emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // subss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* NEG.D */
- {
- emit_xorps_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // xorps xmm0,xmm0
- emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // subsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x08:
- /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
- drc_append_set_temp_sse_rounding(drc, FPRND_NEAR); // ldmxcsr [round]
- if (IS_SINGLE(op)) /* ROUND.L.S */
- emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
- else /* ROUND.L.D */
- emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
- emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
- drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
- return TRUE;
-
- case 0x09:
- if (IS_SINGLE(op)) /* TRUNC.L.S */
- emit_cvttss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvttss2si rax,[fsreg]
- else /* TRUNC.L.D */
- emit_cvttsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvttsd2si rax,[fsreg]
- emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
- return TRUE;
-
- case 0x0a:
- /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
- drc_append_set_temp_sse_rounding(drc, FPRND_UP); // ldmxcsr [round]
- if (IS_SINGLE(op)) /* CEIL.L.S */
- emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
- else /* CEIL.L.D */
- emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
- emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
- drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
- return TRUE;
-
- case 0x0b:
- /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
- drc_append_set_temp_sse_rounding(drc, FPRND_DOWN); // ldmxcsr [round]
- if (IS_SINGLE(op)) /* FLOOR.L.S */
- emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
- else /* FLOOR.L.D */
- emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
- emit_mov_m64_r64(DRCTOP, FPR64ADDR(FDREG), REG_RAX); // mov [fdreg],rax
- drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
- return TRUE;
-
- case 0x0c:
- /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
- drc_append_set_temp_sse_rounding(drc, FPRND_NEAR); // ldmxcsr [round]
- if (IS_SINGLE(op)) /* ROUND.W.S */
- emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
- else /* ROUND.W.D */
- emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
- return TRUE;
-
- case 0x0d:
- if (IS_SINGLE(op)) /* TRUNC.W.S */
- emit_cvttss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvttss2si eax,[fsreg]
- else /* TRUNC.W.D */
- emit_cvttsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvttsd2si eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- return TRUE;
-
- case 0x0e:
- /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
- drc_append_set_temp_sse_rounding(drc, FPRND_UP); // ldmxcsr [round]
- if (IS_SINGLE(op)) /* CEIL.W.S */
- emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
- else /* CEIL.W.D */
- emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
- return TRUE;
-
- case 0x0f:
- /* FUTURE: On Penryn, we can use ROUNDPS/ROUNDPD */
- drc_append_set_temp_sse_rounding(drc, FPRND_DOWN); // ldmxcsr [round]
- if (IS_SINGLE(op)) /* FLOOR.W.S */
- emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
- else /* FLOOR.W.D */
- emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- drc_append_restore_sse_rounding(drc); // ldmxcsr [mode]
- return TRUE;
-
- case 0x11: /* R5000 */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp fcc[which],0
- emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1);
- // jz/nz skip
- if (IS_SINGLE(op)) /* MOVT/F.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* MOVT/F.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- resolve_link(DRCTOP, &link1); // skip:
- return TRUE;
-
- case 0x12: /* R5000 */
- emit_cmp_m64_imm(DRCTOP, REGADDR(RTREG), 0); // cmp [X86REG(rt)],0
- emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip
- if (IS_SINGLE(op)) /* MOVZ.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* MOVZ.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- resolve_link(DRCTOP, &link1); // skip:
- return TRUE;
-
- case 0x13: /* R5000 */
- emit_cmp_m64_imm(DRCTOP, REGADDR(RTREG), 0); // cmp [X86REG(rt)],0
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- if (IS_SINGLE(op)) /* MOVN.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* MOVN.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- resolve_link(DRCTOP, &link1); // skip:
- return TRUE;
-
- case 0x15: /* R5000 */
- if (IS_SINGLE(op)) /* RECIP.S */
- {
- emit_rcpss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // rcpss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* RECIP.D */
- {
- emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsd2ss xmm0,[fsreg]
- emit_rcpss_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // rcpss xmm0,xmm0
- emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // cvtss2sd xmm0,xmm0
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x16: /* R5000 */
- if (IS_SINGLE(op)) /* RSQRT.S */
- {
- emit_rsqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // rsqrtss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else /* RSQRT.D */
- {
- emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtss2sd xmm0,[fsreg]
- emit_rsqrtss_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // rsqrtss xmm0,xmm0
- emit_cvtss2sd_r128_r128(DRCTOP, REG_XMM0, REG_XMM0); // cvtsd2ss xmm0,xmm0
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- return TRUE;
-
- case 0x20:
- if (IS_INTEGRAL(op))
- {
- if (IS_SINGLE(op)) /* CVT.S.W */
- emit_cvtsi2ss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtsi2ss xmm0,[fsreg]
- else /* CVT.S.L */
- emit_cvtsi2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsi2ss xmm0,[fsreg]
- }
- else /* CVT.S.D */
- emit_cvtsd2ss_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsd2ss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- return TRUE;
-
- case 0x21:
- if (IS_INTEGRAL(op))
- {
- if (IS_SINGLE(op)) /* CVT.D.W */
- emit_cvtsi2sd_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtsi2sd xmm0,[fsreg]
- else /* CVT.D.L */
- emit_cvtsi2sd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // cvtsi2sd xmm0,[fsreg]
- }
- else /* CVT.D.S */
- emit_cvtss2sd_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // cvtss2sd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- return TRUE;
-
- case 0x24:
- if (IS_SINGLE(op)) /* CVT.W.S */
- emit_cvtss2si_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // cvtss2si eax,[fsreg]
- else /* CVT.W.D */
- emit_cvtsd2si_r32_m64(DRCTOP, REG_EAX, FPR64ADDR(FSREG)); // cvtsd2si eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- return TRUE;
-
- case 0x25:
- if (IS_SINGLE(op)) /* CVT.L.S */
- emit_cvtss2si_r64_m32(DRCTOP, REG_RAX, FPR32ADDR(FSREG)); // cvtss2si rax,[fsreg]
- else /* CVT.L.D */
- emit_cvtsd2si_r64_m64(DRCTOP, REG_RAX, FPR64ADDR(FSREG)); // cvtsd2si rax,[fsreg]
- emit_mov_m64_r64(DRCTOP, FPR32ADDR(FDREG), REG_RAX); // mov [fdreg],rax
- return TRUE;
-
- case 0x30:
- case 0x38:
- emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */
- return TRUE;
-
- case 0x31:
- case 0x39:
- emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */
- return TRUE;
-
- case 0x32:
- case 0x3a:
- if (IS_SINGLE(op)) /* C.EQ.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
- }
- else /* C.EQ.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete fcc[x]
- return TRUE;
-
- case 0x33:
- case 0x3b:
- if (IS_SINGLE(op)) /* C.UEQ.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
- }
- else /* C.UEQ.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete fcc[x]
- return TRUE;
-
- case 0x34:
- case 0x3c:
- if (IS_SINGLE(op)) /* C.OLT.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
- }
- else /* C.OLT.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb fcc[x]
- return TRUE;
-
- case 0x35:
- case 0x3d:
- if (IS_SINGLE(op)) /* C.ULT.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
- }
- else /* C.ULT.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb fcc[x]
- return TRUE;
-
- case 0x36:
- case 0x3e:
- if (IS_SINGLE(op)) /* C.OLE.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
- }
- else /* C.OLE.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe fcc[x]
- return TRUE;
-
- case 0x37:
- case 0x3f:
- if (IS_SINGLE(op)) /* C.ULE.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
- }
- else /* C.ULE.D */
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe fcc[x]
- return TRUE;
- }
- break;
- }
- return FALSE;
-}
-
-
-
-/***************************************************************************
- COP1X RECOMPILATION
-***************************************************************************/
-
-/*-------------------------------------------------
- compile_cop1x - compile COP1X opcodes
--------------------------------------------------*/
-
-static int compile_cop1x(drc_core *drc, compiler_state *compiler, const opcode_desc *desc)
-{
- UINT32 op = *desc->opptr.l;
-
- if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
- {
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [mips3.core->cpr[0][COP0_Status]],SR_COP1
- oob_request_callback(drc, COND_Z, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_cop_exception);
- // jz generate_cop_exception
- }
-
- switch (op & 0x3f)
- {
- case 0x00: /* LWXC1 */
- return compile_loadx_cop(drc, compiler, desc, 4, FPR32(FDREG));
-
- case 0x01: /* LDXC1 */
- return compile_loadx_cop(drc, compiler, desc, 8, FPR64(FDREG));
-
- case 0x08: /* SWXC1 */
- return compile_storex_cop(drc, compiler, desc, 4, FPR32(FDREG));
-
- case 0x09: /* SDXC1 */
- return compile_storex_cop(drc, compiler, desc, 8, FPR64(FDREG));
-
- case 0x0f: /* PREFX */
- return TRUE;
-
- case 0x20: /* MADD.S */
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- return TRUE;
-
- case 0x21: /* MADD.D */
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- return TRUE;
-
- case 0x28: /* MSUB.S */
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- return TRUE;
-
- case 0x29: /* MSUB.D */
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- return TRUE;
-
- case 0x30: /* NMADD.S */
- emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
- emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
- return TRUE;
-
- case 0x31: /* NMADD.D */
- emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
- emit_subsd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subsd xmm1,xmm0
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
- return TRUE;
-
- case 0x38: /* NMSUB.S */
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg]
- emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
- return TRUE;
-
- case 0x39: /* NMSUB.D */
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg]
- emit_subsd_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subsd xmm1,xmm0
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
- return TRUE;
-
- case 0x24: /* MADD.W */
- case 0x25: /* MADD.L */
- case 0x2c: /* MSUB.W */
- case 0x2d: /* MSUB.L */
- case 0x34: /* NMADD.W */
- case 0x35: /* NMADD.L */
- case 0x3c: /* NMSUB.W */
- case 0x3d: /* NMSUB.L */
- default:
- fprintf(stderr, "cop1x %X\n", op);
- break;
- }
- return FALSE;
-}
-
-
-
-/***************************************************************************
- INDIVIDUAL INSTRUCTION COMPILATION
-***************************************************************************/
-
-/*-------------------------------------------------
- compile_shift - compile a 32-bit
- shift, both fixed and variable counts
-
- 0: sll/sllv rD,rT,rS
- 2: srl/srlv rD,rT,rS
- 3: sra/srav rD,rT,rS
--------------------------------------------------*/
-
-static int compile_shift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rd, rs, rt;
-
- assert(shift_type == 0 || shift_type == 2 || shift_type == 3);
-
- /* if the destination is r0, bail */
- if (RDREG == 0)
- return TRUE;
-
- /* allocate source registers */
- rs = shift_variable ? compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC) : MAKE_CONST(SHIFT);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rS and rT are both constant, we can compute the constant result */
- if (ISCONST(rs) && ISCONST(rt))
- {
- if (shift_type == 0)
- emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((UINT32)CONSTVAL(rt) << CONSTVAL(rs)));
- else if (shift_type == 2)
- emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((UINT32)CONSTVAL(rt) >> CONSTVAL(rs)));
- else
- emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)((INT32)CONSTVAL(rt) >> CONSTVAL(rs)));
- }
-
- /* otherwise, handle generically */
- else
- {
- /* allocate the register and load rT into it */
- /* if rS is non-const, must load it first in case rD == rS */
- rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
- if (!ISCONST(rs))
- emit_load_register_value(drc, compiler, REG_ECX, rs); // mov ecx,<rs>
- emit_load_register_value(drc, compiler, X86REG(rd), rt); // mov <rd>,<rt>
-
- /* if rs is constant, use immediate forms of the shift */
- if (ISCONST(rs))
- {
- if (shift_type == 0)
- emit_shl_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // shl <rd>,<rs>
- else if (shift_type == 2)
- emit_shr_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // shr <rd>,<rs>
- else
- emit_sar_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 31); // sar <rd>,<rs>
- }
-
- /* otherwise, load rs into cl so we can do a variable shift */
- else
- {
- if (shift_type == 0)
- emit_shl_r32_cl(DRCTOP, X86REG(rd)); // shl <rd>,cl
- else if (shift_type == 2)
- emit_shr_r32_cl(DRCTOP, X86REG(rd)); // shr <rd>,cl
- else
- emit_sar_r32_cl(DRCTOP, X86REG(rd)); // sar <rd>,cl
- }
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_dshift - compile a 64-bit
- shift, both fixed and variable counts
-
- 0: dsll/dsll32/dsllv rD,rT,rS
- 2: dsrl/dsrl32/dsrlv rD,rT,rS
- 3: dsra/dsra32/dsrav rD,rT,rS
--------------------------------------------------*/
-
-static int compile_dshift(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int shift_type, int shift_variable, int shift_const_plus32)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rd, rs, rt;
-
- assert(shift_type == 0 || shift_type == 2 || shift_type == 3);
-
- /* if the destination is r0, bail */
- if (RDREG == 0)
- return TRUE;
-
- /* allocate source registers */
- rs = shift_variable ? compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC) : MAKE_CONST(SHIFT + (shift_const_plus32 ? 32 : 0));
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rS and rT are both constant, we can compute the constant result */
- if (ISCONST(rs) && ISCONST(rt))
- {
- if (shift_type == 0)
- emit_set_constant_value(drc, compiler, desc, RDREG, (UINT64)CONSTVAL(rt) << CONSTVAL(rs));
- else if (shift_type == 2)
- emit_set_constant_value(drc, compiler, desc, RDREG, (UINT64)CONSTVAL(rt) >> CONSTVAL(rs));
- else
- emit_set_constant_value(drc, compiler, desc, RDREG, (INT64)CONSTVAL(rt) >> CONSTVAL(rs));
- }
-
- /* otherwise, handle generically */
- else
- {
- /* allocate the register and load rT into it */
- /* if rS is non-const, must load it first in case rD == rS */
- rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST | ALLOC_DIRTY);
- if (!ISCONST(rs))
- emit_load_register_value(drc, compiler, REG_ECX, rs); // mov ecx,<rs>
- emit_load_register_value(drc, compiler, X86REG(rd), rt); // mov <rd>,<rt>
-
- /* if rs is constant, use immediate forms of the shift */
- if (ISCONST(rs))
- {
- if (shift_type == 0)
- emit_shl_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // shl <rd>,<rs>
- else if (shift_type == 2)
- emit_shr_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // shr <rd>,<rs>
- else
- emit_sar_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs) & 63); // sar <rd>,<rs>
- }
-
- /* otherwise, load rs into cl so we can do a variable shift */
- else
- {
- if (shift_type == 0)
- emit_shl_r64_cl(DRCTOP, X86REG(rd)); // shl <rd>,cl
- else if (shift_type == 2)
- emit_shr_r64_cl(DRCTOP, X86REG(rd)); // shr <rd>,cl
- else
- emit_sar_r64_cl(DRCTOP, X86REG(rd)); // sar <rd>,cl
- }
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_movzn - compile a conditional
- move based on compare against 0
-
- movz/movn rD,rS,rT
--------------------------------------------------*/
-
-static int compile_movzn(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_movn)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rd, rs, rt;
- emit_link skip = { 0 };
-
- /* if the destination is r0, bail */
- if (RDREG == 0)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
- rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
-
- /* if rT is constant and fails the condition, we're done */
- if (ISCONST(rt))
- {
- INT32 rtval = CONSTVAL(rt);
- if ((is_movn && rtval == 0) || (!is_movn && rtval != 0))
- return TRUE;
- }
-
- /* if rT is not constant, check the condition */
- else
- {
- emit_test_r64_r64(DRCTOP, X86REG(rt), X86REG(rt)); // test <rt>,<rt>
- emit_jcc_short_link(DRCTOP, is_movn ? COND_Z : COND_NZ, &skip); // jz/nz skip
- }
-
- /* load rS into rD */
- emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
- if (!ISCONST(rt))
- resolve_link(DRCTOP, &skip); // skip:
-
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_trapcc - compile a conditional
- trap comparing two registers
-
- 0/1: tge/tgeu rS,rT / tgei/tgeiu rS,SIMM
- 2/3: tlt/tltu rS,rT / tlti/tltiu rS,SIMM
- 4: teq rS,rT / teqi rS,SIMM
- 6: tne rS,rT / tnei rS,SIMM
--------------------------------------------------*/
-
-static int compile_trapcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int immediate)
-{
- static const UINT8 condtype[] = { COND_GE, COND_AE, COND_L, COND_B, COND_E, COND_NONE, COND_NE, COND_NONE };
- UINT32 op = *desc->opptr.l;
- mipsreg_state rs, rt;
-
- assert(condition < ARRAY_LENGTH(condtype) && condtype[condition] != COND_NONE);
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT32 rsval = CONSTVAL(rs);
- INT32 rtval = CONSTVAL(rt);
- int result = FALSE;
-
- /* determine the fixed answer */
- switch (condition)
- {
- case 0: result = ((INT64)rsval >= (INT64)rtval); break;
- case 1: result = ((UINT64)rsval >= (UINT64)rtval); break;
- case 2: result = ((INT64)rsval < (INT64)rtval); break;
- case 3: result = ((UINT64)rsval < (UINT64)rtval); break;
- case 4: result = (rsval == rtval); break;
- case 6: result = (rsval != rtval); break;
- }
-
- /* if we're not trapping, just return; otherwise, always trap */
- if (!result)
- return TRUE;
- condition = COND_NONE;
- }
-
- /* if rT is constant do an immediate compare */
- else if (ISCONST(rt))
- {
- emit_cmp_r64_imm(DRCTOP, X86REG(rs), CONSTVAL(rt)); // cmp <rs>,<rt>
- condition = condtype[condition];
- }
-
- /* if rS is constant do an immediate compare with opposite condition */
- else if (ISCONST(rs))
- {
- emit_cmp_r64_imm(DRCTOP, X86REG(rt), CONSTVAL(rs)); // cmp <rt>,<rs>
- condition = condtype[condition] ^ 1;
- }
-
- /* otherwise, compare the two registers with a normal condition */
- else
- {
- emit_cmp_r64_imm(DRCTOP, X86REG(rs), X86REG(rt)); // cmp <rs>,<rt>
- condition = condtype[condition];
- }
-
- /* generate an OOB request if the trap is taken */
- oob_request_callback(drc, condition, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_trap_exception);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_branchcc - compile a conditional
- branch comparing two registers
-
- beq rS,rT,dest
- bne rS,rT,dest
--------------------------------------------------*/
-
-static int compile_branchcc(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition)
-{
- UINT32 op = *desc->opptr.l;
- emit_link skip = { 0 };
- mipsreg_state rs, rt;
-
- assert(condition == COND_E || condition == COND_NE);
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT32 rsval = CONSTVAL(rs);
- INT32 rtval = CONSTVAL(rt);
- if ((condition == COND_E && rsval != rtval) || (condition == COND_NE && rsval == rtval))
- return TRUE;
- }
-
- /* if rT is constant do an immediate compare */
- else if (ISCONST(rt))
- {
- emit_cmp_r64_imm(DRCTOP, X86REG(rs), CONSTVAL(rt)); // cmp <rs>,<rt>
- emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
- }
-
- /* if rS is constant do an immediate compare */
- else if (ISCONST(rs))
- {
- emit_cmp_r64_imm(DRCTOP, X86REG(rt), CONSTVAL(rs)); // cmp <rt>,<rs>
- emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
- }
-
- /* otherwise, compare the two registers with a normal condition */
- else
- {
- emit_cmp_r64_r64(DRCTOP, X86REG(rs), X86REG(rt)); // cmp <rs>,<rt>
- emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
- }
-
- /* append the branch logic */
- emit_delay_slot_and_branch(drc, compiler, desc, 0); // <next instruction + redispatch>
-
- if (!(ISCONST(rs) && ISCONST(rt)))
- resolve_link(DRCTOP, &skip); // skip:
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_branchcz - compile a conditional
- branch comparing one register against 0
-
- blez rS,dest
- blezl rS,dest
- bgtz rS,dest
- bgtzl rS,dest
- bltz rS,dest
- bltzl rS,dest
- bltzal rS,dest
- bltzall rS,dest
- bgez rS,dest
- bgezl rS,dest
- bgezal rS,dest
- bgezall rS,dest
--------------------------------------------------*/
-
-static int compile_branchcz(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int condition, int link)
-{
- UINT32 op = *desc->opptr.l;
- emit_link skip = { 0 };
- mipsreg_state rs;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
-
- /* if the register is constant, we know the answer up front */
- if (ISCONST(rs))
- {
- INT32 rsval = CONSTVAL(rs);
- if ((condition == COND_LE && rsval > 0) || (condition == COND_G && rsval <= 0) ||
- (condition == COND_L && rsval >= 0) || (condition == COND_GE && rsval < 0))
- return TRUE;
- }
-
- /* otherwise, perform the compare */
- else
- {
- emit_cmp_r64_imm(DRCTOP, X86REG(rs), 0); // cmp <rs>,0
- emit_jcc_near_link(DRCTOP, condition ^ 1, &skip); // jncc skip
- }
-
- /* append the branch logic */
- emit_delay_slot_and_branch(drc, compiler, desc, link ? 31 : 0); // <next instruction + redispatch>
-
- if (!ISCONST(rs))
- resolve_link(DRCTOP, &skip); // skip:
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_add - compile an add with or without
- overflow
-
- add rD,rS,rT / addi rT,rS,SIMM
- addu rD,rS,rT / addiu rT,rS,SIMM
--------------------------------------------------*/
-
-static int compile_add(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 destreg = immediate ? RTREG : RDREG;
- mipsreg_state rd, rs, rt;
-
- /* note that we still must perform this operation even if destreg == 0
- in the overflow case */
- if (destreg == 0 && suppress_exceptions)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT64 result = (INT64)CONSTVAL(rs) + (INT64)CONSTVAL(rt);
-
- /* if we overflow, always generate an exception */
- if (!suppress_exceptions && (INT32)result != result)
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
-
- /* else just set the new constant value */
- else if (destreg != 0)
- emit_set_constant_value(drc, compiler, desc, destreg, (INT32)result);
- }
-
- /* otherwise, handle generically */
- else
- {
- rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST);
-
- /* perform the operating in EAX so we don't trash rD if an exception happens */
- if (!suppress_exceptions)
- {
- emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
- if (!ISCONST(rt))
- emit_add_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // add eax,<rt>
- else if (CONSTVAL(rt) != 0)
- emit_add_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rt)); // add eax,<rt>
- oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
- // jo generate_overflow_exception
- if (destreg != 0)
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), REG_EAX); // movsxd <rd>,eax
- }
- else
- {
- if (ISCONST(rs) && CONSTVAL(rs) == 0)
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rt)); // movsxd <rd>,<rt>
- else if (ISCONST(rt) && CONSTVAL(rt) == 0)
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rs)); // movsxd <rd>,<rs>
- else if (ISCONST(rs))
- {
- emit_lea_r32_m32(DRCTOP, X86REG(rd), MBD(X86REG(rt), CONSTVAL(rs))); // lea <rd>,[<rt> + <rs>]
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
- }
- else if (ISCONST(rt))
- {
- emit_lea_r32_m32(DRCTOP, X86REG(rd), MBD(X86REG(rs), CONSTVAL(rt))); // lea <rd>,[<rs> + <rt>]
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
- }
- else
- {
- emit_lea_r32_m32(DRCTOP, X86REG(rd), MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea <rd>,[<rs> + <rt>]
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
- }
- }
-
- /* only mark it dirty after the exception risk is over */
- compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DIRTY);
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_dadd - compile an add with or without
- overflow
-
- dadd rD,rS,rT
- daddu rD,rS,rT
--------------------------------------------------*/
-
-static int compile_dadd(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions, int immediate)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 destreg = immediate ? RTREG : RDREG;
- mipsreg_state rd, rs, rt;
-
- /* note that we still must perform this operation even if destreg == 0
- in the overflow case */
- if (destreg == 0 && suppress_exceptions)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT64 result = (INT64)CONSTVAL(rs) + (INT64)CONSTVAL(rt);
-
- /* if we overflow, always generate an exception */
- if (!suppress_exceptions && (INT32)result != result)
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
-
- /* else just set the new constant value */
- else if (destreg != 0)
- emit_set_constant_value(drc, compiler, desc, destreg, result);
- }
-
- /* otherwise, handle generically */
- else
- {
- rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST);
-
- /* perform the operating in EAX so we don't trash RTREG if an exception happens */
- if (!suppress_exceptions)
- {
- emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
- if (!ISCONST(rt))
- emit_add_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // add rax,<rt>
- else if (CONSTVAL(rt) != 0)
- emit_add_r64_imm(DRCTOP, REG_RAX, CONSTVAL(rt)); // add rax,<rt>
- oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
- // jo generate_overflow_exception
- if (destreg != 0)
- emit_mov_r64_r64(DRCTOP, X86REG(rd), REG_RAX); // mov <rd>,rax
- }
- else
- {
- if (ISCONST(rs))
- emit_lea_r64_m64(DRCTOP, X86REG(rd), MBD(X86REG(rt), CONSTVAL(rs))); // lea <rd>,[<rt> + <rs>]
- else if (ISCONST(rt))
- emit_lea_r64_m64(DRCTOP, X86REG(rd), MBD(X86REG(rs), CONSTVAL(rt))); // lea <rd>,[<rs> + <rt>]
- else
- emit_lea_r64_m64(DRCTOP, X86REG(rd), MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea <rd>,[<rs> + <rt>]
- }
-
- /* only mark it dirty after the exception risk is over */
- compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DIRTY);
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_sub - compile an add with or without
- overflow
-
- sub rD,rS,rT
- subu rD,rS,rT
--------------------------------------------------*/
-
-static int compile_sub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rd, rs, rt;
-
- /* note that we still must perform this operation even if RDREG == 0
- in the overflow case */
- if (RDREG == 0 && suppress_exceptions)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT64 result = (INT64)CONSTVAL(rs) - (INT64)CONSTVAL(rt);
-
- /* if we overflow, always generate an exception */
- if (!suppress_exceptions && (INT32)result != result)
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
-
- /* else just set the new constant value */
- else if (RDREG != 0)
- emit_set_constant_value(drc, compiler, desc, RDREG, (INT32)result);
- }
-
- /* if rS == rT, the result is 0 */
- else if (RSREG == RTREG)
- {
- if (RDREG != 0)
- emit_set_constant_value(drc, compiler, desc, RDREG, 0);
- }
-
- /* otherwise, handle generically */
- else
- {
- rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST);
-
- /* perform the operating in EAX so we don't trash RTREG if an exception happens */
- if (!suppress_exceptions)
- {
- emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
- if (!ISCONST(rt))
- emit_sub_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // sub eax,<rt>
- else if (CONSTVAL(rt) != 0)
- emit_sub_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rt)); // sub eax,<rt>
- if (!ISCONST(rt) || CONSTVAL(rt) != 0)
- oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
- // jo generate_overflow_exception
- if (RDREG != 0)
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), REG_EAX); // movsxd <rd>,eax
- }
- else
- {
- /* if rD and rT aren't the same, it is pretty basic */
- if (X86REG(rd) != X86REG(rt))
- {
- emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
- if (!ISCONST(rt))
- emit_sub_r32_r32(DRCTOP, X86REG(rd), X86REG(rt)); // sub <rd>,<rt>
- else if (CONSTVAL(rt) != 0)
- emit_sub_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // sub <rd>,<rt>
- }
-
- /* otherwise, we negate rT and add rS */
- else
- {
- emit_neg_r32(DRCTOP, X86REG(rd)); // neg <rd>
- if (!ISCONST(rs))
- emit_add_r32_r32(DRCTOP, X86REG(rd), X86REG(rs)); // add <rd>,<rs>
- else if (CONSTVAL(rs) != 0)
- emit_add_r32_imm(DRCTOP, X86REG(rd), CONSTVAL(rs)); // add <rd>,<rs>
- }
- emit_movsxd_r64_r32(DRCTOP, X86REG(rd), X86REG(rd)); // movsxd <rd>,<rd>
- }
-
- /* only mark it dirty after the exception risk is over */
- compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DIRTY);
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_dsub - compile an add with or without
- overflow
-
- dsub rD,rS,rT
- dsubu rD,rS,rT
--------------------------------------------------*/
-
-static int compile_dsub(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int suppress_exceptions)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rd, rs, rt;
-
- /* note that we still must perform this operation even if RDREG == 0
- in the overflow case */
- if (RDREG == 0 && suppress_exceptions)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT64 result = (INT64)CONSTVAL(rs) - (INT64)CONSTVAL(rt);
-
- /* if we overflow, always generate an exception */
- if (!suppress_exceptions && (INT32)result != result)
- oob_request_callback(drc, COND_NONE, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
-
- /* else just set the new constant value */
- else if (RDREG != 0)
- emit_set_constant_value(drc, compiler, desc, RDREG, result);
- }
-
- /* if rS == rT, the result is 0 */
- else if (RSREG == RTREG)
- {
- if (RDREG != 0)
- emit_set_constant_value(drc, compiler, desc, RDREG, 0);
- }
-
- /* otherwise, handle generically */
- else
- {
- rd = compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DST);
-
- /* perform the operating in EAX so we don't trash RTREG if an exception happens */
- if (!suppress_exceptions)
- {
- emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
- if (!ISCONST(rt))
- emit_sub_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // sub rax,<rt>
- else if (CONSTVAL(rt) != 0)
- emit_sub_r64_imm(DRCTOP, REG_RAX, CONSTVAL(rt)); // sub rax,<rt>
- if (!ISCONST(rt) || CONSTVAL(rt) != 0)
- oob_request_callback(drc, COND_O, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_overflow_exception);
- // jo generate_overflow_exception
- if (RDREG != 0)
- emit_mov_r64_r64(DRCTOP, X86REG(rd), REG_RAX); // mov <rd>,rax
- }
- else
- {
- /* if rD and rT aren't the same, it is pretty basic */
- if (X86REG(rd) != X86REG(rt))
- {
- emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
- if (!ISCONST(rt))
- emit_sub_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // sub <rd>,<rt>
- else if (CONSTVAL(rt) != 0)
- emit_sub_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // sub <rd>,<rt>
- }
-
- /* otherwise, we negate rT and add rS */
- else
- {
- emit_neg_r64(DRCTOP, X86REG(rd)); // neg <rd>
- if (!ISCONST(rs))
- emit_add_r64_r64(DRCTOP, X86REG(rd), X86REG(rs)); // add <rd>,<rs>
- else if (CONSTVAL(rs) != 0)
- emit_add_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rs)); // add <rd>,<rs>
- }
- }
-
- /* only mark it dirty after the exception risk is over */
- compiler_register_allocate(drc, compiler, desc, RDREG, ALLOC_DIRTY);
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_mult - compile a 32-bit multiply
- instruction
-
- mult rS,rT
- multu rS,rT
--------------------------------------------------*/
-
-static int compile_mult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rs, rt, lo, hi;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- UINT64 result = is_unsigned ? ((UINT64)CONSTVAL(rs) * (UINT64)CONSTVAL(rt)) : ((INT64)CONSTVAL(rs) * (INT64)CONSTVAL(rt));
- emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result);
- emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)(result >> 32));
- }
-
- /* otherwise, handle generically */
- else
- {
- UINT8 mulreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
-
- hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
- lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
-
- emit_load_register_value(drc, compiler, REG_EAX, rs); // mov eax,<rs>
- emit_load_register_value(drc, compiler, mulreg, rt); // mov <mulreg>,<rt>
- if (is_unsigned)
- emit_mul_r32(DRCTOP, mulreg); // mul <mulreg>
- else
- emit_imul_r32(DRCTOP, mulreg); // imul <mulreg>
- emit_movsxd_r64_r32(DRCTOP, X86REG(hi), REG_EDX); // movsxd <hireg>,edx
- emit_movsxd_r64_r32(DRCTOP, X86REG(lo), REG_EAX); // movsxd <loreg>,eax
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_dmult - compile a 64-bit multiply
- instruction
-
- dmult rS,rT
- dmultu rS,rT
--------------------------------------------------*/
-
-static int compile_dmult(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rs, rt, lo, hi;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- UINT64 result = is_unsigned ? ((UINT64)CONSTVAL(rs) * (UINT64)CONSTVAL(rt)) : ((INT64)CONSTVAL(rs) * (INT64)CONSTVAL(rt));
- emit_set_constant_value(drc, compiler, desc, REG_LO, (INT64)result);
- emit_set_constant_value(drc, compiler, desc, REG_HI, (INT64)(result >> 63));
- }
-
- /* otherwise, handle generically */
- else
- {
- UINT8 mulreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
-
- hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
- lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
-
- emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
- emit_load_register_value(drc, compiler, mulreg, rt); // mov <mulreg>,<rt>
- if (is_unsigned)
- emit_mul_r64(DRCTOP, mulreg); // mul <mulreg>
- else
- emit_imul_r64(DRCTOP, mulreg); // imul <mulreg>
- emit_mov_r64_r64(DRCTOP, X86REG(hi), REG_RDX); // mov <hi>,rdx
- emit_mov_r64_r64(DRCTOP, X86REG(lo), REG_RAX); // mov <lo>,rax
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_div - compile a 32-bit divide
- instruction
-
- div rS,rT
- divu rS,rT
--------------------------------------------------*/
-
-static int compile_div(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rs, rt, lo, hi;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rT is constant and 0, just skip */
- if (ISCONST(rt) && CONSTVAL(rt) == 0)
- return TRUE;
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- UINT32 result = is_unsigned ? ((UINT32)CONSTVAL(rs) / (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) / (INT32)CONSTVAL(rt));
- UINT32 remainder = is_unsigned ? ((UINT32)CONSTVAL(rs) % (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) % (INT32)CONSTVAL(rt));
-
- emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result);
- emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)remainder);
- }
-
- /* otherwise, handle generically */
- else
- {
- UINT8 divreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
- emit_link skip = { 0 };
-
- hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
- lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
-
- emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
- emit_load_register_value(drc, compiler, divreg, rt); // mov <divreg>,<rt>
- if (!ISCONST(rt))
- {
- emit_test_r32_r32(DRCTOP, divreg, divreg); // test <divreg>,<divreg>
- emit_jcc_short_link(DRCTOP, COND_Z, &skip); // jz skip
- }
- if (is_unsigned)
- {
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_div_r32(DRCTOP, divreg); // div <divreg>
- }
- else
- {
- emit_cdq(DRCTOP); // cdq
- emit_idiv_r32(DRCTOP, divreg); // idiv <divreg>
- }
- emit_movsxd_r64_r32(DRCTOP, X86REG(hi), REG_EDX); // movsxd <hi>,edx
- emit_movsxd_r64_r32(DRCTOP, X86REG(lo), REG_EAX); // movsxd <lo>,eax
- if (!ISCONST(rt))
- resolve_link(DRCTOP, &skip); // skip:
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_ddiv - compile a 64-bit divide
- instruction
-
- ddiv rS,rT
- ddivu rS,rT
--------------------------------------------------*/
-
-static int compile_ddiv(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rs, rt, lo, hi;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rT is constant and 0, just skip */
- if (ISCONST(rt) && CONSTVAL(rt) == 0)
- return TRUE;
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- UINT32 result = is_unsigned ? ((UINT32)CONSTVAL(rs) / (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) / (INT32)CONSTVAL(rt));
- UINT32 remainder = is_unsigned ? ((UINT32)CONSTVAL(rs) % (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) % (INT32)CONSTVAL(rt));
-
- emit_set_constant_value(drc, compiler, desc, REG_LO, (INT32)result);
- emit_set_constant_value(drc, compiler, desc, REG_HI, (INT32)remainder);
- }
-
- /* if one is a constant, load the constant into EAX and multiple from there */
- else
- {
- UINT8 divreg = ISCONST(rt) ? REG_ECX : X86REG(rt);
- emit_link skip = { 0 };
-
- hi = compiler_register_allocate(drc, compiler, desc, REG_HI, ALLOC_DST | ALLOC_DIRTY);
- lo = compiler_register_allocate(drc, compiler, desc, REG_LO, ALLOC_DST | ALLOC_DIRTY);
-
- emit_load_register_value(drc, compiler, REG_RAX, rs); // mov rax,<rs>
- emit_load_register_value(drc, compiler, divreg, rt); // mov <divreg>,<rt>
- emit_test_r64_r64(DRCTOP, divreg, divreg); // test <divreg>,<divreg>
- emit_jcc_short_link(DRCTOP, COND_Z, &skip); // jz skip
- if (is_unsigned)
- {
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_div_r64(DRCTOP, divreg); // div <divreg>
- }
- else
- {
- emit_cqo(DRCTOP); // cqo
- emit_idiv_r64(DRCTOP, divreg); // idiv <divreg>
- }
- emit_mov_r64_r64(DRCTOP, X86REG(hi), REG_EDX); // mov <hi>,edx
- emit_mov_r64_r64(DRCTOP, X86REG(lo), REG_EAX); // mov <loreg>,eax
- resolve_link(DRCTOP, &skip); // skip:
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_logical - compile a logical
- operation between two registers
-
- 0: and rD,rS,rT / and rT,rS,UIMM
- 1: or rD,rS,rT / or rT,rS,UIMM
- 2: xor rD,rS,rT / xor rT,rS,UIMM
- 3: nor rD,rS,rT
--------------------------------------------------*/
-
-static int compile_logical(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int operation, int immediate)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 destreg = immediate ? RTREG : RDREG;
- mipsreg_state rd, rs, rt;
-
- assert(operation >= 0 && operation <= 3);
- assert(!immediate || operation != 3);
-
- /* if the destination is r0, bail */
- if (destreg == 0)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = immediate ? MAKE_CONST(UIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if both constant, we know the answer up front */
- if (ISCONST(rs) && ISCONST(rt))
- {
- UINT64 result = (operation == 0) ? (CONSTVAL(rs) & CONSTVAL(rt)) : (operation == 1) ? (CONSTVAL(rs) | CONSTVAL(rt)) : (operation == 2) ? (CONSTVAL(rs) ^ CONSTVAL(rt)) : ~(CONSTVAL(rs) | CONSTVAL(rt));
- emit_set_constant_value(drc, compiler, desc, destreg, result);
- }
-
- /* an AND against 0 is constant as well */
- else if (operation == 0 && ISCONST(rt) && CONSTVAL(rt) == 0)
- emit_set_constant_value(drc, compiler, desc, destreg, 0);
-
- /* else do the operation in code */
- else
- {
- rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST | ALLOC_DIRTY);
-
- /* if rD matches rT, or if rS is const and rT isn't, then swap rT and rS */
- if (X86REG(rd) == X86REG(rt) || (ISCONST(rs) && !ISCONST(rt)))
- {
- mipsreg_state temp = rs;
- rs = rt;
- rt = temp;
- }
-
- /* load rS into rD */
- emit_load_register_value(drc, compiler, X86REG(rd), rs); // mov <rd>,<rs>
-
- /* if rD does not match rT, we can work directly in rD */
- if (!ISCONST(rt))
- {
- if (operation == 0)
- emit_and_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // and <rd>,<rt>
- else if (operation == 1)
- emit_or_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // or <rd>,<rt>
- else if (operation == 2)
- emit_xor_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // xor <rd>,<rt>
- else if (operation == 3)
- {
- emit_or_r64_r64(DRCTOP, X86REG(rd), X86REG(rt)); // or <rd>,<rt>
- emit_not_r64(DRCTOP, X86REG(rd)); // not <rd>
- }
- }
- else
- {
- if (operation == 0)
- emit_and_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // and <rd>,CONSTVAL(rt)
- else if (operation == 1 && CONSTVAL(rt) != 0)
- emit_or_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // or <rd>,CONSTVAL(rt)
- else if (operation == 2 && CONSTVAL(rt) != 0)
- emit_xor_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // xor <rd>,CONSTVAL(rt)
- else if (operation == 3)
- {
- if (CONSTVAL(rt) != 0)
- emit_or_r64_imm(DRCTOP, X86REG(rd), CONSTVAL(rt)); // or <rd>,CONSTVAL(rt)
- emit_not_r64(DRCTOP, X86REG(rd)); // not <rd>
- }
- }
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_slt - compile a set if less
- than btween two registers
-
- slti rD,rS,rT / slti rT,rS,SIMM
- sltiu rD,rS,rT / sltiu rT,rS,SIMM
--------------------------------------------------*/
-
-static int compile_slt(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_unsigned, int immediate)
-{
- UINT32 op = *desc->opptr.l;
- UINT8 destreg = immediate ? RTREG : RDREG;
- mipsreg_state rd, rs, rt;
-
- /* if the destination is r0, bail */
- if (destreg == 0)
- return TRUE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = immediate ? MAKE_CONST(SIMMVAL) : compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if the source is constant, compute as constant */
- if (ISCONST(rs) && ISCONST(rt))
- {
- INT64 result = is_unsigned ? ((UINT32)CONSTVAL(rs) < (UINT32)CONSTVAL(rt)) : ((INT32)CONSTVAL(rs) < (INT32)CONSTVAL(rt));
- emit_set_constant_value(drc, compiler, desc, destreg, result);
- }
-
- /* else do the operation in code */
- else
- {
- UINT8 rsreg = ISCONST(rs) ? REG_RAX : X86REG(rs);
-
- rd = compiler_register_allocate(drc, compiler, desc, destreg, ALLOC_DST | ALLOC_DIRTY);
-
- emit_load_register_value(drc, compiler, rsreg, rs); // mov <rsreg>,<rs>
- if (ISCONST(rt))
- emit_cmp_r64_imm(DRCTOP, rsreg, CONSTVAL(rt)); // cmp <rsreg>,<rt>
- else
- emit_cmp_r64_r64(DRCTOP, rsreg, X86REG(rt)); // cmp <rsreg>,<rt>
- emit_setcc_r8(DRCTOP, is_unsigned ? COND_B : COND_L, X86REG(rd)); // setb/l <rd>
- emit_movzx_r32_r8(DRCTOP, X86REG(rd), X86REG(rd)); // movzx <rd>,<rd>
- }
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_load - compile a memory load
- instruction
-
- lb rT,SIMM(rS)
- lbu rT,SIMM(rS)
- lh rT,SIMM(rS)
- lhu rT,SIMM(rS)
- lw rT,SIMM(rS)
- lwu rT,SIMM(rS)
- ld rT,SIMM(rS)
--------------------------------------------------*/
-
-static int compile_load(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, int is_unsigned)
-{
- UINT32 op = *desc->opptr.l;
- mipsreg_state rs, rt;
- int was_fixed = FALSE;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DST);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
- {
- UINT8 destreg = (RTREG == 0) ? REG_RAX : X86REG(rt);
-
- /* perform a fixed read if we can */
- if (size == 1)
- was_fixed = emit_fixed_byte_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL);
- else if (size == 2)
- was_fixed = emit_fixed_half_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL);
- else if (size == 4)
- was_fixed = emit_fixed_word_read(drc, compiler, desc, destreg, is_unsigned, CONSTVAL(rs) + SIMMVAL, 0xffffffff);
- else
- was_fixed = emit_fixed_double_read(drc, compiler, desc, destreg, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff));
- }
-
- /* otherwise, we just need to call the appropriate subroutine */
- else
- {
- if (ISCONST(rs))
- emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
- else
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
- if (size == 1 && is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_byte_unsigned); // call general.read_byte_unsigned
- else if (size == 1 && !is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_byte_signed); // call general.read_byte_signed
- else if (size == 2 && is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_half_unsigned); // call general.read_half_unsigned
- else if (size == 2 && !is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_half_signed); // call general.read_half_signed
- else if (size == 4 && is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned
- else if (size == 4 && !is_unsigned)
- emit_call(DRCTOP, mips3.drcdata->general.read_word_signed); // call general.read_word_signed
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- if (RTREG != 0)
- emit_mov_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // mov <rt>,rax
- }
-
- /* only mark dirty after the exception risk is over */
- compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_DIRTY);
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_load_cop - compile a COP memory load
- instruction
-
- lwc1 rT,SIMM(rs)
- lwc2 rT,SIMM(rs)
- ldc1 rT,SIMM(rs)
- ldc2 rT,SIMM(rs)
--------------------------------------------------*/
-
-static int compile_load_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
- {
- /* perform a fixed read if we can */
- if (size == 4)
- was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, CONSTVAL(rs) + SIMMVAL, 0xffffffff);
- else
- was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff));
- }
-
- /* otherwise, we just need to call the appropriate subroutine */
- else
- {
- if (ISCONST(rs))
- emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
- else
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
- if (size == 4)
- emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- }
-
- /* complete the load by moving to the destination address */
- if (size == 4)
- emit_mov_m32_r32(DRCTOP, MDRC(dest), REG_EAX); // mov [dest],eax
- else
- emit_mov_m64_r64(DRCTOP, MDRC(dest), REG_RAX); // mov [dest],rax
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_loadx_cop - compile a COP indexed
- memory load instruction
-
- lwxc1 fD,rS,rT
- ldxc1 fD,rS,rT
--------------------------------------------------*/
-
-static int compile_loadx_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *dest)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && ISCONST(rt) && !DISABLE_FIXED_RAM_LOAD)
- {
- /* perform a fixed read if we can */
- if (size == 4)
- was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, CONSTVAL(rs) + CONSTVAL(rt), 0xffffffff);
- else
- was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, CONSTVAL(rs) + CONSTVAL(rt), U64(0xffffffffffffffff));
- }
-
- /* otherwise, we just need to call the appropriate subroutine */
- else
- {
- if (ISCONST(rs) && ISCONST(rt))
- emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + CONSTVAL(rt)); // mov p1,<rs> + <rt>
- else if (ISCONST(rs))
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rt), CONSTVAL(rs))); // lea p1,[<rt> + <rs>]
- else if (ISCONST(rt))
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), CONSTVAL(rt))); // lea p1,[<rs> + <rt>]
- else
- emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea p1,[<rs> + <rt>]
- if (size == 4)
- emit_call(DRCTOP, mips3.drcdata->general.read_word_unsigned); // call general.read_word_unsigned
- else
- emit_call(DRCTOP, mips3.drcdata->general.read_double); // call general.read_double
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
- }
-
- /* complete the load by moving to the destination address */
- if (size == 4)
- emit_mov_m32_r32(DRCTOP, MDRC(dest), REG_EAX); // mov [dest],eax
- else
- emit_mov_m64_r64(DRCTOP, MDRC(dest), REG_RAX); // mov [dest],rax
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_load_word_partial - compile a lwl/lwr
- instruction
-
- lwl rT,SIMM(rS)
- lwr rT,SIMM(rS)
--------------------------------------------------*/
-
-static int compile_load_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source/dest registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
- {
- INT32 addr = CONSTVAL(rs) + SIMMVAL;
- int shift = (addr & 3) * 8;
-
- /* shift the opposite amount depending on right/left and endianness */
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- shift ^= 0x18;
-
- /* read the double value into rax, handling exceptions */
- was_fixed = emit_fixed_word_read(drc, compiler, desc, REG_RAX, FALSE, addr, is_right ? ((UINT32)-1 << shift) : ((UINT32)-1 >> shift));
-
- /* handle writing back the register */
- if (RTREG != 0)
- {
- UINT32 mask = is_right ? (~((UINT32)-1 >> shift)) : (~((UINT32)-1 << shift));
-
- /* AND rT with the mask */
- emit_and_r32_imm(DRCTOP, X86REG(rt), mask); // and <rt>,mask
-
- /* shift and merge rax into the X86REG(rt) */
- if (!is_right)
- emit_shl_r32_imm(DRCTOP, REG_EAX, shift); // shl eax,shift
- else
- emit_shr_r32_imm(DRCTOP, REG_EAX, shift); // shr eax,shift
- emit_or_r32_r32(DRCTOP, X86REG(rt), REG_EAX); // or <rtdst>,eax
- emit_movsxd_r64_r32(DRCTOP, X86REG(rt), X86REG(rt)); // movsxd <rt>,<rt>
- }
- }
-
- /* otherwise, we need to compute everything at runtime */
- else
- {
- /* compute the address and mask values */
- if (ISCONST(rs))
- emit_mov_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rs) + SIMMVAL); // mov eax,<rs> + SIMMVAL
- else
- emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
- emit_or_r32_imm(DRCTOP, REG_P2, -1); // or p2,-1
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
- emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
- if (!is_right)
- emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl
- else
- emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl
- emit_mov_m8_r8(DRCTOP, MBD(REG_RSP, SPOFFS_SAVECL), REG_CL); // mov [sp+savecl],cl
- emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
- emit_call(DRCTOP, mips3.drcdata->general.read_word_masked); // call general.read_word_masked
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
-
- /* handle writing back the register */
- if (RTREG != 0)
- {
- /* recompute the mask */
- emit_mov_r8_m8(DRCTOP, REG_CL, MBD(REG_RSP, SPOFFS_SAVECL)); // mov cl,[sp+savecl]
- emit_or_r32_imm(DRCTOP, REG_P2, -1); // or p2,-1
- if (!is_right)
- emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl
- else
- emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl
-
- /* apply the shifts and masks */
- emit_not_r32(DRCTOP, REG_P2); // not p2
- if (!is_right)
- emit_shl_r32_cl(DRCTOP, REG_RAX); // shl rax,cl
- else
- emit_shr_r32_cl(DRCTOP, REG_RAX); // shr rax,cl
- emit_and_r32_r32(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2
- emit_or_r32_r32(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax
- emit_movsxd_r64_r32(DRCTOP, X86REG(rt), X86REG(rt)); // movsxd <rt>,<rt>
- }
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_load_double_partial - compile a
- ldl/ldr instruction
-
- ldl rT,SIMM(rS)
- ldr rT,SIMM(rS)
--------------------------------------------------*/
-
-static int compile_load_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source/dest registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC | ALLOC_DST | ALLOC_DIRTY);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_LOAD)
- {
- INT32 addr = CONSTVAL(rs) + SIMMVAL;
- int shift = (addr & 7) * 8;
-
- /* shift the opposite amount depending on right/left and endianness */
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- shift ^= 0x38;
-
- /* read the double value into rax, handling exceptions */
- was_fixed = emit_fixed_double_read(drc, compiler, desc, REG_RAX, addr, is_right ? ((UINT64)-1 << shift) : ((UINT64)-1 >> shift));
-
- /* handle writing back the register */
- if (RTREG != 0)
- {
- UINT64 mask = is_right ? (~((UINT64)-1 >> shift)) : (~((UINT64)-1 << shift));
-
- /* AND rT with the mask, using 32 bits if we can */
- if ((INT32)mask == (INT64)mask)
- emit_and_r64_imm(DRCTOP, X86REG(rt), (INT32)mask); // and <rt>,mask
- else
- {
- emit_mov_r64_imm(DRCTOP, REG_P2, mask); // mov p2,mask
- emit_and_r64_r64(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2
- }
-
- /* shift and merge rax into the X86REG(rt) */
- if (!is_right)
- emit_shl_r64_imm(DRCTOP, REG_RAX, shift); // shl rax,shift
- else
- emit_shr_r64_imm(DRCTOP, REG_RAX, shift); // shr rax,shift
- emit_or_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax
- }
- }
-
- /* otherwise, we need to compute everything at runtime */
- else
- {
- /* compute the address and mask values */
- if (ISCONST(rs))
- emit_mov_r32_imm(DRCTOP, REG_EAX, CONSTVAL(rs) + SIMMVAL); // mov eax,<rs> + SIMMVAL
- else
- emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
- emit_or_r64_imm(DRCTOP, REG_P2, -1); // or p2,-1
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x38); // xor ecx,0x38
- emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
- if (!is_right)
- emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl
- else
- emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl
- emit_mov_m8_r8(DRCTOP, MBD(REG_RSP, SPOFFS_SAVECL), REG_CL); // mov [sp+savecl],cl
- emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
- emit_call(DRCTOP, mips3.drcdata->general.read_double_masked); // call general.read_double_masked
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbload_exception);
-
- /* handle writing back the register */
- if (RTREG != 0)
- {
- /* recompute the mask */
- emit_mov_r8_m8(DRCTOP, REG_CL, MBD(REG_RSP, SPOFFS_SAVECL)); // mov cl,[sp+savecl]
- emit_or_r64_imm(DRCTOP, REG_P2, -1); // or p2,-1
- if (!is_right)
- emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl
- else
- emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl
-
- /* apply the shifts and masks */
- emit_not_r64(DRCTOP, REG_P2); // not p2
- if (!is_right)
- emit_shl_r64_cl(DRCTOP, REG_RAX); // shl rax,cl
- else
- emit_shr_r64_cl(DRCTOP, REG_RAX); // shr rax,cl
- emit_and_r64_r64(DRCTOP, X86REG(rt), REG_P2); // and <rt>,p2
- emit_or_r64_r64(DRCTOP, X86REG(rt), REG_RAX); // or <rt>,rax
- }
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_store - compile a memory store
- instruction
-
- sb rT,SIMM(rS)
- sh rT,SIMM(rS)
- sw rT,SIMM(rS)
- sd rT,SIMM(rS)
--------------------------------------------------*/
-
-static int compile_store(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
- {
- /* perform a fixed write if we can */
- if (size == 1)
- was_fixed = emit_fixed_byte_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL);
- else if (size == 2)
- was_fixed = emit_fixed_half_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL);
- else if (size == 4)
- was_fixed = emit_fixed_word_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL, 0xffffffff);
- else
- was_fixed = emit_fixed_double_write(drc, compiler, desc, rt, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff));
- }
-
- /* otherwise, we just need to call the appropriate subroutine */
- else
- {
- if (ISCONST(rs))
- emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
- else
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
- emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt>
- if (size == 1)
- emit_call(DRCTOP, mips3.drcdata->general.write_byte); // call general.write_byte
- else if (size == 2)
- emit_call(DRCTOP, mips3.drcdata->general.write_half); // call general.write_half
- else if (size == 4)
- emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word
- else if (size == 8)
- emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_store_cop - compile a COP memory
- store instruction
-
- swc1 rT,SIMM(rs)
- swc2 rT,SIMM(rs)
- sdc1 rT,SIMM(rs)
- sdc2 rT,SIMM(rs)
--------------------------------------------------*/
-
-static int compile_store_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
-
- /* load the value into P2 */
- if (size == 4)
- emit_mov_r32_m32(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
- else
- emit_mov_r64_m64(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
- {
- /* perform a fixed write if we can */
- if (size == 4)
- was_fixed = emit_fixed_word_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + SIMMVAL, 0xffffffff);
- else
- was_fixed = emit_fixed_double_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + SIMMVAL, U64(0xffffffffffffffff));
- }
-
- /* otherwise, we just need to call the appropriate subroutine */
- else
- {
- if (ISCONST(rs))
- emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + SIMMVAL); // mov p1,<rs> + SIMMVAL
- else
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), SIMMVAL)); // lea p1,[<rs> + SIMMVAL]
- if (size == 4)
- emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word
- else if (size == 8)
- emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_storex_cop - compile a COP indexed
- memory store instruction
-
- swxc1 fD,rS,rT
- sdxc1 fD,rS,rT
--------------------------------------------------*/
-
-static int compile_storex_cop(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int size, void *src)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* load the value into P2 */
- if (size == 4)
- emit_mov_r32_m32(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
- else
- emit_mov_r64_m64(DRCTOP, REG_P2, MDRC(src)); // mov p2,[src]
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && ISCONST(rt) && !DISABLE_FIXED_RAM_STORE)
- {
- /* perform a fixed write if we can */
- if (size == 4)
- was_fixed = emit_fixed_word_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + CONSTVAL(rt), 0xffffffff);
- else
- was_fixed = emit_fixed_double_write(drc, compiler, desc, REG_P2, CONSTVAL(rs) + CONSTVAL(rt), U64(0xffffffffffffffff));
- }
-
- /* otherwise, we just need to call the appropriate subroutine */
- else
- {
- if (ISCONST(rs) && ISCONST(rt))
- emit_mov_r32_imm(DRCTOP, REG_P1, CONSTVAL(rs) + CONSTVAL(rt)); // mov p1,<rs> + <rt>
- else if (ISCONST(rs))
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rt), CONSTVAL(rs))); // lea p1,[<rt> + <rs>]
- else if (ISCONST(rt))
- emit_lea_r32_m32(DRCTOP, REG_P1, MBD(X86REG(rs), CONSTVAL(rt))); // lea p1,[<rs> + <rt>]
- else
- emit_lea_r32_m32(DRCTOP, REG_P1, MBISD(X86REG(rs), X86REG(rt), 1, 0)); // lea p1,[<rs> + <rt>]
- if (size == 4)
- emit_call(DRCTOP, mips3.drcdata->general.write_word); // call general.write_word
- else if (size == 8)
- emit_call(DRCTOP, mips3.drcdata->general.write_double); // call general.write_double
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_store_word_partial - compile a swl/swr
- instruction
-
- swl rT,SIMM(rS)
- swr rT,SIMM(rS)
--------------------------------------------------*/
-
-static int compile_store_word_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
- {
- INT32 addr = CONSTVAL(rs) + SIMMVAL;
- int shift = (addr & 3) * 8;
- UINT32 mask;
-
- /* shift the opposite amount depending on right/left and endianness */
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- shift ^= 0x18;
-
- /* if rT is not constant, load and shift it */
- if (!ISCONST(rt))
- {
- emit_mov_r32_r32(DRCTOP, REG_EAX, X86REG(rt)); // mov eax,X86REG(rt)
- emit_shr_r32_imm(DRCTOP, REG_EAX, shift); // shr eax,shift
- rt = MAKE_DESTREG(REG_EAX);
- }
-
- /* compute shifted value and mask */
- if (!is_right)
- {
- if (ISCONST(rt))
- rt = MAKE_CONST((UINT32)CONSTVAL(rt) >> shift);
- mask = (UINT32)-1 >> shift;
- }
- else
- {
- if (ISCONST(rt))
- rt = MAKE_CONST((UINT32)CONSTVAL(rt) << shift);
- mask = (UINT32)-1 << shift;
- }
-
- /* perform a fixed write */
- was_fixed = emit_fixed_word_write(drc, compiler, desc, rt, addr & ~3, mask);
- }
-
- /* otherwise, we need to compute everything at runtime */
- else
- {
- /* compute the address and mask values */
- emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
- emit_or_r32_imm(DRCTOP, REG_P3, -1); // or p3,-1
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
- emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt>
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
- emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
- if (!is_right)
- {
- emit_shr_r32_cl(DRCTOP, REG_P3); // shr p3,cl
- emit_shr_r32_cl(DRCTOP, REG_P2); // shr p2,cl
- }
- else
- {
- emit_shl_r32_cl(DRCTOP, REG_P3); // shl p3,cl
- emit_shl_r32_cl(DRCTOP, REG_P2); // shl p2,cl
- }
- emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
-
- /* perform the write */
- emit_call(DRCTOP, mips3.drcdata->general.write_word_masked); // call general.write_word_masked
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- compile_store_double_partial - compile a
- sdl/sdr instruction
-
- sdl rT,SIMM(rS)
- sdr rT,SIMM(rS)
--------------------------------------------------*/
-
-static int compile_store_double_partial(drc_core *drc, compiler_state *compiler, const opcode_desc *desc, int is_right)
-{
- UINT32 op = *desc->opptr.l;
- int was_fixed = FALSE;
- mipsreg_state rs, rt;
-
- /* allocate source registers */
- rs = compiler_register_allocate(drc, compiler, desc, RSREG, ALLOC_SRC);
- rt = compiler_register_allocate(drc, compiler, desc, RTREG, ALLOC_SRC);
-
- /* if rS is constant, we know the address at compile time; this simplifies the code */
- if (ISCONST(rs) && !DISABLE_FIXED_RAM_STORE)
- {
- INT32 addr = CONSTVAL(rs) + SIMMVAL;
- int shift = (addr & 7) * 8;
- UINT64 mask;
-
- /* shift the opposite amount depending on right/left and endianness */
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- shift ^= 0x38;
-
- /* if rT is not constant, load and shift it */
- if (!ISCONST(rt))
- {
- emit_mov_r64_r64(DRCTOP, REG_RAX, X86REG(rt)); // mov rax,X86REG(rt)
- emit_shr_r64_imm(DRCTOP, REG_RAX, shift); // shr rax,shift
- rt = MAKE_DESTREG(REG_RAX);
- }
-
- /* compute shifted value and mask */
- if (!is_right)
- {
- if (ISCONST(rt))
- rt = MAKE_CONST((UINT64)CONSTVAL(rt) >> shift);
- mask = (UINT64)-1 >> shift;
- }
- else
- {
- if (ISCONST(rt))
- rt = MAKE_CONST((UINT64)CONSTVAL(rt) << shift);
- mask = (UINT64)-1 << shift;
- }
-
- /* perform a fixed write */
- was_fixed = emit_fixed_double_write(drc, compiler, desc, rt, addr & ~7, mask);
- }
-
- /* otherwise, we need to compute everything at runtime */
- else
- {
- /* compute the address and mask values */
- emit_lea_r32_m32(DRCTOP, REG_EAX, MBD(X86REG(rs), SIMMVAL)); // lea eax,[<rs> + SIMMVAL]
- emit_or_r64_imm(DRCTOP, REG_P3, -1); // or p3,-1
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_RAX, 8, 0)); // lea ecx,[rax*8]
- emit_load_register_value(drc, compiler, REG_P2, rt); // mov p2,<rt>
- if ((!mips3.core->bigendian && !is_right) || (mips3.core->bigendian && is_right))
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x38); // xor ecx,0x38
- emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
- if (!is_right)
- {
- emit_shr_r64_cl(DRCTOP, REG_P3); // shr p3,cl
- emit_shr_r64_cl(DRCTOP, REG_P2); // shr p2,cl
- }
- else
- {
- emit_shl_r64_cl(DRCTOP, REG_P3); // shl p3,cl
- emit_shl_r64_cl(DRCTOP, REG_P2); // shl p2,cl
- }
- emit_mov_r32_r32(DRCTOP, REG_P1, REG_EAX); // mov p1,eax
-
- /* perform the write */
- emit_call(DRCTOP, mips3.drcdata->general.write_double_masked); // call general.write_double_masked
- oob_request_callback(drc, COND_NO_JUMP, oob_exception_cleanup, compiler, desc, mips3.drcdata->generate_tlbstore_exception);
- }
-
- /* update cycle counts */
- if (!was_fixed)
- emit_update_cycles_pc_and_flush(drc, compiler, desc, 0);
- return TRUE;
-}
diff --git a/src/emu/cpu/mips/mdrcold.c b/src/emu/cpu/mips/mdrcold.c
deleted file mode 100644
index e00aa1eece8..00000000000
--- a/src/emu/cpu/mips/mdrcold.c
+++ /dev/null
@@ -1,4872 +0,0 @@
-
-
-/***************************************************************************
- CONFIGURATION
-***************************************************************************/
-
-#define STRIP_NOPS 1 /* 1 is faster */
-#define USE_SSE 0 /* can't tell any speed difference here */
-
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define MAX_INSTRUCTIONS ((512 + 128) / 4)
-
-/* recompiler flags */
-#define RECOMPILE_UNIMPLEMENTED 0x0000
-#define RECOMPILE_SUCCESSFUL 0x0001
-#define RECOMPILE_SUCCESSFUL_CP(c,p) (RECOMPILE_SUCCESSFUL | (((c) & 0xfff) << 8) | (((p) & 0xfff) << 20))
-#define RECOMPILE_MAY_CAUSE_EXCEPTION 0x0002
-#define RECOMPILE_END_OF_STRING 0x0004
-#define RECOMPILE_CHECK_INTERRUPTS 0x0008
-#define RECOMPILE_CHECK_SW_INTERRUPTS 0x0010
-#define RECOMPILE_ADD_DISPATCH 0x0020
-
-/* append_readwrite flags */
-#define ARW_READ 0x0000
-#define ARW_WRITE 0x0001
-#define ARW_UNSIGNED 0x0000
-#define ARW_SIGNED 0x0002
-#define ARW_MASKED 0x0004
-
-
-
-/***************************************************************************
- MACROS
-***************************************************************************/
-
-#define REGDISP(reg) (offsetof(mips3_state, r[reg]) - offsetof(mips3_state, r[17]))
-#define REGADDR(reg) MBD(REG_ESI, REGDISP(reg))
-#define REGADDRLO(reg) MBD(REG_ESI, REGDISP(reg))
-#define REGADDRHI(reg) MBD(REG_ESI, REGDISP(reg)+4)
-
-#define HIADDR REGADDR(REG_HI)
-#define HIADDRLO REGADDRLO(REG_HI)
-#define HIADDRHI REGADDRHI(REG_HI)
-
-#define LOADDR REGADDR(REG_LO)
-#define LOADDRLO REGADDRLO(REG_LO)
-#define LOADDRHI REGADDRHI(REG_LO)
-
-#define CPR0ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg])
-#define CPR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg])
-#define CPR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg] + 4)
-
-#define CCR0ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg])
-#define CCR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg])
-#define CCR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg] + 4)
-
-#define CPR1ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg])
-#define CPR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg])
-#define CPR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg] + 4)
-
-#define CCR1ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg])
-#define CCR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg])
-#define CCR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg] + 4)
-
-#define CPR2ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg])
-#define CPR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg])
-#define CPR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg] + 4)
-
-#define CCR2ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg])
-#define CCR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg])
-#define CCR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg] + 4)
-
-#define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg])
-#define FPR32ADDR(reg) MABS(FPR32(reg))
-#define FPR32ADDRLO(reg) MABS(FPR32(reg))
-#define FPR32ADDRHI(reg) MABS((UINT8 *)FPR32(reg) + 4)
-
-#define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg])
-#define FPR64ADDR(reg) MABS(FPR64(reg))
-#define FPR64ADDR(reg) MABS(FPR64(reg))
-#define FPR64ADDRLO(reg) MABS(FPR64(reg))
-#define FPR64ADDRHI(reg) MABS((UINT8 *)FPR64(reg) + 4)
-
-#define CF1ADDR(which) MABS(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)])
-
-#define ICOUNTADDR MABS(&mips3.core->icount)
-
-
-/***************************************************************************
- USEFUL PRIMITIVES
-***************************************************************************/
-
-INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 reghi, UINT8 reglo, DECLARE_MEMPARAMS)
-{
- emit_mov_r32_m32(emitptr, reglo, MEMPARAMS);
- emit_mov_r32_m32(emitptr, reghi, base, index, scale, disp+4);
-}
-
-INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 reghi, UINT8 reglo)
-{
- emit_mov_m32_r32(emitptr, MEMPARAMS, reglo);
- emit_mov_m32_r32(emitptr, base, index, scale, disp+4, reghi);
-}
-
-INLINE void emit_mov_m64_imm32(x86code **emitptr, DECLARE_MEMPARAMS, INT32 imm)
-{
- emit_mov_m32_imm(emitptr, MEMPARAMS, imm);
- emit_mov_m32_imm(emitptr, base, index, scale, disp+4, (INT32)imm >> 31);
-}
-
-INLINE void emit_zero_m64(x86code **emitptr, DECLARE_MEMPARAMS)
-{
- if (USE_SSE)
- {
- emit_xorpd_r128_r128(emitptr, REG_XMM0, REG_XMM0);
- emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0);
- }
- else
- emit_mov_m64_imm32(emitptr, MEMPARAMS, 0);
-}
-
-INLINE void emit_mov_m64_m64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 base2, UINT8 index2, UINT8 scale2, INT32 disp2)
-{
- if (USE_SSE)
- {
- emit_movsd_r128_m64(emitptr, REG_XMM0, base2, index2, scale2, disp2);
- emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0);
- }
- else
- {
- emit_mov_r64_m64(emitptr, REG_EDX, REG_EAX, base2, index2, scale2, disp2);
- emit_mov_m64_r64(emitptr, MEMPARAMS, REG_EDX, REG_EAX);
- }
-}
-
-#define emit_save_pc_before_call(e) \
-do { \
- if (mips3.drcoptions & MIPS3DRC_FLUSH_PC) \
- emit_mov_m32_r32(e, MABS(drc->pcptr), REG_EDI); \
-} while (0)
-
-
-
-
-/***************************************************************************
- TYPEDEFS
-***************************************************************************/
-
-struct _mips3drc_data
-{
- x86code * generate_interrupt_exception;
- x86code * generate_cop_exception;
- x86code * generate_overflow_exception;
- x86code * generate_invalidop_exception;
- x86code * generate_syscall_exception;
- x86code * generate_break_exception;
- x86code * generate_trap_exception;
- x86code * generate_tlbload_exception;
- x86code * generate_tlbstore_exception;
- x86code * handle_pc_tlb_mismatch;
- x86code * read_and_translate_byte_signed;
- x86code * read_and_translate_byte_unsigned;
- x86code * read_and_translate_half_signed;
- x86code * read_and_translate_half_unsigned;
- x86code * read_and_translate_word;
- x86code * read_and_translate_word_masked;
- x86code * read_and_translate_double;
- x86code * read_and_translate_double_masked;
- x86code * write_and_translate_byte;
- x86code * write_and_translate_half;
- x86code * write_and_translate_word;
- x86code * write_and_translate_word_masked;
- x86code * write_and_translate_double;
- x86code * write_and_translate_double_masked;
-};
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-static void drc_reset_callback(drc_core *drc);
-static void drc_recompile_callback(drc_core *drc);
-static void drc_entrygen_callback(drc_core *drc);
-
-static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc);
-
-static void append_generate_exception(drc_core *drc, UINT8 exception);
-static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags);
-static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target);
-static void append_update_cycle_counting(drc_core *drc);
-static void append_check_interrupts(drc_core *drc, int inline_generate);
-static void append_check_sw_interrupts(drc_core *drc, int inline_generate);
-
-static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc);
-static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op);
-static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op);
-
-static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op);
-static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op);
-static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op);
-
-
-
-/***************************************************************************
- PRIVATE GLOBAL VARIABLES
-***************************************************************************/
-
-static UINT64 dmult_temp1;
-static UINT64 dmult_temp2;
-static UINT32 jr_temp;
-
-static UINT8 in_delay_slot = 0;
-
-
-
-/***************************************************************************
- CORE RECOMPILER SYSTEMS
-***************************************************************************/
-
-/*-------------------------------------------------
- mips3drc_init - initialize the drc-specific
- state
--------------------------------------------------*/
-
-static void mips3drc_init(void)
-{
- drc_config drconfig;
-
- /* fill in the config */
- memset(&drconfig, 0, sizeof(drconfig));
- drconfig.cache_base = mips3.cache;
- drconfig.cache_size = CACHE_SIZE;
- drconfig.max_instructions = MAX_INSTRUCTIONS;
- drconfig.address_bits = 32;
- drconfig.lsbs_to_ignore = 2;
- drconfig.uses_fp = 1;
- drconfig.uses_sse = USE_SSE;
- drconfig.pc_in_memory = 0;
- drconfig.icount_in_memory = 0;
- drconfig.pcptr = (UINT32 *)&mips3.core->pc;
- drconfig.icountptr = (UINT32 *)&mips3.core->icount;
- drconfig.esiptr = NULL;
- drconfig.cb_reset = drc_reset_callback;
- drconfig.cb_recompile = drc_recompile_callback;
- drconfig.cb_entrygen = drc_entrygen_callback;
-
- /* initialize the compiler */
- mips3.drc = drc_init(cpu_getactivecpu(), &drconfig);
- mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS;
-
- /* allocate our data out of the cache */
- mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata));
- memset(mips3.drcdata, 0, sizeof(*mips3.drcdata));
-}
-
-
-/*-------------------------------------------------
- mips3drc_exit - clean up the drc-specific
- state
--------------------------------------------------*/
-
-static void mips3drc_exit(void)
-{
- drc_exit(mips3.drc);
-}
-
-
-
-/***************************************************************************
- RECOMPILER CALLBACKS
-***************************************************************************/
-
-/*------------------------------------------------------------------
- drc_reset_callback
-------------------------------------------------------------------*/
-
-static void drc_reset_callback(drc_core *drc)
-{
- if (LOG_CODE)
- {
- x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->out_of_cycles);
- x86log_disasm_code_range(mips3.log, "out_of_cycles:", drc->out_of_cycles, drc->recompile);
- x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch);
- x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush);
- x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top);
- }
-
- mips3.drcdata->generate_interrupt_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_INTERRUPT);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top);
-
- mips3.drcdata->generate_cop_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_BADCOP);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top);
-
- mips3.drcdata->generate_overflow_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_OVERFLOW);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top);
-
- mips3.drcdata->generate_invalidop_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_INVALIDOP);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top);
-
- mips3.drcdata->generate_syscall_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_SYSCALL);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top);
-
- mips3.drcdata->generate_break_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_BREAK);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top);
-
- mips3.drcdata->generate_trap_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_TRAP);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top);
-
- mips3.drcdata->generate_tlbload_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_TLBLOAD);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top);
-
- mips3.drcdata->generate_tlbstore_exception = drc->cache_top;
- append_generate_exception(drc, EXCEPTION_TLBSTORE);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top);
-
- mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top;
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
- emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12
- emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EAX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[eax*4]
- emit_test_r32_imm(DRCTOP, REG_EBX, 2); // test ebx,2
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
- emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception
- emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI); // mov [pcptr],edi
- emit_jmp(DRCTOP, drc->recompile); // jmp recompile
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top);
-
- mips3.drcdata->read_and_translate_byte_signed = drc->cache_top;
- append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_byte_signed:", mips3.drcdata->read_and_translate_byte_signed, drc->cache_top);
-
- mips3.drcdata->read_and_translate_byte_unsigned = drc->cache_top;
- append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_byte_unsigned:", mips3.drcdata->read_and_translate_byte_unsigned, drc->cache_top);
-
- mips3.drcdata->read_and_translate_half_signed = drc->cache_top;
- append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_half_signed:", mips3.drcdata->read_and_translate_half_signed, drc->cache_top);
-
- mips3.drcdata->read_and_translate_half_unsigned = drc->cache_top;
- append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_half_unsigned:", mips3.drcdata->read_and_translate_half_unsigned, drc->cache_top);
-
- mips3.drcdata->read_and_translate_word = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_READ);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_word:", mips3.drcdata->read_and_translate_word, drc->cache_top);
-
- mips3.drcdata->read_and_translate_word_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_READ | ARW_MASKED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_word_masked:", mips3.drcdata->read_and_translate_word_masked, drc->cache_top);
-
- mips3.drcdata->read_and_translate_double = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_READ);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_double:", mips3.drcdata->read_and_translate_double, drc->cache_top);
-
- mips3.drcdata->read_and_translate_double_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "read_and_translate_double_masked:", mips3.drcdata->read_and_translate_double_masked, drc->cache_top);
-
- mips3.drcdata->write_and_translate_byte = drc->cache_top;
- append_readwrite_and_translate(drc, 1, ARW_WRITE);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "write_and_translate_byte:", mips3.drcdata->write_and_translate_byte, drc->cache_top);
-
- mips3.drcdata->write_and_translate_half = drc->cache_top;
- append_readwrite_and_translate(drc, 2, ARW_WRITE);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "write_and_translate_half:", mips3.drcdata->write_and_translate_half, drc->cache_top);
-
- mips3.drcdata->write_and_translate_word = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_WRITE);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "write_and_translate_word:", mips3.drcdata->write_and_translate_word, drc->cache_top);
-
- mips3.drcdata->write_and_translate_word_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "write_and_translate_word_masked:", mips3.drcdata->write_and_translate_word_masked, drc->cache_top);
-
- mips3.drcdata->write_and_translate_double = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_WRITE);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "write_and_translate_double:", mips3.drcdata->write_and_translate_double, drc->cache_top);
-
- mips3.drcdata->write_and_translate_double_masked = drc->cache_top;
- append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED);
- if (LOG_CODE)
- x86log_disasm_code_range(mips3.log, "write_and_translate_double_masked:", mips3.drcdata->write_and_translate_double_masked, drc->cache_top);
-}
-
-
-/*------------------------------------------------------------------
- drc_recompile_callback
-------------------------------------------------------------------*/
-
-static void drc_recompile_callback(drc_core *drc)
-{
- int remaining = MAX_INSTRUCTIONS;
- x86code *start = drc->cache_top;
- UINT32 pc = mips3.core->pc;
- UINT32 lastpc = pc;
- UINT32 physpc;
-
- (void)start;
-
- /* begin the sequence */
- drc_begin_sequence(drc, pc);
-
- /* make sure our FR flag matches the last time */
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_FR); // test [COP0_Status],SR_FR
- emit_jcc(DRCTOP, IS_FR0 ? COND_NZ : COND_Z, drc->recompile); // jnz/z recompile
-
- /* ensure that we are still mapped */
- append_tlb_verify(drc, pc, mips3.drcdata->handle_pc_tlb_mismatch);
- physpc = pc;
- if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc))
- {
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi
- emit_jmp(DRCTOP, mips3.drcdata->generate_tlbload_exception); // jmp tlbload_exception
- goto exit;
- }
- change_pc(physpc);
-
- /* loose verification case: one verification here only */
- if (!(mips3.drcoptions & MIPS3DRC_STRICT_VERIFY))
- drc_append_verify_code(drc, cpu_opptr(physpc), 4);
-
- /* loop until we hit an unconditional branch */
- while (--remaining != 0)
- {
- UINT32 result;
-
- /* if we crossed a page boundary, check the mapping */
- if ((pc ^ lastpc) & 0xfffff000)
- {
- physpc = pc;
- if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc))
- break;
- append_tlb_verify(drc, pc, drc->dispatch);
- change_pc(physpc);
- }
-
- /* compile one instruction */
- physpc = (physpc & 0xfffff000) | (pc & 0xfff);
- result = compile_one(drc, pc, physpc);
- lastpc = pc;
- pc += (INT32)result >> 20;
- if (result & RECOMPILE_END_OF_STRING)
- break;
- }
-
- /* add dispatcher just in case */
- if (remaining == 0)
- drc_append_dispatcher(drc);
-
-exit:
- /* end the sequence */
- drc_end_sequence(drc);
-
- /* log the generated code */
- if (LOG_CODE)
- {
- char label[60];
- physpc = mips3.core->pc;
- mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc);
- sprintf(label, "Code @ %08X (%08X physical)", mips3.core->pc, physpc);
- x86log_disasm_code_range(mips3.log, label, start, drc->cache_top);
- }
-}
-
-
-/*------------------------------------------------------------------
- drc_entrygen_callback
-------------------------------------------------------------------*/
-
-static void drc_entrygen_callback(drc_core *drc)
-{
- emit_mov_r32_imm(DRCTOP, REG_ESI, (FPTR)&mips3.core->r[17]);
- append_check_interrupts(drc, 1);
-}
-
-
-
-/***************************************************************************
- RECOMPILER CORE
-***************************************************************************/
-
-/*------------------------------------------------------------------
- compile_one
-------------------------------------------------------------------*/
-
-static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc)
-{
- int pcdelta, cycles, hotnum;
- UINT32 *opptr;
- UINT32 result;
-
- /* register this instruction */
- drc_register_code_at_cache_top(drc, pc);
-
- /* get a pointer to the current instruction */
- change_pc(physpc);
- opptr = cpu_opptr(physpc);
-
- /* emit debugging and self-modifying code checks */
- drc_append_call_debugger(drc);
- if (mips3.drcoptions & MIPS3DRC_STRICT_VERIFY)
- drc_append_verify_code(drc, opptr, 4);
-
- /* is this a hotspot? */
- for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
- if (pc == mips3.hotspot[hotnum].pc && *(UINT32 *)opptr == mips3.hotspot[hotnum].opcode)
- break;
-
- /* compile the instruction */
- result = recompile_instruction(drc, pc, physpc);
-
- /* handle the results */
- if (!(result & RECOMPILE_SUCCESSFUL))
- fatalerror("Unimplemented op %08X (%02X,%02X)", *opptr, *opptr >> 26, *opptr & 0x3f);
-
- pcdelta = (INT32)result >> 20;
- cycles = (result >> 8) & 0xfff;
-
- /* absorb any NOPs following */
- if (STRIP_NOPS && !Machine->debug_mode)
- {
- if (!(result & (RECOMPILE_END_OF_STRING | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_CHECK_SW_INTERRUPTS)))
- while ((((pc + pcdelta) ^ pc) & 0xfffff000) == 0 && pcdelta < 120 && opptr[pcdelta/4] == 0)
- {
- pcdelta += 4;
- cycles += 1;
- }
- }
-
- /* epilogue */
- if (hotnum != MIPS3_MAX_HOTSPOTS)
- cycles += mips3.hotspot[hotnum].cycles;
- drc_append_standard_epilogue(drc, cycles, pcdelta, 1);
-
- /* check interrupts */
- if (result & RECOMPILE_CHECK_INTERRUPTS)
- append_check_interrupts(drc, 0);
- if (result & RECOMPILE_CHECK_SW_INTERRUPTS)
- append_check_sw_interrupts(drc, 0);
- if (result & RECOMPILE_ADD_DISPATCH)
- drc_append_dispatcher(drc);
-
- return (result & 0xff) | ((cycles & 0xfff) << 8) | ((pcdelta & 0xfff) << 20);
-}
-
-
-
-/***************************************************************************
- COMMON ROUTINES
-***************************************************************************/
-
-/*------------------------------------------------------------------
- append_generate_exception
-------------------------------------------------------------------*/
-
-static void append_generate_exception(drc_core *drc, UINT8 exception)
-{
- UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180;
- emit_link link1, link2;
-
- /* assumes address is in EAX */
- if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
- {
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_EAX); // mov [BadVAddr],eax
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff
- emit_and_r32_imm(DRCTOP, REG_EAX, 0xffffe000); // and eax,0xffffe000
- emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_EAX); // or [EntryHi],eax
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000
- emit_shr_r32_imm(DRCTOP, REG_EAX, 9); // shr eax,9
- emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_EAX); // or [Context],eax
- }
-
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_EDI); // mov [COP0_EPC],edi
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff
- if (exception)
- emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2
- emit_cmp_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // cmp [mips3.nextpc],~0
- emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
- emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // mov [mips3.nextpc],~0
- emit_sub_m32_imm(DRCTOP, CPR0ADDR(COP0_EPC), 4); // sub [COP0_EPC],4
- emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000
- resolve_link(DRCTOP, &link1); // skip:
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[COP0_Status]
- emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL
- emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax
- emit_mov_r32_imm(DRCTOP, REG_EDI, 0xbfc00200 + offset); // mov edi,0xbfc00200+offset
- emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2
- emit_mov_r32_imm(DRCTOP, REG_EDI, 0x80000000 + offset); // mov edi,0x80000000+offset
- resolve_link(DRCTOP, &link2); // skip2:
- drc_append_dispatcher(drc); // dispatch
-}
-
-
-/*------------------------------------------------------------------
- append_readwrite_and_translate
-------------------------------------------------------------------*/
-
-static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags)
-{
- emit_link link1 = { 0 }, link2 = { 0 }, link3 = { 0 };
- int ramnum;
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4]
- emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EAX); // mov ebx,eax
- emit_shr_r32_imm(DRCTOP, REG_EBX, 12); // shr ebx,12
- emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EBX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[ebx*4]
- emit_and_r32_imm(DRCTOP, REG_EAX, 0xfff); // and eax,0xfff
- emit_shr_r32_imm(DRCTOP, REG_EBX, ((flags & ARW_WRITE) ? 1 : 2)); // shr ebx,2/1 (read/write)
- emit_lea_r32_m32(DRCTOP, REG_EBX, MBISD(REG_EAX, REG_EBX, ((flags & ARW_WRITE) ? 2 : 4), 0));
- // lea ebx,[eax+ebx*4/2] (read/write)
- emit_jcc_near_link(DRCTOP, COND_C, &link1); // jc error
- for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++)
- if (!Machine->debug_mode && mips3.fastram[ramnum].base && (!(flags & ARW_WRITE) || !mips3.fastram[ramnum].readonly))
- {
- UINT32 fastbase = (UINT32)((UINT8 *)mips3.fastram[ramnum].base - mips3.fastram[ramnum].start);
- if (mips3.fastram[ramnum].end != 0xffffffff)
- {
- emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].end); // cmp ebx,fastram_end
- emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja notram
- }
- if (mips3.fastram[ramnum].start != 0x00000000)
- {
- emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].start); // cmp ebx,fastram_start
- emit_jcc_short_link(DRCTOP, COND_B, &link3); // jb notram
- }
-
- if (!(flags & ARW_WRITE))
- {
- if (size == 1)
- {
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3
- if (flags & ARW_SIGNED)
- emit_movsx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,byte ptr [ebx+fastbase]
- else
- emit_movzx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,byte ptr [ebx+fastbase]
- }
- else if (size == 2)
- {
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2
- if (flags & ARW_SIGNED)
- emit_movsx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,word ptr [ebx+fastbase]
- else
- emit_movzx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,word ptr [ebx+fastbase]
- }
- else if (size == 4)
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // mov eax,[ebx+fastbase]
- else if (size == 8)
- {
- if (mips3.core->bigendian)
- emit_mov_r64_m64(DRCTOP, REG_EAX, REG_EDX, MBD(REG_EBX, (FPTR)fastbase));
- // mov eax:edx,[ebx+fastbase]
- else
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MBD(REG_EBX, (FPTR)fastbase));
- // mov edx:eax,[ebx+fastbase]
- }
- emit_ret(DRCTOP); // ret
- }
- else
- {
- if (size == 1)
- {
- emit_mov_r8_m8(DRCTOP, REG_AL, MBD(REG_ESP, 8)); // mov al,[esp+8]
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3
- emit_mov_m8_r8(DRCTOP, MBD(REG_EBX, fastbase), REG_AL); // mov [ebx+fastbase],al
- }
- else if (size == 2)
- {
- emit_mov_r16_m16(DRCTOP, REG_AX, MBD(REG_ESP, 8)); // mov ax,[esp+8]
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2
- emit_mov_m16_r16(DRCTOP, MBD(REG_EBX, fastbase), REG_AX); // mov [ebx+fastbase],ax
- }
- else if (size == 4)
- {
- if (!(flags & ARW_MASKED))
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8]
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 12)); // mov ecx,[esp+12]
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
- emit_not_r32(DRCTOP, REG_ECX); // not ecx
- emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8]
- emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase]
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
- }
- }
- else if (size == 8)
- {
- if (!(flags & ARW_MASKED))
- {
- if (mips3.core->bigendian)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8]
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12]
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8]
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12]
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
- }
- }
- else
- {
- if (mips3.core->bigendian)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16]
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
- emit_not_r32(DRCTOP, REG_ECX); // not ecx
- emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8]
- emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4]
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
- emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20]
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
- emit_not_r32(DRCTOP, REG_ECX); // not ecx
- emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12]
- emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase]
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16]
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
- emit_not_r32(DRCTOP, REG_ECX); // not ecx
- emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8]
- emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase]
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax
- emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20]
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx
- emit_not_r32(DRCTOP, REG_ECX); // not ecx
- emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12]
- emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4]
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx
- emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax
- }
- }
- }
- emit_ret(DRCTOP); // ret
- }
-
- if (mips3.fastram[ramnum].end != 0xffffffff) // notram:
- resolve_link(DRCTOP, &link2);
- if (mips3.fastram[ramnum].start != 0x00000000)
- resolve_link(DRCTOP, &link3);
- }
-
- if (flags & ARW_WRITE)
- {
- emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx
- if (size == 1)
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writebyte); // jmp writebyte
- else if (size == 2)
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writehalf); // jmp writehalf
- else if (size == 4)
- {
- if (!(flags & ARW_MASKED))
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword); // jmp writeword
- else
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword_masked); // jmp writeword_masked
- }
- else
- {
- if (!(flags & ARW_MASKED))
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble); // jmp writedouble
- else
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble_masked); // jmp writedouble_masked
- }
- }
- else
- {
- if (size == 1)
- {
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- emit_call(DRCTOP, (x86code *)mips3.core->memory.readbyte); // call readbyte
- if (flags & ARW_SIGNED)
- emit_movsx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movsx eax,al
- else
- emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movzx eax,al
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_ret(DRCTOP); // ret
- }
- else if (size == 2)
- {
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- emit_call(DRCTOP, (x86code *)mips3.core->memory.readhalf); // call readhalf
- if (flags & ARW_SIGNED)
- emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movsx eax,ax
- else
- emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movzx eax,ax
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_ret(DRCTOP); // ret
- }
- else if (size == 4)
- {
- emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx
- if (!(flags & ARW_MASKED))
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword); // jmp readword
- else
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword_masked); // jmp readword_masked
- }
- else
- {
- emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx
- if (!(flags & ARW_MASKED))
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble); // jmp readdouble
- else
- emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble_masked); // jmp readdouble_masked
- }
- }
- {
- int valuebytes = (size == 8) ? 8 : 4;
- int stackbytes = 4 + ((flags & ARW_WRITE) ? 4 + valuebytes : 4) + ((flags & ARW_MASKED) ? valuebytes : 0);
- resolve_link(DRCTOP, &link1); // error:
- emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4]
- emit_add_r32_imm(DRCTOP, REG_ESP, stackbytes); // add esp,stack_bytes
- emit_jmp(DRCTOP, (flags & ARW_WRITE) ? (x86code *)mips3.drcdata->generate_tlbstore_exception : (x86code *)mips3.drcdata->generate_tlbload_exception);
- // jmp generate_exception
- }
-}
-
-
-/*------------------------------------------------------------------
- append_tlb_verify
-------------------------------------------------------------------*/
-
-static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target)
-{
- /* addresses 0x80000000-0xbfffffff are direct-mapped; no checking needed */
- if (pc < 0x80000000 || pc >= 0xc0000000)
- {
- emit_cmp_m32_imm(DRCTOP, MABS(&mips3.core->tlb_table[pc >> 12]), mips3.core->tlb_table[pc >> 12]);
- // cmp tlbtable[pc >> 12],physpc & 0xfffff000
- emit_jcc(DRCTOP, COND_NE, target); // jne handle_pc_tlb_mismatch
- }
-}
-
-
-/*------------------------------------------------------------------
- append_update_cycle_counting
-------------------------------------------------------------------*/
-
-static void append_update_cycle_counting(drc_core *drc)
-{
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
- emit_call(DRCTOP, (x86code *)mips3com_update_cycle_counting); // call update_cycle_counting
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
-}
-
-
-/*------------------------------------------------------------------
- append_check_interrupts
-------------------------------------------------------------------*/
-
-static void append_check_interrupts(drc_core *drc, int inline_generate)
-{
- emit_link link1, link2, link3;
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause]
- emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status]
- emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00
- if (!inline_generate)
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- else
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [COP0_Status,SR_IE
- if (!inline_generate)
- emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip
- else
- emit_jcc_near_link(DRCTOP, COND_Z, &link2); // jz skip
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [COP0_Status,SR_EXL | SR_ERL
- if (!inline_generate)
- emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_interrupt_exception); // jz generate_interrupt_exception
- else
- {
- emit_jcc_near_link(DRCTOP, COND_NZ, &link3); // jnz skip
- append_generate_exception(drc, EXCEPTION_INTERRUPT); // <generate exception>
- resolve_link(DRCTOP, &link3); // skip:
- }
- resolve_link(DRCTOP, &link1); // skip:
- resolve_link(DRCTOP, &link2);
-}
-
-
-/*------------------------------------------------------------------
- append_check_sw_interrupts
-------------------------------------------------------------------*/
-
-static void append_check_sw_interrupts(drc_core *drc, int inline_generate)
-{
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), 0x300); // test [COP0_Cause],0x300
- emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_interrupt_exception); // jnz generate_interrupt_exception
-}
-
-
-/*------------------------------------------------------------------
- append_branch_or_dispatch
-------------------------------------------------------------------*/
-
-static void append_branch_or_dispatch(drc_core *drc, UINT32 newpc, int cycles)
-{
- void *code = drc_get_code_at_pc(drc, newpc);
- emit_mov_r32_imm(DRCTOP, REG_EDI, newpc); // mov edi,newpc
- drc_append_standard_epilogue(drc, cycles, 0, 1); // <epilogue>
-
- if (code)
- emit_jmp(DRCTOP, code); // jmp code
- else
- drc_append_tentative_fixed_dispatcher(drc, newpc); // <dispatch>
-}
-
-
-
-/***************************************************************************
- CORE RECOMPILATION
-***************************************************************************/
-
-static void ddiv(INT64 *rs, INT64 *rt)
-{
- if (*rt)
- {
- mips3.core->r[REG_LO] = *rs / *rt;
- mips3.core->r[REG_HI] = *rs % *rt;
- }
-}
-
-static void ddivu(UINT64 *rs, UINT64 *rt)
-{
- if (*rt)
- {
- mips3.core->r[REG_LO] = *rs / *rt;
- mips3.core->r[REG_HI] = *rs % *rt;
- }
-}
-
-
-/*------------------------------------------------------------------
- recompile_delay_slot
-------------------------------------------------------------------*/
-
-static int recompile_delay_slot(drc_core *drc, UINT32 pc)
-{
- UINT8 *saved_top;
- UINT32 result;
- UINT32 physpc;
-
-#ifdef ENABLE_DEBUGGER
- if (Machine->debug_mode)
- {
- /* emit debugging */
- emit_mov_r32_imm(DRCTOP, REG_EDI, pc);
- drc_append_call_debugger(drc);
- }
-#endif
-
- saved_top = drc->cache_top;
-
- /* recompile the instruction as-is */
- in_delay_slot = 1;
- physpc = pc;
- mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc);
- result = recompile_instruction(drc, pc, physpc); // <next instruction>
- in_delay_slot = 0;
-
- /* if the instruction can cause an exception, recompile setting nextpc */
- if (result & RECOMPILE_MAY_CAUSE_EXCEPTION)
- {
- drc->cache_top = saved_top;
- emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), 0); // bogus nextpc for exceptions
- result = recompile_instruction(drc, pc, physpc); // <next instruction>
- emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // reset nextpc
- }
-
- return (result >> 8) & 0xfff;
-}
-
-
-/*------------------------------------------------------------------
- recompile_instruction
-------------------------------------------------------------------*/
-
-static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc)
-{
- emit_link link1, link2 = { 0 }, link3;
- UINT32 op = cpu_readop32(physpc);
- int cycles;
-
- if (LOG_CODE)
- log_add_disasm_comment(mips3.log, drc->cache_top, pc, op);
-
- switch (op >> 26)
- {
- case 0x00: /* SPECIAL */
- return recompile_special(drc, pc, op);
-
- case 0x01: /* REGIMM */
- return recompile_regimm(drc, pc, op);
-
- case 0x02: /* J */
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
-
- case 0x03: /* JAL */
- emit_mov_m64_imm32(DRCTOP, REGADDR(31), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
-
- case 0x04: /* BEQ */
- if (RSREG == RTREG)
- {
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else if (RSREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
- }
- else if (RTREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- if (RSREG != 0 && RTREG != 0)
- resolve_link(DRCTOP, &link2); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x05: /* BNE */
- if (RSREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- }
- else if (RTREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip
- resolve_link(DRCTOP, &link2); // takeit:
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x06: /* BLEZ */
- if (RSREG == 0)
- {
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip
- emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
- emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip
- resolve_link(DRCTOP, &link2); // takeit:
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- resolve_link(DRCTOP, &link3); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x07: /* BGTZ */
- if (RSREG == 0)
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
- emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
- emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip
- resolve_link(DRCTOP, &link2); // takeit:
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- resolve_link(DRCTOP, &link3); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x08: /* ADDI */
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
- if (RTREG != 0)
- {
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- }
- else if (RTREG != 0)
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x09: /* ADDIU */
- if (RTREG != 0)
- {
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- else
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0a: /* SLTI */
- if (RTREG != 0)
- {
- if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo
- emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo
- emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EDX); // mov [rdreg].lo,edx
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rdreg].hi,0
- }
- else
- {
- emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0b: /* SLTIU */
- if (RTREG != 0)
- {
- if (RSREG != 0)
- {
- emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); // cmp [rsreg].hi,upper
- emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb takeit
- emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skip
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
- emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skip
- resolve_link(DRCTOP, &link1); // takeit:
- emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1
- resolve_link(DRCTOP, &link2); // skip:
- resolve_link(DRCTOP, &link3); // skip:
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_ECX); // mov [rtreg].lo,ecx
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
- }
- else
- {
- emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0c: /* ANDI */
- if (RTREG != 0)
- {
- if (RSREG == RTREG)
- {
- emit_and_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // and [rtreg],UIMMVAL
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
- }
- else if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_and_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // and eax,UIMMVAL
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
- }
- else
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), 0); // mov [rtreg],0
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0d: /* ORI */
- if (RTREG != 0)
- {
- if (RSREG == RTREG)
- emit_or_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // or [rtreg].lo,UIMMVAL
- else if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_or_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // or eax,UIMMVAL
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- else
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0e: /* XORI */
- if (RTREG != 0)
- {
- if (RSREG == RTREG)
- emit_xor_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // xor [rtreg].lo,UIMMVAL
- else if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_xor_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // xor eax,UIMMVAL
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- else
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0f: /* LUI */
- if (RTREG != 0)
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL << 16); // mov [rtreg],const << 16
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x10: /* COP0 */
- return recompile_cop0(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x11: /* COP1 */
- return recompile_cop1(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x12: /* COP2 */
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
-
- case 0x13: /* COP1X - R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
- }
- return recompile_cop1x(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x14: /* BEQL */
- if (RSREG == RTREG)
- {
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else if (RSREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
- }
- else if (RTREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- if (RSREG != 0 && RTREG != 0)
- resolve_link(DRCTOP, &link2); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x15: /* BNEL */
- if (RSREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- }
- else if (RTREG == 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- }
- else
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip
- resolve_link(DRCTOP, &link2); // takeit:
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x16: /* BLEZL */
- if (RSREG == 0)
- {
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip
- emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
- emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip
- resolve_link(DRCTOP, &link2); // takeit:
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- resolve_link(DRCTOP, &link3); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x17: /* BGTZL */
- if (RSREG == 0)
- return RECOMPILE_SUCCESSFUL_CP(1,8);
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
- emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0
- emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip
- resolve_link(DRCTOP, &link2); // takeit:
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- resolve_link(DRCTOP, &link3); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x18: /* DADDI */
- if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL)
- emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
- if (RTREG != 0)
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- else if (RTREG != 0)
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x19: /* DADDIU */
- if (RTREG != 0)
- {
- if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL)
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- else
- emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x1a: /* LDL */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
- if (!mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
- emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
- emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl
- emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
- emit_push_r32(DRCTOP, REG_ECX); // push ecx
- emit_push_r32(DRCTOP, REG_EBP); // push ebp
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
-
- if (RTREG != 0)
- {
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_not_r32(DRCTOP, REG_EBX); // not ebx
- emit_not_r32(DRCTOP, REG_EBP); // not ebp
- emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl
- emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
- emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl
- emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
- emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
- emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x1b: /* LDR */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_push_r32(DRCTOP, REG_ECX); // push ecx
- emit_push_r32(DRCTOP, REG_EBP); // push ebp
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
-
- if (RTREG != 0)
- {
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
- emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
- emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl
- emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
- emit_not_r32(DRCTOP, REG_EBX); // not ebx
- emit_not_r32(DRCTOP, REG_EBP); // not ebp
- emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl
- emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl
- emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl
- emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl
- emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
- emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */
- switch (op & 0x1f)
- {
- case 0: /* MAD */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
- emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg]
- emit_imul_r32(DRCTOP, REG_EDX); // imul edx
- emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo]
- emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi]
- emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- }
- return RECOMPILE_SUCCESSFUL_CP(3,4);
-
- case 1: /* MADU */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
- emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg]
- emit_mul_r32(DRCTOP, REG_EDX); // mul edx
- emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo]
- emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi]
- emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- }
- return RECOMPILE_SUCCESSFUL_CP(3,4);
-
- case 2: /* MUL */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_imul_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // imul eax,[rtreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG)); // mov [rdreg],0
- }
- return RECOMPILE_SUCCESSFUL_CP(3,4);
- }
- break;
-
- case 0x20: /* LB */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_signed); // call read_and_translate_byte_signed
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- if (RTREG != 0)
- {
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x21: /* LH */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_signed); // call read_and_translate_half_signed
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- if (RTREG != 0)
- {
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x22: /* LWL */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- if (!mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
- emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl
- emit_push_r32(DRCTOP, REG_ECX); // push ecx
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8
- emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
-
- if (RTREG != 0)
- {
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_not_r32(DRCTOP, REG_EBX); // not ebx
- emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
- emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x23: /* LW */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- if (RTREG != 0)
- {
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x24: /* LBU */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_unsigned); // call read_and_translate_byte_unsigned
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- if (RTREG != 0)
- {
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x25: /* LHU */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_unsigned); // call read_and_translate_half_unsigned
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- if (RTREG != 0)
- {
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x26: /* LWR */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_push_r32(DRCTOP, REG_ECX); // push ecx
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8
- emit_pop_r32(DRCTOP, REG_ECX); // pop ecx
-
- if (RTREG != 0)
- {
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl
- emit_not_r32(DRCTOP, REG_EBX); // not ebx
- emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl
- emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x27: /* LWU */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- if (RTREG != 0)
- {
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax
- }
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x28: /* SB */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- if (RTREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
- else
- emit_push_imm(DRCTOP, 0); // push 0
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_byte); // call writebyte
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x29: /* SH */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- if (RTREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
- else
- emit_push_imm(DRCTOP, 0); // push 0
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_half); // call writehalf
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2a: /* SWL */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- if (!mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
- emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo
- emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- }
- else
- emit_push_imm(DRCTOP, 0); // push 0
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2b: /* SW */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- if (RTREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
- else
- emit_push_imm(DRCTOP, 0); // push 0
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2c: /* SDL */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
- if (!mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
- emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
- emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl
- emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl
- emit_push_r32(DRCTOP, REG_EBP); // push ebp
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi
- emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl
- emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
- emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl
- emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- }
- else
- {
- emit_push_imm(DRCTOP, 0); // push 0
- emit_push_imm(DRCTOP, 0); // push 0
- }
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2d: /* SDR */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_push_r32(DRCTOP, REG_EBP); // push ebp
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi
- emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- }
- else
- {
- emit_push_imm(DRCTOP, 0); // push 0
- emit_push_imm(DRCTOP, 0); // push 0
- }
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2e: /* SWR */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- if (SIMMVAL)
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3
- emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1
- if (mips3.core->bigendian)
- emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18
- emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl
- emit_push_r32(DRCTOP, REG_EBX); // push ebx
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo
- emit_shl_r32_cl(DRCTOP, REG_EDX); // shl edx,cl
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- }
- else
- emit_push_imm(DRCTOP, 0); // push 0
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked
- emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2f: /* CACHE */
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
-// case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break;
-
- case 0x31: /* LWC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].los
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(RTREG), REG_EAX); // mov [rtreg],eax
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x32: /* LWC2 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_m32_r32(DRCTOP, CPR2ADDR(RTREG), REG_EAX); // mov [rtreg],eax
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x33: /* PREF */
- if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- else
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
- }
-
-// case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break;
-
- case 0x35: /* LDC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double
- emit_mov_m64_r64(DRCTOP, FPR64ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x36: /* LDC2 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_word
- emit_mov_m64_r64(DRCTOP, CPR2ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x37: /* LD */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double
- if (RTREG != 0)
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
-// case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break;
-
- case 0x39: /* SWC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_push_m32(DRCTOP, FPR32ADDR(RTREG)); // push dword [rtreg]
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3a: /* SWC2 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_push_m32(DRCTOP, CPR2ADDR(RTREG)); // push dword [rtreg]
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
-// case 0x3b: /* SWC3 */ invalid_instruction(op); break;
-// case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break;
-
- case 0x3d: /* SDC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_push_m32(DRCTOP, FPR64ADDRHI(RTREG)); // push dword [rtreg].hi
- emit_push_m32(DRCTOP, FPR64ADDRLO(RTREG)); // push dword [rtreg].lo
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3e: /* SDC2 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_push_m32(DRCTOP, CPR2ADDRHI(RTREG)); // push dword [rtreg].hi
- emit_push_m32(DRCTOP, CPR2ADDRLO(RTREG)); // push dword [rtreg].lo
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3f: /* SD */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- if (RTREG != 0)
- {
- emit_push_m32(DRCTOP, REGADDRHI(RTREG)); // push dword [rtreg].hi
- emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo
- }
- else
- {
- emit_push_imm(DRCTOP, 0); // push 0
- emit_push_imm(DRCTOP, 0); // push 0
- }
- if (RSREG != 0 && SIMMVAL != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- }
- else if (RSREG != 0)
- emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo
- else
- emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
-// default: /* ??? */ invalid_instruction(op); break;
- }
- return RECOMPILE_UNIMPLEMENTED;
-}
-
-
-/*------------------------------------------------------------------
- recompile_special
-------------------------------------------------------------------*/
-
-static UINT32 recompile_special1(drc_core *drc, UINT32 pc, UINT32 op)
-{
- emit_link link1, link2, link3;
- int cycles;
-
- switch (op & 63)
- {
- case 0x00: /* SLL */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (SHIFT != 0)
- emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x01: /* MOVF - R5000*/
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
- }
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
- emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x02: /* SRL */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (SHIFT != 0)
- emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x03: /* SRA */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (SHIFT != 0)
- emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x04: /* SLLV */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
- emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
- }
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x06: /* SRLV */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
- emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl
- }
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x07: /* SRAV */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
- emit_sar_r32_cl(DRCTOP, REG_EAX); // sar eax,cl
- }
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x08: /* JR */
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_mov_m32_r32(DRCTOP, MABS(&jr_temp), REG_EAX); // mov jr_temp,eax
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&jr_temp)); // mov edi,jr_temp
- return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
-
- case 0x09: /* JALR */
- if (RDREG != 0)
- emit_mov_m64_imm32(DRCTOP, REGADDR(RDREG), pc + 8); // mov [rdreg],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- emit_mov_r32_m32(DRCTOP, REG_EDI, REGADDRLO(RSREG)); // mov edi,[rsreg].lo
- return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
-
- case 0x0a: /* MOVZ - R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
- }
- if (RDREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG));
- // mov [rdreg],[rsreg]
- resolve_link(DRCTOP, &link1); // skip:
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0b: /* MOVN - R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
- }
- if (RDREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG));
- // mov [rdreg],[rsreg]
- resolve_link(DRCTOP, &link1); // skip:
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0c: /* SYSCALL */
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_syscall_exception); // jmp generate_syscall_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
-
- case 0x0d: /* BREAK */
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_break_exception); // jmp generate_break_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING;
-
- case 0x0f: /* SYNC */
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x10: /* MFHI */
- if (RDREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), HIADDR); // mov [rdreg],[hi]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x11: /* MTHI */
- emit_mov_m64_m64(DRCTOP, HIADDR, REGADDR(RSREG)); // mov [hi],[rsreg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x12: /* MFLO */
- if (RDREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), LOADDR); // mov [rdreg],[lo]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x13: /* MTLO */
- emit_mov_m64_m64(DRCTOP, LOADDR, REGADDR(RSREG)); // mov [lo],[rsreg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x14: /* DSLLV */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
- emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EAX); // mov edx,eax
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- resolve_link(DRCTOP, &link1); // skip:
- emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl
- emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl
- }
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x16: /* DSRLV */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
- emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- resolve_link(DRCTOP, &link1); // skip:
- emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl
- emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl
- }
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x17: /* DSRAV */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo
- emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx
- emit_cdq(DRCTOP); // cdq
- resolve_link(DRCTOP, &link1); // skip:
- emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl
- emit_sar_r32_cl(DRCTOP, REG_EDX); // sar edx,cl
- }
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x18: /* MULT */
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_imul_r32(DRCTOP, REG_ECX); // imul ecx
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_pop_r32(DRCTOP, REG_EAX); // pop eax
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- return RECOMPILE_SUCCESSFUL_CP(4,4);
-
- case 0x19: /* MULTU */
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_mul_r32(DRCTOP, REG_ECX); // mul ecx
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_pop_r32(DRCTOP, REG_EAX); // pop eax
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- return RECOMPILE_SUCCESSFUL_CP(4,4);
-
- case 0x1a: /* DIV */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0
- emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
- emit_idiv_r32(DRCTOP, REG_ECX); // idiv ecx
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_pop_r32(DRCTOP, REG_EAX); // pop eax
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- resolve_link(DRCTOP, &link1); // skip:
- }
- return RECOMPILE_SUCCESSFUL_CP(36,4);
-
- case 0x1b: /* DIVU */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0
- emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
- emit_div_r32(DRCTOP, REG_ECX); // div ecx
- emit_push_r32(DRCTOP, REG_EDX); // push edx
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
- emit_pop_r32(DRCTOP, REG_EAX); // pop eax
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
- resolve_link(DRCTOP, &link1); // skip:
- }
- return RECOMPILE_SUCCESSFUL_CP(36,4);
-
- case 0x1c: /* DMULT */
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
- emit_jcc_short_link(DRCTOP, COND_GE, &link1); // jge skip1
- emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_neg_r32(DRCTOP, REG_EAX); // neg eax
- emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx
- resolve_link(DRCTOP, &link1); // skip1:
- emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp1), REG_EDX, REG_EAX); // mov [dmult_temp1],edx:eax
-
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
- emit_jcc_short_link(DRCTOP, COND_GE, &link2); // jge skip2
- emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_neg_r32(DRCTOP, REG_EAX); // neg eax
- emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx
- resolve_link(DRCTOP, &link2); // skip2:
- emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp2), REG_EDX, REG_EAX); // mov [dmult_temp2],edx:eax
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo
- emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo
- emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
- emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
- emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi
- emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo
- emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
- emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo
- emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi
- emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
- emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
- emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi
- emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi
- emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax
- emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0
- emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx
- emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // xor eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_NS, &link3); // jns noflip
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
- emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_sub_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // sub eax,[lo].lo
- emit_sbb_r32_m32(DRCTOP, REG_EBX, LOADDRHI); // sbb ebx,[lo].hi
- emit_sbb_r32_m32(DRCTOP, REG_ECX, HIADDRLO); // sbb ecx,[hi].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, HIADDRHI); // sbb edx,[hi].hi
- emit_mov_m64_r64(DRCTOP, LOADDR, REG_EBX, REG_EAX); // mov [lo],ebx:eax
- emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_ECX); // mov [hi],edx:ecx
- resolve_link(DRCTOP, &link3); // noflip:
- return RECOMPILE_SUCCESSFUL_CP(8,4);
-
- case 0x1d: /* DMULTU */
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo
- emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx
- emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
- emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo
- emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
- emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi
- emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax
- emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx
- emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx
-
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi
- emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax
- emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0
- emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx
- emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx
- return RECOMPILE_SUCCESSFUL_CP(8,4);
-
- case 0x1e: /* DDIV */
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg]
- emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg]
- emit_call(DRCTOP, (x86code *)ddiv); // call ddiv
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- return RECOMPILE_SUCCESSFUL_CP(68,4);
-
- case 0x1f: /* DDIVU */
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg]
- emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg]
- emit_call(DRCTOP, (x86code *)ddivu); // call ddivu
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- return RECOMPILE_SUCCESSFUL_CP(68,4);
- }
-
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
-}
-
-static UINT32 recompile_special2(drc_core *drc, UINT32 pc, UINT32 op)
-{
- emit_link link1, link2, link3;
-
- switch (op & 63)
- {
- case 0x20: /* ADD */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
- emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
- if (RDREG != 0)
- {
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- }
- else if (RDREG != 0)
- {
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x21: /* ADDU */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x22: /* SUB */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
- if (RDREG != 0)
- {
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- }
- else if (RDREG != 0)
- {
- if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_neg_r32(DRCTOP, REG_EAX); // neg eax
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x23: /* SUBU */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RSREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_neg_r32(DRCTOP, REG_EAX); // neg eax
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x24: /* AND */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg]
- emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg]
- emit_andpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // andpd xmm0,xmm1
- emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0
- }
- else
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG));
- // mov edx:eax,[rsreg]
- emit_and_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // and eax,[rtreg].lo
- emit_and_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // and edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x25: /* OR */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg]
- emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg]
- emit_orpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // orpd xmm0,xmm1
- emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0
- }
- else
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG));
- // mov edx:eax,[rsreg]
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- }
- else if (RSREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
- else if (RTREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg]
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x26: /* XOR */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg]
- emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg]
- emit_xorpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // xorpd xmm0,xmm1
- emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0
- }
- else
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG));
- // mov edx:eax,[rsreg]
- emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // xor eax,[rtreg].lo
- emit_xor_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // xor edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- }
- else if (RSREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
- else if (RTREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg]
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x27: /* NOR */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi
- emit_not_r32(DRCTOP, REG_EDX); // not edx
- emit_not_r32(DRCTOP, REG_EAX); // not eax
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_not_r32(DRCTOP, REG_EDX); // not edx
- emit_not_r32(DRCTOP, REG_EAX); // not eax
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- emit_not_r32(DRCTOP, REG_EDX); // not edx
- emit_not_r32(DRCTOP, REG_EAX); // not eax
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- {
- emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), ~0); // mov [rtreg].lo,~0
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), ~0); // mov [rtreg].hi,~0
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2a: /* SLT */
- if (RDREG != 0)
- {
- if (RSREG != 0)
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- else
- {
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- }
- if (RTREG != 0)
- {
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].lo
- }
- emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EDX); // mov [rdreg].lo,edx
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2b: /* SLTU */
- if (RDREG != 0)
- {
- emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb setit
- emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skipit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skipit
- resolve_link(DRCTOP, &link1); // setit:
- emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1
- resolve_link(DRCTOP, &link2); // skipit:
- resolve_link(DRCTOP, &link3); // skipit:
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_ECX); // mov [rdreg].lo,ecx
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2c: /* DADD */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
- emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi
- emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
- if (RDREG != 0)
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RDREG != 0)
- {
- if (RSREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
- else if (RTREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg]
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x2d: /* DADDU */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo
- emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RSREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG));
- // mov [rdreg],[rsreg]
- else if (RTREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG));
- // mov [rdreg],[rtreg]
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x2e: /* DSUB */
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
- emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception
- if (RDREG != 0)
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RDREG != 0)
- {
- if (RSREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
- else if (RTREG != 0)
- {
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x2f: /* DSUBU */
- if (RDREG != 0)
- {
- if (RSREG != 0 && RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else if (RSREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg]
- else if (RTREG != 0)
- {
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x30: /* TGE */
- if (RSREG != 0)
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- else
- {
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- }
- if (RTREG != 0)
- {
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
- }
- else
- emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
- emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x31: /* TGEU */
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception
- emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skipit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception
- resolve_link(DRCTOP, &link1); // skipit:
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x32: /* TLT */
- if (RSREG != 0)
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- else
- {
- emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- }
- if (RTREG != 0)
- {
- emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo
- emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi
- }
- else
- emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0
- emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x33: /* TLTU */
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
- emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skipit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
- resolve_link(DRCTOP, &link1); // skipit:
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x34: /* TEQ */
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skipit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception
- resolve_link(DRCTOP, &link1); // skipit:
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x36: /* TNE */
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skipit
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo
- emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo
- emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception
- resolve_link(DRCTOP, &link1); // skipit:
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x38: /* DSLL */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- if (SHIFT != 0)
- {
- emit_shld_r32_r32_imm(DRCTOP, REG_EDX, REG_EAX, SHIFT); // shld edx,eax,SHIFT
- emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT
- }
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3a: /* DSRL */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- if (SHIFT != 0)
- {
- emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT
- emit_shr_r32_imm(DRCTOP, REG_EDX, SHIFT); // shr edx,SHIFT
- }
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3b: /* DSRA */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg]
- if (SHIFT != 0)
- {
- emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT
- emit_sar_r32_imm(DRCTOP, REG_EDX, SHIFT); // sar edx,SHIFT
- }
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3c: /* DSLL32 */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- if (SHIFT != 0)
- emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT
- emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), 0); // mov [rdreg].lo,0
- emit_mov_m32_r32(DRCTOP, REGADDRHI(RDREG), REG_EAX); // mov [rdreg].hi,eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3e: /* DSRL32 */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi
- if (SHIFT != 0)
- emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0
- emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EAX); // mov [rdreg].lo,eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x3f: /* DSRA32 */
- if (RDREG != 0)
- {
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi
- emit_cdq(DRCTOP); // cdq
- if (SHIFT != 0)
- emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT
- emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax
- }
- else
- emit_zero_m64(DRCTOP, REGADDR(RDREG));
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- }
-
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
-}
-
-
-static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op)
-{
- if (!(op & 32))
- return recompile_special1(drc, pc, op);
- else
- return recompile_special2(drc, pc, op);
-}
-
-
-/*------------------------------------------------------------------
- recompile_regimm
-------------------------------------------------------------------*/
-
-static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op)
-{
- emit_link link1;
- int cycles;
-
- switch (RTREG)
- {
- case 0x00: /* BLTZ */
- if (RSREG == 0)
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x01: /* BGEZ */
- if (RSREG == 0)
- {
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x02: /* BLTZL */
- if (RSREG == 0)
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x03: /* BGEZL */
- if (RSREG == 0)
- {
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
- }
-
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x08: /* TGEI */
- if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo
- emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo
- emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception
- }
- else
- {
- if (0 >= SIMMVAL)
- emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x09: /* TGEIU */
- if (RSREG != 0)
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
- // cmp [rsreg].hi,upper
- emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception
- emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skip
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
- emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception
- resolve_link(DRCTOP, &link1); // skip:
- }
- else
- {
- if (0 >= SIMMVAL)
- emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x0a: /* TLTI */
- if (RSREG != 0)
- {
- emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg]
- emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo
- emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo
- emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception
- }
- else
- {
- if (0 < SIMMVAL)
- emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x0b: /* TLTIU */
- if (RSREG != 0)
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
- // cmp [rsreg].hi,upper
- emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
- emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skip
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
- emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception
- resolve_link(DRCTOP, &link1); // skip:
- }
- else
- {
- emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const
- emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const)
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x0c: /* TEQI */
- if (RSREG != 0)
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
- // cmp [rsreg].hi,upper
- emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skip
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
- emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception
- resolve_link(DRCTOP, &link1); // skip:
- }
- else
- {
- if (0 == SIMMVAL)
- emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x0e: /* TNEI */
- if (RSREG != 0)
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31));
- // cmp [rsreg].hi,upper
- emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip
- emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower
- emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception
- resolve_link(DRCTOP, &link1); // skip:
- }
- else
- {
- if (0 != SIMMVAL)
- emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION;
-
- case 0x10: /* BLTZAL */
- if (RSREG == 0)
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
- }
- emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x11: /* BGEZAL */
- if (RSREG == 0)
- {
- emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
- }
-
- emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x12: /* BLTZALL */
- if (RSREG == 0)
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip
- }
-
- emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x13: /* BGEZALL */
- if (RSREG == 0)
- {
- emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING;
- }
- else
- {
- emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0
- emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip
- }
-
- emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
- }
-
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
-}
-
-
-
-/***************************************************************************
- COP0 RECOMPILATION
-***************************************************************************/
-
-/*------------------------------------------------------------------
- recompile_set_cop0_reg
-------------------------------------------------------------------*/
-
-static UINT32 recompile_set_cop0_reg(drc_core *drc, UINT8 reg)
-{
- emit_link link1;
-
- switch (reg)
- {
- case COP0_Cause:
- emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Cause)); // mov ebx,[COP0_Cause]
- emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00
- emit_and_r32_imm(DRCTOP, REG_EBX, 0xfc00); // and ebx,0xfc00
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax
- emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status]
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_SW_INTERRUPTS;
-
- case COP0_Status:
- emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Status)); // mov ebx,[COP0_Status]
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax
- emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EAX); // xor ebx,eax
-/*
-#ifdef ENABLE_DEBUGGER
- _test_r32_imm(REG_EAX, 0xe0); // test eax,0xe0
- _jcc_short_link(COND_Z, &link1); // jz skip
- _sub_r32_imm(REG_ESP, 4); // sub esp,4
- _push_r32(REG_EAX); // push eax
- _push_imm("System set 64-bit addressing mode, SR=%08X"); // push <string>
- _call(mame_printf_debug); // call mame_printf_debug
- _call(mame_debug_break); // call mame_debug_break
- _add_r32_imm(REG_ESP, 12); // add esp,12
- _resolve_link(&link1); // skip:
-#endif
-*/
- emit_test_r32_imm(DRCTOP, REG_EBX, 0x8000); // test ebx,0x8000
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- append_update_cycle_counting(drc); // update cycle counting
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
-
- case COP0_Count:
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [COP0_Count],eax
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles); // call activecpu_gettotalcycles
- emit_pop_r32(DRCTOP, REG_EBX); // pop ebx
- emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8
- emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx
- emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0
- emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx
- emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0
- emit_mov_m64_r64(DRCTOP, MABS(&mips3.core->count_zero_time), REG_EDX, REG_EAX); // mov [mips3.core->count_zero_time],edx:eax
- append_update_cycle_counting(drc); // update cycle counting
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case COP0_Compare:
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [COP0_Compare],eax
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [COP0_Cause],~0x8000
- append_update_cycle_counting(drc); // update cycle counting
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case COP0_PRId:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case COP0_Config:
- emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Config)); // mov ebx,[COP0_Cause]
- emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007
- emit_and_r32_imm(DRCTOP, REG_EBX, ~0x0007); // and ebx,~0x0007
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [COP0_Cause],eax
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- default:
- emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov [reg],eax
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- }
- return RECOMPILE_UNIMPLEMENTED;
-}
-
-
-/*------------------------------------------------------------------
- recompile_get_cop0_reg
-------------------------------------------------------------------*/
-
-static UINT32 recompile_get_cop0_reg(drc_core *drc, UINT8 reg)
-{
- emit_link link1;
-
- switch (reg)
- {
- case COP0_Count:
- emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24
- emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg
- emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp
- resolve_link(DRCTOP, &link1); // notneg:
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12
- emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles); // call activecpu_gettotalcycles
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_sub_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->count_zero_time))); // sub eax,[mips3.core->count_zero_time+0]
- emit_sbb_r32_m32(DRCTOP, REG_EDX, MABS(HI(&mips3.core->count_zero_time))); // sbb edx,[mips3.core->count_zero_time+4]
- emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, 1); // shrd eax,edx,1
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case COP0_Cause:
- emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24
- emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg
- emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp
- resolve_link(DRCTOP, &link1); // notneg:
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- default:
- emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- }
- return RECOMPILE_UNIMPLEMENTED;
-}
-
-
-/*------------------------------------------------------------------
- recompile_cop0
-------------------------------------------------------------------*/
-
-static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op)
-{
- emit_link checklink;
- UINT32 result;
-
- if (mips3.drcoptions & MIPS3DRC_STRICT_COP0)
- {
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [COP0_Status],SR_KSU_MASK
- emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [COP0_Status],SR_COP0
- emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception
- resolve_link(DRCTOP, &checklink); // okay:
- }
-
- switch (RSREG)
- {
- case 0x00: /* MFCz */
- result = RECOMPILE_SUCCESSFUL_CP(1,4);
- if (RTREG != 0)
- {
- result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- return result;
-
- case 0x01: /* DMFCz */
- result = RECOMPILE_SUCCESSFUL_CP(1,4);
- if (RTREG != 0)
- {
- result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- return result;
-
- case 0x02: /* CFCz */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, CCR0ADDR(RDREG)); // mov eax,[mips3.core->ccr[0][rdreg]]
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x04: /* MTCz */
- if (RTREG != 0)
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
- else
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg
- return result;
-
- case 0x05: /* DMTCz */
- if (RTREG != 0)
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
- else
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg
- return result;
-
- case 0x06: /* CTCz */
- if (RTREG != 0)
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
- else
- emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax
- emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[0][RDREG]],eax
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
-// case 0x08: /* BC */
-// switch (RTREG)
-// {
-// case 0x00: /* BCzF */ if (!mips3.core->cf[0][0]) ADDPC(SIMMVAL); break;
-// case 0x01: /* BCzF */ if (mips3.core->cf[0][0]) ADDPC(SIMMVAL); break;
-// case 0x02: /* BCzFL */ invalid_instruction(op); break;
-// case 0x03: /* BCzTL */ invalid_instruction(op); break;
-// default: invalid_instruction(op); break;
-// }
-// break;
-
- case 0x10:
- case 0x11:
- case 0x12:
- case 0x13:
- case 0x14:
- case 0x15:
- case 0x16:
- case 0x17:
- case 0x18:
- case 0x19:
- case 0x1a:
- case 0x1b:
- case 0x1c:
- case 0x1d:
- case 0x1e:
- case 0x1f: /* COP */
- switch (op & 0x01ffffff)
- {
- case 0x01: /* TLBR */
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
- drc_append_save_call_restore(drc, (x86code *)mips3com_tlbr, 12); // call tlbr
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x02: /* TLBWI */
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
- drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwi, 12); // call tlbwi
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x06: /* TLBWR */
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
- drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwr, 12); // call tlbwr
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x08: /* TLBP */
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core
- drc_append_save_call_restore(drc, (x86code *)mips3com_tlbp, 12); // call tlbp
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x10: /* RFE */
- emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
-
- case 0x18: /* ERET */
- emit_mov_r32_m32(DRCTOP, REG_EDI, CPR0ADDR(COP0_EPC)); // mov edi,[COP0_EPC]
- emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [COP0_Status],~SR_EXL
- return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH;
-
- default:
- emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- break;
-
-// default:
-// _jmp(mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
-// return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- return RECOMPILE_UNIMPLEMENTED;
-}
-
-
-
-/***************************************************************************
- COP1 RECOMPILATION
-***************************************************************************/
-
-/*------------------------------------------------------------------
- recompile_cop1
-------------------------------------------------------------------*/
-
-static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op)
-{
- emit_link link1;
- int cycles, i;
-
- if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
- {
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1
- emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception
- }
-
- switch (RSREG)
- {
- case 0x00: /* MFCz */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(RDREG)); // mov eax,[RDREG]
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [RTREG],edx:eax
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x01: /* DMFCz */
- if (RTREG != 0)
- emit_mov_m64_m64(DRCTOP, REGADDR(RTREG), FPR64ADDR(RDREG));
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x02: /* CFCz */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, CCR1ADDR(RDREG)); // mov eax,[mips3.core->ccr[1][RDREG]]
- if (RDREG == 31)
- {
- emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfe800000); // and eax,~0xfe800000
- emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx
- emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][0]), 0); // cmp [cf[0]],0
- emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl
- emit_shl_r32_imm(DRCTOP, REG_EBX, 23); // shl ebx,23
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
- for (i = 1; i <= 7; i++)
- {
- emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][i]), 0); // cmp [cf[i]],0
- emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl
- emit_shl_r32_imm(DRCTOP, REG_EBX, 24+i); // shl ebx,24+i
- emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx
- }
- }
- emit_cdq(DRCTOP); // cdq
- emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [mips3.core->r[RTREG]],edx:eax
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x04: /* MTCz */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), REG_EAX); // mov [mips3.core->cpr[1][RDREG]],eax
- }
- else
- emit_mov_m32_imm(DRCTOP, FPR32ADDR(RDREG), 0); // mov [mips3.core->cpr[1][RDREG]],0
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x05: /* DMTCz */
- if (RTREG != 0)
- emit_mov_m64_m64(DRCTOP, FPR64ADDR(RDREG), REGADDR(RTREG));
- else
- emit_zero_m64(DRCTOP, FPR64ADDR(RDREG)); // mov [mips3.core->cpr[1][RDREG]],0
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x06: /* CTCz */
- if (RTREG != 0)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]]
- emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[1][RDREG]],eax
- }
- else
- emit_mov_m32_imm(DRCTOP, CCR1ADDR(RDREG), 0); // mov [mips3.core->ccr[1][RDREG]],0
- if (RDREG == 31)
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->ccr[1][RDREG]))); // mov eax,[mips3.core->ccr[1][RDREG]]
- emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1<<23
- emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][0])); // setnz [cf[0]]
- if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV)
- for (i = 1; i <= 7; i++)
- {
- emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24+i)); // test eax,1<<(24+i)
- emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][i])); // setnz [cf[i]]
- }
- emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3
- emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip
- emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2
- resolve_link(DRCTOP, &link1); // skip:
- drc_append_set_fp_rounding(drc, REG_EAX); // set_rounding(EAX)
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x08: /* BC */
- switch ((op >> 16) & 3)
- {
- case 0x00: /* BCzF */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x01: /* BCzT */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x02: /* BCzFL */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
- emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
-
- case 0x03: /* BCzTL */
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
- emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1
- cycles = recompile_delay_slot(drc, pc + 4); // <next instruction>
- append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch>
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,8);
- }
- break;
-
- default:
- switch (op & 0x3f)
- {
- case 0x00:
- if (IS_SINGLE(op)) /* ADD.S */
- {
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_faddp(DRCTOP); // faddp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- }
- else /* ADD.D */
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_faddp(DRCTOP); // faddp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x01:
- if (IS_SINGLE(op)) /* SUB.S */
- {
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fsubp(DRCTOP); // fsubp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- }
- else /* SUB.D */
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fsubp(DRCTOP); // fsubp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x02:
- if (IS_SINGLE(op)) /* MUL.S */
- {
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- }
- else /* MUL.D */
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x03:
- if (IS_SINGLE(op)) /* DIV.S */
- {
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fdivp(DRCTOP); // fdivp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- }
- else /* DIV.D */
- {
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fdivp(DRCTOP); // fdivp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x04:
- if (IS_SINGLE(op)) /* SQRT.S */
- {
- if (USE_SSE)
- {
- emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fsqrt(DRCTOP); // fsqrt
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- }
- else /* SQRT.D */
- {
- if (USE_SSE)
- {
- emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fsqrt(DRCTOP); // fsqrt
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x05:
- if (IS_SINGLE(op)) /* ABS.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fabs(DRCTOP); // fabs
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- else /* ABS.D */
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fabs(DRCTOP); // fabs
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x06:
- if (IS_SINGLE(op)) /* MOV.S */
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- }
- else /* MOV.D */
- emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x07:
- if (IS_SINGLE(op)) /* NEG.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fchs(DRCTOP); // fchs
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- else /* NEG.D */
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fchs(DRCTOP); // fchs
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x08:
- drc_append_set_temp_fp_rounding(drc, FPRND_NEAR);
- if (IS_SINGLE(op)) /* ROUND.L.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* ROUND.L.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x09:
- drc_append_set_temp_fp_rounding(drc, FPRND_CHOP);
- if (IS_SINGLE(op)) /* TRUNC.L.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* TRUNC.L.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0a:
- drc_append_set_temp_fp_rounding(drc, FPRND_UP);
- if (IS_SINGLE(op)) /* CEIL.L.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* CEIL.L.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0b:
- drc_append_set_temp_fp_rounding(drc, FPRND_DOWN);
- if (IS_SINGLE(op)) /* FLOOR.L.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* FLOOR.L.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0c:
- drc_append_set_temp_fp_rounding(drc, FPRND_NEAR);
- if (IS_SINGLE(op)) /* ROUND.W.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* ROUND.W.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0d:
- drc_append_set_temp_fp_rounding(drc, FPRND_CHOP);
- if (IS_SINGLE(op)) /* TRUNC.W.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* TRUNC.W.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0e:
- drc_append_set_temp_fp_rounding(drc, FPRND_UP);
- if (IS_SINGLE(op)) /* CEIL.W.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* CEIL.W.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0f:
- drc_append_set_temp_fp_rounding(drc, FPRND_DOWN);
- if (IS_SINGLE(op)) /* FLOOR.W.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* FLOOR.W.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
- drc_append_restore_fp_rounding(drc);
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x11: /* R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
- // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0
- emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1);
- // jz/nz skip
- if (IS_SINGLE(op)) /* MOVT/F.S */
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- }
- else /* MOVT/F.D */
- emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x12: /* R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
- // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip
- if (IS_SINGLE(op)) /* MOVZ.S */
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- }
- else /* MOVZ.D */
- emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x13: /* R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
- // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo
- emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi
- emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip
- if (IS_SINGLE(op)) /* MOVN.S */
- {
- emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg]
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- }
- else /* MOVN.D */
- emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG));
- resolve_link(DRCTOP, &link1); // skip:
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x15: /* R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
- // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- emit_fld1(DRCTOP); // fld1
- if (IS_SINGLE(op)) /* RECIP.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fdivp(DRCTOP); // fdivp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- else /* RECIP.D */
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fdivp(DRCTOP); // fdivp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x16: /* R5000 */
- if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV)
- {
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception);
- // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
- }
- emit_fld1(DRCTOP); // fld1
- if (IS_SINGLE(op)) /* RSQRT.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fsqrt(DRCTOP); // fsqrt
- emit_fdivp(DRCTOP); // fdivp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- else /* RSQRT.D */
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fsqrt(DRCTOP); // fsqrt
- emit_fdivp(DRCTOP); // fdivp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x20:
- if (IS_INTEGRAL(op))
- {
- if (IS_SINGLE(op)) /* CVT.S.W */
- emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg]
- else /* CVT.S.L */
- emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg]
- }
- else /* CVT.S.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x21:
- if (IS_INTEGRAL(op))
- {
- if (IS_SINGLE(op)) /* CVT.D.W */
- emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg]
- else /* CVT.D.L */
- emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg]
- }
- else /* CVT.D.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x24:
- if (IS_SINGLE(op)) /* CVT.W.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* CVT.W.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x25:
- if (IS_SINGLE(op)) /* CVT.L.S */
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- else /* CVT.L.D */
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x30:
- case 0x38:
- emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x31:
- case 0x39:
- emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.UN.S/D */
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x32:
- case 0x3a:
- if (USE_SSE)
- {
- if (IS_SINGLE(op)) /* C.EQ.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
- }
- else
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
- }
- else
- {
- if (IS_SINGLE(op)) /* C.EQ.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- }
- emit_fcompp(DRCTOP); // fcompp
- emit_fstsw_ax(DRCTOP); // fnstsw ax
- emit_sahf(DRCTOP); // sahf
- emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x33:
- case 0x3b:
- if (USE_SSE)
- {
- if (IS_SINGLE(op)) /* C.UEQ.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
- }
- else
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
- }
- else
- {
- if (IS_SINGLE(op)) /* C.UEQ.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- }
- emit_fucompp(DRCTOP); // fucompp
- emit_fstsw_ax(DRCTOP); // fnstsw ax
- emit_sahf(DRCTOP); // sahf
- emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x34:
- case 0x3c:
- if (USE_SSE)
- {
- if (IS_SINGLE(op)) /* C.OLT.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
- }
- else
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
- }
- else
- {
- if (IS_SINGLE(op)) /* C.OLT.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- }
- emit_fcompp(DRCTOP); // fcompp
- emit_fstsw_ax(DRCTOP); // fnstsw ax
- emit_sahf(DRCTOP); // sahf
- emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x35:
- case 0x3d:
- if (USE_SSE)
- {
- if (IS_SINGLE(op)) /* C.ULT.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
- }
- else
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
- }
- else
- {
- if (IS_SINGLE(op)) /* C.ULT.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- }
- emit_fucompp(DRCTOP); // fucompp
- emit_fstsw_ax(DRCTOP); // fnstsw ax
- emit_sahf(DRCTOP); // sahf
- emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x36:
- case 0x3e:
- if (USE_SSE)
- {
- if (IS_SINGLE(op)) /* C.OLE.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg]
- }
- else
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setle [cf[x]]
- }
- else
- {
- if (IS_SINGLE(op)) /* C.OLE.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- }
- emit_fcompp(DRCTOP); // fcompp
- emit_fstsw_ax(DRCTOP); // fnstsw ax
- emit_sahf(DRCTOP); // sahf
- emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x37:
- case 0x3f:
- if (USE_SSE)
- {
- if (IS_SINGLE(op)) /* C.ULE.S */
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg]
- }
- else
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg]
- }
- emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setl [cf[x]]
- }
- else
- {
- if (IS_SINGLE(op)) /* C.ULE.S */
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- }
- emit_fucompp(DRCTOP); // fucompp
- emit_fstsw_ax(DRCTOP); // fnstsw ax
- emit_sahf(DRCTOP); // sahf
- emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
- }
- break;
- }
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
-}
-
-
-
-/***************************************************************************
- COP1X RECOMPILATION
-***************************************************************************/
-
-/*------------------------------------------------------------------
- recompile_cop1x
-------------------------------------------------------------------*/
-
-static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op)
-{
- if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
- {
- emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1
- emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception
- }
-
- switch (op & 0x3f)
- {
- case 0x00: /* LWXC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x01: /* LDXC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double
- emit_mov_m32_r32(DRCTOP, FPR64ADDRLO(FDREG), REG_EAX); // mov [fdreg].lo,eax
- emit_mov_m32_r32(DRCTOP, FPR64ADDRHI(FDREG), REG_EDX); // mov [fdreg].hi,edx
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x08: /* SWXC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4
- emit_push_m32(DRCTOP, FPR32ADDR(FSREG)); // push [fsreg]
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,8
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x09: /* SDXC1 */
- emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp
- emit_save_pc_before_call(DRCTOP); // save pc
- emit_push_m32(DRCTOP, FPR64ADDRHI(FSREG)); // push [fsreg].hi
- emit_push_m32(DRCTOP, FPR64ADDRLO(FSREG)); // push [fsreg].lo
- emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg]
- emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg]
- emit_push_r32(DRCTOP, REG_EAX); // push eax
- emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double
- emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12
- emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount]
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x0f: /* PREFX */
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x20: /* MADD.S */
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_faddp(DRCTOP); // faddp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x21: /* MADD.D */
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_faddp(DRCTOP); // faddp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x28: /* MSUB.S */
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg]
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_fsubrp(DRCTOP); // fsubrp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x29: /* MSUB.D */
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg]
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_fsubrp(DRCTOP); // fsubrp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x30: /* NMADD.S */
- if (USE_SSE)
- {
- emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg]
- emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_faddp(DRCTOP); // faddp
- emit_fchs(DRCTOP); // fchs
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x31: /* NMADD.D */
- if (USE_SSE)
- {
- emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg]
- emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_faddp(DRCTOP); // faddp
- emit_fchs(DRCTOP); // fchs
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x38: /* NMSUB.S */
- if (USE_SSE)
- {
- emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg]
- emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg]
- emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg]
- emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
- emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1
- }
- else
- {
- emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg]
- emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_fsubp(DRCTOP); // fsubp
- emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x39: /* NMSUB.D */
- if (USE_SSE)
- {
- emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg]
- emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg]
- emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg]
- emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0
- emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1
- }
- else
- {
- emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg]
- emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg]
- emit_fmulp(DRCTOP); // fmulp
- emit_fsubp(DRCTOP); // fsubrp
- emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg]
- }
- return RECOMPILE_SUCCESSFUL_CP(1,4);
-
- case 0x24: /* MADD.W */
- case 0x25: /* MADD.L */
- case 0x2c: /* MSUB.W */
- case 0x2d: /* MSUB.L */
- case 0x34: /* NMADD.W */
- case 0x35: /* NMADD.L */
- case 0x3c: /* NMSUB.W */
- case 0x3d: /* NMSUB.L */
- default:
- fprintf(stderr, "cop1x %X\n", op);
- break;
- }
- emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception
- return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING;
-}
diff --git a/src/emu/cpu/mips/mips3.c b/src/emu/cpu/mips/mips3.c
index 66627996f67..7f439c9d64e 100644
--- a/src/emu/cpu/mips/mips3.c
+++ b/src/emu/cpu/mips/mips3.c
@@ -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;
diff --git a/src/emu/cpu/mips/mips3.h b/src/emu/cpu/mips/mips3.h
index e0c22ab7ac0..3ab8ec82ec8 100644
--- a/src/emu/cpu/mips/mips3.h
+++ b/src/emu/cpu/mips/mips3.h
@@ -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,
diff --git a/src/emu/cpu/mips/mips3com.c b/src/emu/cpu/mips/mips3com.c
index 2e10d38d6a4..dfbc777d3a2 100644
--- a/src/emu/cpu/mips/mips3com.c
+++ b/src/emu/cpu/mips/mips3com.c
@@ -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;
}
}
diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c
index 50dadefb448..11666848934 100644
--- a/src/emu/cpu/mips/mips3drc.c
+++ b/src/emu/cpu/mips/mips3drc.c
@@ -1,13 +1,33 @@
/***************************************************************************
mips3drc.c
- x86 Dynamic recompiler for MIPS III/IV emulator.
- Written by Aaron Giles
- Philosophy: this is intended to be a very basic implementation of a
- dynamic compiler in order to keep things simple. There are certainly
- more optimizations that could be added but for now, we keep it
- strictly to NOP stripping and LUI optimizations.
+ Universal machine language-based MIPS III/IV emulator.
+
+ 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:
+
+ * Add DRC option to flush PC before calling memory handlers
+
+ * Map MIPS registers to i5-i7 (or more)
+ - should rely on backend hints to know how many to assign
+ - add instrumentation to figure out which ones are most used
+ - on entry, load registers; on exit, flush them
+ - also flush before calling debugger
+
+ * Constant tracking? (hasn't bought us much in the past)
+
+ * Customized mapped/unmapped memory handlers
+ - create 3 sets of handlers: cached, uncached, general
+ - default to general
+ - in general case, if cached use RECALL to point to cached code
+ - (same for uncached)
+ - in cached/uncached case, fall back to general case
***************************************************************************/
@@ -17,8 +37,9 @@
#include "mips3com.h"
#include "mips3fe.h"
#include "deprecat.h"
-#include "cpu/x86log.h"
#include "cpu/drcfe.h"
+#include "cpu/drcuml.h"
+#include "cpu/drcumlsh.h"
extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
@@ -28,21 +49,25 @@ extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
DEBUGGING
***************************************************************************/
-#define LOG_CODE (0)
-#define SINGLE_INSTRUCTION_MODE (0)
+#define FORCE_C_BACKEND (0)
+#define LOG_UML (0)
+#define LOG_NATIVE (0)
-#ifdef ENABLE_DEBUGGER
-#define COMPARE_AGAINST_C (0)
-#else
-#define COMPARE_AGAINST_C (0)
-#endif
+#define SINGLE_INSTRUCTION_MODE (0)
+#define PRINTF_EXCEPTIONS (0)
+
+#define PROBE_ADDRESS ~0
/***************************************************************************
- CONFIGURATION
+ CONSTANTS
***************************************************************************/
+/* map variables */
+#define MAPVAR_PC MVAR(0)
+#define MAPVAR_CYCLES MVAR(1)
+
/* size of the execution code cache */
#define CACHE_SIZE (32 * 1024 * 1024)
@@ -52,13 +77,9 @@ extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4))
#define COMPILE_MAX_SEQUENCE 64
-/* hack when running comparison against the C core */
-#if COMPARE_AGAINST_C
-#undef MIPS3_COUNT_READ_CYCLES
-#undef MIPS3_CAUSE_READ_CYCLES
-#define MIPS3_COUNT_READ_CYCLES 0
-#define MIPS3_CAUSE_READ_CYCLES 0
-#endif
+/* exit codes */
+#define EXECUTE_OUT_OF_CYCLES 0
+#define EXECUTE_MISSING_CODE 1
@@ -66,9 +87,33 @@ extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
MACROS
***************************************************************************/
-#define SR mips3.core->cpr[0][COP0_Status]
-#define IS_FR0 (!(SR & SR_FR))
-#define IS_FR1 (SR & SR_FR)
+#ifdef LSB_FIRST
+#define LOPTR(x) ((UINT32 *)(x))
+#else
+#define LOPTR(x) ((UINT32 *)(x) + 1)
+#endif
+
+#define R32(reg) ((reg == 0) ? DRCUML_PTYPE_IMMEDIATE : DRCUML_PTYPE_MEMORY), ((reg) == 0) ? 0 : (FPTR)LOPTR(&mips3.core->r[reg])
+#define LO32 R32(REG_LO)
+#define HI32 R32(REG_HI)
+#define CPR032(reg) MEM(LOPTR(&mips3.core->cpr[0][reg]))
+#define CCR032(reg) MEM(LOPTR(&mips3.core->ccr[0][reg]))
+#define FPR32(reg) MEM((mips3.cstate->mode == 0) ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg])
+#define CCR132(reg) MEM(LOPTR(&mips3.core->ccr[1][reg]))
+#define CPR232(reg) MEM(LOPTR(&mips3.core->cpr[2][reg]))
+#define CCR232(reg) MEM(LOPTR(&mips3.core->ccr[2][reg]))
+
+#define R64(reg) ((reg == 0) ? DRCUML_PTYPE_IMMEDIATE : DRCUML_PTYPE_MEMORY), ((reg) == 0) ? 0 : (FPTR)&mips3.core->r[reg]
+#define LO64 R64(REG_LO)
+#define HI64 R64(REG_HI)
+#define CPR064(reg) MEM(&mips3.core->cpr[0][reg])
+#define CCR064(reg) MEM(&mips3.core->ccr[0][reg])
+#define FPR64(reg) MEM((mips3.cstate->mode == 0) ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg])
+#define CCR164(reg) MEM(&mips3.core->ccr[1][reg])
+#define CPR264(reg) MEM(&mips3.core->cpr[2][reg])
+#define CCR264(reg) MEM(&mips3.core->ccr[2][reg])
+
+#define FCCMASK(which) fcc_mask[(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)]
@@ -80,10 +125,10 @@ extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op);
typedef struct _fast_ram_info fast_ram_info;
struct _fast_ram_info
{
- offs_t start;
- offs_t end;
- UINT8 readonly;
- void * base;
+ offs_t start; /* start of the RAM block */
+ offs_t end; /* end of the RAM block */
+ UINT8 readonly; /* TRUE if read-only */
+ void * base; /* base in memory where the RAM lives */
};
@@ -91,14 +136,43 @@ struct _fast_ram_info
typedef struct _hotspot_info hotspot_info;
struct _hotspot_info
{
- offs_t pc;
- UINT32 opcode;
- UINT32 cycles;
+ offs_t pc; /* PC to consider */
+ UINT32 opcode; /* required opcode at that PC */
+ UINT32 cycles; /* number of cycles to eat when hit */
};
-/* opaque drc-specific info */
-typedef struct _mips3drc_data mips3drc_data;
+/* internal compiler state */
+typedef struct _compiler_state compiler_state;
+struct _compiler_state
+{
+ UINT32 cycles; /* accumulated cycles */
+ UINT8 checkints; /* need to check interrupts before next instruction */
+ UINT8 checksoftints; /* need to check software interrupts before next instruction */
+ drcuml_codelabel labelnum; /* index for local labels */
+};
+
+
+/* cache-based state */
+typedef struct _mips3_cache_state mips3_cache_state;
+struct _mips3_cache_state
+{
+ /* parameters for subroutines */
+ UINT64 numcycles; /* return value from gettotalcycles */
+ UINT32 mode; /* current global mode */
+
+ /* tables */
+ UINT8 fpmode[4]; /* FPU mode table */
+ UINT64 slt_table[32]; /* FLAGS table for slt */
+ UINT64 sltu_table[32]; /* FLAGS table for sltu */
+ UINT32 c_un_table[32]; /* FLAGS table for c_un */
+ UINT32 c_eq_table[32]; /* FLAGS table for c_eq */
+ UINT32 c_ueq_table[32]; /* FLAGS table for c_ueq */
+ UINT32 c_olt_table[32]; /* FLAGS table for c_olt */
+ UINT32 c_ult_table[32]; /* FLAGS table for c_ult */
+ UINT32 c_ole_table[32]; /* FLAGS table for c_ole */
+ UINT32 c_ule_table[32]; /* FLAGS table for c_ule */
+};
/* MIPS3 registers */
@@ -106,37 +180,43 @@ typedef struct _mips3_regs mips3_regs;
struct _mips3_regs
{
/* core state */
- UINT8 * cache; /* base of the cache */
- mips3_state * core; /* pointer to the core MIPS3 state */
- drcfe_state * drcfe; /* pointer to the DRC front-end state */
- drc_core * drc; /* pointer to the DRC core */
- mips3drc_data * drcdata; /* pointer to the DRC-specific data */
- UINT32 drcoptions; /* configurable DRC options */
+ drccache * cache; /* pointer to the DRC code cache */
+ drcuml_state * drcuml; /* DRC UML generator state */
+ drcfe_state * drcfe; /* pointer to the DRC front-end state */
+ UINT32 drcoptions; /* configurable DRC options */
+ mips3_state * core; /* pointer to the core MIPS3 state */
+ mips3_cache_state * cstate; /* state that needs to live in the cache */
/* internal stuff */
- UINT32 nextpc;
- UINT8 cache_dirty;
-
+ UINT8 cache_dirty; /* true if we need to flush the cache */
+
+ /* subroutines */
+ drcuml_codehandle * entry; /* entry point */
+ drcuml_codehandle * nocode; /* nocode exception handler */
+ drcuml_codehandle * out_of_cycles; /* out of cycles exception handler */
+ drcuml_codehandle * tlb_mismatch; /* tlb mismatch at current PC */
+ drcuml_codehandle * read8; /* read byte */
+ drcuml_codehandle * write8; /* write byte */
+ drcuml_codehandle * read16; /* read half */
+ drcuml_codehandle * write16; /* write half */
+ drcuml_codehandle * read32; /* read word */
+ drcuml_codehandle * read32mask; /* read word masked */
+ drcuml_codehandle * write32; /* write word */
+ drcuml_codehandle * write32mask; /* write word masked */
+ drcuml_codehandle * read64; /* read double */
+ drcuml_codehandle * read64mask; /* read double masked */
+ drcuml_codehandle * write64; /* write double */
+ drcuml_codehandle * write64mask; /* write double masked */
+ drcuml_codehandle * exception[EXCEPTION_COUNT]; /* array of exception handlers */
+ drcuml_codehandle * exception_norecover[EXCEPTION_COUNT]; /* array of no-recover exception handlers */
+
/* fast RAM */
- UINT32 fastram_select;
- fast_ram_info fastram[MIPS3_MAX_FASTRAM];
+ UINT32 fastram_select;
+ fast_ram_info fastram[MIPS3_MAX_FASTRAM];
/* hotspots */
- UINT32 hotspot_select;
- hotspot_info hotspot[MIPS3_MAX_HOTSPOTS];
-
- /* code logging */
- x86log_context *log;
-
-#if COMPARE_AGAINST_C
- /* memory state */
- UINT8 access_size;
- UINT8 access_type;
- offs_t access_addr;
- UINT64 access_data;
- UINT64 access_mask;
- memory_handlers orighandler;
-#endif
+ UINT32 hotspot_select;
+ hotspot_info hotspot[MIPS3_MAX_HOTSPOTS];
};
@@ -145,15 +225,37 @@ struct _mips3_regs
FUNCTION PROTOTYPES
***************************************************************************/
-static void mips3drc_init(void);
-static void mips3drc_exit(void);
+static void code_flush_cache(drcuml_state *drcuml);
+static void code_compile_block(drcuml_state *drcuml, UINT8 mode, offs_t pc);
-#if COMPARE_AGAINST_C
-static void execute_c_version(void);
-static void compare_c_version(void);
-static void mips3c_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int));
-static void mips3c_reset(void);
-#endif
+static void cfunc_printf_exception(void *param);
+static void cfunc_get_cycles(void *param);
+static void cfunc_printf_probe(void *param);
+
+static void static_generate_entry_point(drcuml_state *drcuml);
+static void static_generate_nocode_handler(drcuml_state *drcuml);
+static void static_generate_out_of_cycles(drcuml_state *drcuml);
+static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int recover, const char *name);
+static void static_generate_memory_accessor(drcuml_state *drcuml, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr);
+
+static void generate_update_cycles(drcuml_block *block, compiler_state *compiler, UINT32 nextpc, UINT32 *mempc, int allow_exception);
+static void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
+static void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static void generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg);
+static int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static int generate_special(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static int generate_regimm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static int generate_idt(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg);
+static int generate_get_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg);
+static int generate_cop0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static int generate_cop1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+static int generate_cop1x(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc);
+
+static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op);
+static const char *log_desc_flags_to_string(UINT32 flags);
+static void log_register_list(drcuml_state *drcuml, const char *string, UINT64 gprmask, UINT64 fprmask);
+static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent);
@@ -162,7 +264,380 @@ static void mips3c_reset(void);
***************************************************************************/
static mips3_regs mips3;
-static size_t allocatedsize;
+
+
+/* bit indexes for various FCCs */
+static const UINT32 fcc_mask[8] = { 1 << 23, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29, 1 << 30, 1 << 31 };
+
+/* lookup table for FP modes */
+static const UINT8 fpmode_source[4] =
+{
+ DRCUML_FMOD_ROUND,
+ DRCUML_FMOD_TRUNC,
+ DRCUML_FMOD_CEIL,
+ DRCUML_FMOD_FLOOR
+};
+
+/* flag lookup table for SLT */
+static const UINT64 slt_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ 0,
+ /* ...V. */ 1,
+ /* ...VC */ 1,
+ /* ..Z.. */ 0,
+ /* ..Z.C */ 0,
+ /* ..ZV. */ 1,
+ /* ..ZVC */ 1,
+ /* .S... */ 1,
+ /* .S..C */ 1,
+ /* .S.V. */ 0,
+ /* .S.VC */ 0,
+ /* .SZ.. */ 1,
+ /* .SZ.C */ 1,
+ /* .SZV. */ 0,
+ /* .SZVC */ 0,
+ /* U.... */ 0,
+ /* U...C */ 0,
+ /* U..V. */ 1,
+ /* U..VC */ 1,
+ /* U.Z.. */ 0,
+ /* U.Z.C */ 0,
+ /* U.ZV. */ 1,
+ /* U.ZVC */ 1,
+ /* US... */ 1,
+ /* US..C */ 1,
+ /* US.V. */ 0,
+ /* US.VC */ 0,
+ /* USZ.. */ 1,
+ /* USZ.C */ 1,
+ /* USZV. */ 0,
+ /* USZVC */ 0
+};
+
+/* flag lookup table for SLTU */
+static const UINT64 sltu_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ 1,
+ /* ...V. */ 0,
+ /* ...VC */ 1,
+ /* ..Z.. */ 0,
+ /* ..Z.C */ 1,
+ /* ..ZV. */ 0,
+ /* ..ZVC */ 1,
+ /* .S... */ 0,
+ /* .S..C */ 1,
+ /* .S.V. */ 0,
+ /* .S.VC */ 1,
+ /* .SZ.. */ 0,
+ /* .SZ.C */ 1,
+ /* .SZV. */ 0,
+ /* .SZVC */ 1,
+ /* U.... */ 0,
+ /* U...C */ 1,
+ /* U..V. */ 0,
+ /* U..VC */ 1,
+ /* U.Z.. */ 0,
+ /* U.Z.C */ 1,
+ /* U.ZV. */ 0,
+ /* U.ZVC */ 1,
+ /* US... */ 0,
+ /* US..C */ 1,
+ /* US.V. */ 0,
+ /* US.VC */ 1,
+ /* USZ.. */ 0,
+ /* USZ.C */ 1,
+ /* USZV. */ 0,
+ /* USZVC */ 1
+};
+
+/* flag lookup table for C.UN */
+static const UINT32 c_un_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ 0,
+ /* ...V. */ 0,
+ /* ...VC */ 0,
+ /* ..Z.. */ 0,
+ /* ..Z.C */ 0,
+ /* ..ZV. */ 0,
+ /* ..ZVC */ 0,
+ /* .S... */ 0,
+ /* .S..C */ 0,
+ /* .S.V. */ 0,
+ /* .S.VC */ 0,
+ /* .SZ.. */ 0,
+ /* .SZ.C */ 0,
+ /* .SZV. */ 0,
+ /* .SZVC */ 0,
+ /* U.... */ ~0,
+ /* U...C */ ~0,
+ /* U..V. */ ~0,
+ /* U..VC */ ~0,
+ /* U.Z.. */ ~0,
+ /* U.Z.C */ ~0,
+ /* U.ZV. */ ~0,
+ /* U.ZVC */ ~0,
+ /* US... */ ~0,
+ /* US..C */ ~0,
+ /* US.V. */ ~0,
+ /* US.VC */ ~0,
+ /* USZ.. */ ~0,
+ /* USZ.C */ ~0,
+ /* USZV. */ ~0,
+ /* USZVC */ ~0
+};
+
+/* flag lookup table for C.EQ */
+static const UINT32 c_eq_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ 0,
+ /* ...V. */ 0,
+ /* ...VC */ 0,
+ /* ..Z.. */ ~0,
+ /* ..Z.C */ ~0,
+ /* ..ZV. */ ~0,
+ /* ..ZVC */ ~0,
+ /* .S... */ 0,
+ /* .S..C */ 0,
+ /* .S.V. */ 0,
+ /* .S.VC */ 0,
+ /* .SZ.. */ ~0,
+ /* .SZ.C */ ~0,
+ /* .SZV. */ ~0,
+ /* .SZVC */ ~0,
+ /* U.... */ 0,
+ /* U...C */ 0,
+ /* U..V. */ 0,
+ /* U..VC */ 0,
+ /* U.Z.. */ 0,
+ /* U.Z.C */ 0,
+ /* U.ZV. */ 0,
+ /* U.ZVC */ 0,
+ /* US... */ 0,
+ /* US..C */ 0,
+ /* US.V. */ 0,
+ /* US.VC */ 0,
+ /* USZ.. */ 0,
+ /* USZ.C */ 0,
+ /* USZV. */ 0,
+ /* USZVC */ 0
+};
+
+/* flag lookup table for C.UEQ */
+static const UINT32 c_ueq_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ 0,
+ /* ...V. */ 0,
+ /* ...VC */ 0,
+ /* ..Z.. */ ~0,
+ /* ..Z.C */ ~0,
+ /* ..ZV. */ ~0,
+ /* ..ZVC */ ~0,
+ /* .S... */ 0,
+ /* .S..C */ 0,
+ /* .S.V. */ 0,
+ /* .S.VC */ 0,
+ /* .SZ.. */ ~0,
+ /* .SZ.C */ ~0,
+ /* .SZV. */ ~0,
+ /* .SZVC */ ~0,
+ /* U.... */ ~0,
+ /* U...C */ ~0,
+ /* U..V. */ ~0,
+ /* U..VC */ ~0,
+ /* U.Z.. */ ~0,
+ /* U.Z.C */ ~0,
+ /* U.ZV. */ ~0,
+ /* U.ZVC */ ~0,
+ /* US... */ ~0,
+ /* US..C */ ~0,
+ /* US.V. */ ~0,
+ /* US.VC */ ~0,
+ /* USZ.. */ ~0,
+ /* USZ.C */ ~0,
+ /* USZV. */ ~0,
+ /* USZVC */ ~0
+};
+
+/* flag lookup table for C.OLT */
+static const UINT32 c_olt_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ ~0,
+ /* ...V. */ 0,
+ /* ...VC */ ~0,
+ /* ..Z.. */ 0,
+ /* ..Z.C */ ~0,
+ /* ..ZV. */ 0,
+ /* ..ZVC */ ~0,
+ /* .S... */ 0,
+ /* .S..C */ ~0,
+ /* .S.V. */ 0,
+ /* .S.VC */ ~0,
+ /* .SZ.. */ 0,
+ /* .SZ.C */ ~0,
+ /* .SZV. */ 0,
+ /* .SZVC */ ~0,
+ /* U.... */ 0,
+ /* U...C */ 0,
+ /* U..V. */ 0,
+ /* U..VC */ 0,
+ /* U.Z.. */ 0,
+ /* U.Z.C */ 0,
+ /* U.ZV. */ 0,
+ /* U.ZVC */ 0,
+ /* US... */ 0,
+ /* US..C */ 0,
+ /* US.V. */ 0,
+ /* US.VC */ 0,
+ /* USZ.. */ 0,
+ /* USZ.C */ 0,
+ /* USZV. */ 0,
+ /* USZVC */ 0
+};
+
+/* flag lookup table for C.ULT */
+static const UINT32 c_ult_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ ~0,
+ /* ...V. */ 0,
+ /* ...VC */ ~0,
+ /* ..Z.. */ 0,
+ /* ..Z.C */ ~0,
+ /* ..ZV. */ 0,
+ /* ..ZVC */ ~0,
+ /* .S... */ 0,
+ /* .S..C */ ~0,
+ /* .S.V. */ 0,
+ /* .S.VC */ ~0,
+ /* .SZ.. */ 0,
+ /* .SZ.C */ ~0,
+ /* .SZV. */ 0,
+ /* .SZVC */ ~0,
+ /* U.... */ ~0,
+ /* U...C */ ~0,
+ /* U..V. */ ~0,
+ /* U..VC */ ~0,
+ /* U.Z.. */ ~0,
+ /* U.Z.C */ ~0,
+ /* U.ZV. */ ~0,
+ /* U.ZVC */ ~0,
+ /* US... */ ~0,
+ /* US..C */ ~0,
+ /* US.V. */ ~0,
+ /* US.VC */ ~0,
+ /* USZ.. */ ~0,
+ /* USZ.C */ ~0,
+ /* USZV. */ ~0,
+ /* USZVC */ ~0
+};
+
+/* flag lookup table for C.OLE */
+static const UINT32 c_ole_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ ~0,
+ /* ...V. */ 0,
+ /* ...VC */ ~0,
+ /* ..Z.. */ ~0,
+ /* ..Z.C */ ~0,
+ /* ..ZV. */ ~0,
+ /* ..ZVC */ ~0,
+ /* .S... */ 0,
+ /* .S..C */ ~0,
+ /* .S.V. */ 0,
+ /* .S.VC */ ~0,
+ /* .SZ.. */ ~0,
+ /* .SZ.C */ ~0,
+ /* .SZV. */ ~0,
+ /* .SZVC */ ~0,
+ /* U.... */ 0,
+ /* U...C */ 0,
+ /* U..V. */ 0,
+ /* U..VC */ 0,
+ /* U.Z.. */ 0,
+ /* U.Z.C */ 0,
+ /* U.ZV. */ 0,
+ /* U.ZVC */ 0,
+ /* US... */ 0,
+ /* US..C */ 0,
+ /* US.V. */ 0,
+ /* US.VC */ 0,
+ /* USZ.. */ 0,
+ /* USZ.C */ 0,
+ /* USZV. */ 0,
+ /* USZVC */ 0
+};
+
+/* flag lookup table for C.ULE */
+static const UINT32 c_ule_table_source[32] =
+{
+ /* ..... */ 0,
+ /* ....C */ ~0,
+ /* ...V. */ 0,
+ /* ...VC */ ~0,
+ /* ..Z.. */ ~0,
+ /* ..Z.C */ ~0,
+ /* ..ZV. */ ~0,
+ /* ..ZVC */ ~0,
+ /* .S... */ 0,
+ /* .S..C */ ~0,
+ /* .S.V. */ 0,
+ /* .S.VC */ ~0,
+ /* .SZ.. */ ~0,
+ /* .SZ.C */ ~0,
+ /* .SZV. */ ~0,
+ /* .SZVC */ ~0,
+ /* U.... */ ~0,
+ /* U...C */ ~0,
+ /* U..V. */ ~0,
+ /* U..VC */ ~0,
+ /* U.Z.. */ ~0,
+ /* U.Z.C */ ~0,
+ /* U.ZV. */ ~0,
+ /* U.ZVC */ ~0,
+ /* US... */ ~0,
+ /* US..C */ ~0,
+ /* US.V. */ ~0,
+ /* US.VC */ ~0,
+ /* USZ.. */ ~0,
+ /* USZ.C */ ~0,
+ /* USZV. */ ~0,
+ /* USZVC */ ~0
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ epc - compute the exception PC from a
+ descriptor
+-------------------------------------------------*/
+
+INLINE UINT32 epc(const opcode_desc *desc)
+{
+ return (desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc;
+}
+
+
+/*-------------------------------------------------
+ alloc_handle - allocate a handle if not
+ already allocated
+-------------------------------------------------*/
+
+INLINE void alloc_handle(drcuml_state *drcuml, drcuml_codehandle **handleptr, const char *name)
+{
+ if (*handleptr == NULL)
+ *handleptr = drcuml_handle_alloc(drcuml, name);
+}
@@ -183,30 +658,57 @@ static void mips3_init(mips3_flavor flavor, int bigendian, int index, int clock,
COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */
mips3fe_describe /* callback to describe a single instruction */
};
- size_t memsize = mips3com_init(NULL, flavor, bigendian, index, clock, config, irqcallback, NULL);
-
- /* allocate a cache and memory for the core data in a single block */
- allocatedsize = CACHE_SIZE + sizeof(*mips3.core) + memsize;
- mips3.core = osd_alloc_executable(allocatedsize);
- if (mips3.core == NULL)
- fatalerror("Unable to allocate cache of size %d\n", (UINT32)allocatedsize);
- mips3.cache = (UINT8 *)(mips3.core + 1) + memsize;
+ UINT32 flags = 0;
+ size_t extrasize;
+ void *extramem;
+
+ /* determine how much memory beyond the core size we need */
+ extrasize = mips3com_init(NULL, flavor, bigendian, index, clock, config, irqcallback, NULL);
+
+ /* allocate enough space for the cache and the core */
+ mips3.cache = drccache_alloc(CACHE_SIZE + sizeof(*mips3.core) + extrasize);
+ if (mips3.cache == NULL)
+ fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*mips3.core) + extrasize));
+
+ /* allocate the core and the extra memory */
+ mips3.core = drccache_memory_alloc_near(mips3.cache, sizeof(*mips3.core));
+ extramem = drccache_memory_alloc(mips3.cache, extrasize);
/* initialize the core */
- mips3com_init(mips3.core, flavor, bigendian, index, clock, config, irqcallback, mips3.core + 1);
-#if COMPARE_AGAINST_C
- mips3c_init(flavor, bigendian, index, clock, config, irqcallback);
-#endif
-
- /* initialize the DRC to use the cache */
- mips3drc_init();
- if (Machine->debug_mode || SINGLE_INSTRUCTION_MODE)
+ mips3com_init(mips3.core, flavor, bigendian, index, clock, config, irqcallback, extramem);
+
+ /* allocate memory for cache-local state and initialize it */
+ mips3.cstate = drccache_memory_alloc_near(mips3.cache, sizeof(*mips3.cstate));
+ memset(mips3.cstate, 0, sizeof(*mips3.cstate));
+ memcpy(mips3.cstate->fpmode, fpmode_source, sizeof(fpmode_source));
+ memcpy(mips3.cstate->slt_table, slt_table_source, sizeof(slt_table_source));
+ memcpy(mips3.cstate->sltu_table, sltu_table_source, sizeof(sltu_table_source));
+ memcpy(mips3.cstate->c_un_table, c_un_table_source, sizeof(c_un_table_source));
+ memcpy(mips3.cstate->c_eq_table, c_eq_table_source, sizeof(c_eq_table_source));
+ memcpy(mips3.cstate->c_ueq_table, c_ueq_table_source, sizeof(c_ueq_table_source));
+ memcpy(mips3.cstate->c_olt_table, c_olt_table_source, sizeof(c_olt_table_source));
+ memcpy(mips3.cstate->c_ult_table, c_ult_table_source, sizeof(c_ult_table_source));
+ memcpy(mips3.cstate->c_ole_table, c_ole_table_source, sizeof(c_ole_table_source));
+ memcpy(mips3.cstate->c_ule_table, c_ule_table_source, sizeof(c_ule_table_source));
+
+ /* initialize the UML generator */
+ if (FORCE_C_BACKEND)
+ flags |= DRCUML_OPTION_USE_C;
+ if (LOG_UML)
+ flags |= DRCUML_OPTION_LOG_UML;
+ if (LOG_NATIVE)
+ flags |= DRCUML_OPTION_LOG_NATIVE;
+ mips3.drcuml = drcuml_alloc(mips3.cache, flags, 2, 32, 2);
+ if (mips3.drcuml == NULL)
+ fatalerror("Error initializing the UML");
+
+ /* initialize the front-end helper */
+ if (SINGLE_INSTRUCTION_MODE)
feconfig.max_sequence = 1;
mips3.drcfe = drcfe_init(&feconfig, mips3.core);
-
- /* start up code logging */
- if (LOG_CODE)
- mips3.log = x86log_create_context("mips3drc.asm");
+
+ /* mark the cache dirty so it is updated on next execute */
+ mips3.cache_dirty = TRUE;
}
@@ -216,13 +718,9 @@ static void mips3_init(mips3_flavor flavor, int bigendian, int index, int clock,
static void mips3_reset(void)
{
- /* reset the common code and flush the cache */
+ /* reset the common code and mark the cache dirty */
mips3com_reset(mips3.core);
- drc_cache_reset(mips3.drc);
-
-#if COMPARE_AGAINST_C
- mips3c_reset();
-#endif
+ mips3.cache_dirty = TRUE;
}
@@ -233,14 +731,28 @@ static void mips3_reset(void)
static int mips3_execute(int cycles)
{
+ drcuml_state *drcuml = mips3.drcuml;
+ int execute_result;
+
/* reset the cache if dirty */
if (mips3.cache_dirty)
- drc_cache_reset(mips3.drc);
+ code_flush_cache(drcuml);
mips3.cache_dirty = FALSE;
/* execute */
mips3.core->icount = cycles;
- drc_execute(mips3.drc);
+ do
+ {
+ /* run as much as we can */
+ execute_result = drcuml_execute(drcuml, mips3.entry);
+
+ /* if we need to recompile, do it */
+ if (execute_result == EXECUTE_MISSING_CODE)
+ code_compile_block(drcuml, mips3.cstate->mode, mips3.core->pc);
+
+ } while (execute_result != EXECUTE_OUT_OF_CYCLES);
+
+ /* return the number of cycles executed */
return cycles - mips3.core->icount;
}
@@ -251,16 +763,10 @@ static int mips3_execute(int cycles)
static void mips3_exit(void)
{
- /* clean up code logging */
- if (LOG_CODE)
- x86log_free_context(mips3.log);
-
/* clean up the DRC */
drcfe_exit(mips3.drcfe);
- mips3drc_exit();
-
- /* free the cache */
- osd_free_executable(mips3.core, CACHE_SIZE + sizeof(*mips3.core));
+ drcuml_free(mips3.drcuml);
+ drccache_free(mips3.cache);
}
@@ -314,46 +820,2549 @@ static offs_t mips3_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT
/***************************************************************************
- COMMON UTILITIES
+ CACHE MANAGEMENT
***************************************************************************/
/*-------------------------------------------------
- fastram_ptr - return a pointer to the base of
- memory containing the given address, if it
- is within a fast RAM range; returns 0
- otherwise
+ code_flush_cache - flush the cache and
+ regenerate static code
-------------------------------------------------*/
-#ifdef PTR64
-static void *fastram_ptr(offs_t addr, int size, int iswrite)
+static void code_flush_cache(drcuml_state *drcuml)
{
- int ramnum;
+ /* empty the transient cache contents */
+ drcuml_reset(drcuml);
+
+ /* generate the entry point and out-of-cycles handlers */
+ static_generate_entry_point(drcuml);
+ static_generate_nocode_handler(drcuml);
+ static_generate_out_of_cycles(drcuml);
+
+ /* append exception handlers for various types */
+ static_generate_exception(drcuml, EXCEPTION_INTERRUPT, TRUE, "exception_interrupt");
+ static_generate_exception(drcuml, EXCEPTION_INTERRUPT, FALSE, "exception_interrupt_norecover");
+ static_generate_exception(drcuml, EXCEPTION_TLBMOD, TRUE, "exception_tlbmod");
+ static_generate_exception(drcuml, EXCEPTION_TLBLOAD, TRUE, "exception_tlbload");
+ static_generate_exception(drcuml, EXCEPTION_TLBSTORE, TRUE, "exception_tlbstore");
+ static_generate_exception(drcuml, EXCEPTION_SYSCALL, TRUE, "exception_syscall");
+ static_generate_exception(drcuml, EXCEPTION_BREAK, TRUE, "exception_break");
+ static_generate_exception(drcuml, EXCEPTION_INVALIDOP, TRUE, "exception_invalidop");
+ static_generate_exception(drcuml, EXCEPTION_BADCOP, TRUE, "exception_badcop");
+ static_generate_exception(drcuml, EXCEPTION_OVERFLOW, TRUE, "exception_overflow");
+ static_generate_exception(drcuml, EXCEPTION_TRAP, TRUE, "exception_trap");
+
+ /* add subroutines for memory accesses */
+ static_generate_memory_accessor(drcuml, 1, FALSE, FALSE, "read8", &mips3.read8);
+ static_generate_memory_accessor(drcuml, 1, TRUE, FALSE, "write8", &mips3.write8);
+ static_generate_memory_accessor(drcuml, 2, FALSE, FALSE, "read16", &mips3.read16);
+ static_generate_memory_accessor(drcuml, 2, TRUE, FALSE, "write16", &mips3.write16);
+ static_generate_memory_accessor(drcuml, 4, FALSE, FALSE, "read32", &mips3.read32);
+ static_generate_memory_accessor(drcuml, 4, FALSE, TRUE, "read32mask", &mips3.read32mask);
+ static_generate_memory_accessor(drcuml, 4, TRUE, FALSE, "write32", &mips3.write32);
+ static_generate_memory_accessor(drcuml, 4, TRUE, TRUE, "write32mask", &mips3.write32mask);
+ static_generate_memory_accessor(drcuml, 8, FALSE, FALSE, "read64", &mips3.read64);
+ static_generate_memory_accessor(drcuml, 8, FALSE, TRUE, "read64mask", &mips3.read64mask);
+ static_generate_memory_accessor(drcuml, 8, TRUE, FALSE, "write64", &mips3.write64);
+ static_generate_memory_accessor(drcuml, 8, TRUE, TRUE, "write64mask", &mips3.write64mask);
+}
- /* only direct maps are supported */
- if (addr < 0x80000000 || addr >= 0xc0000000)
- return NULL;
- addr &= 0x1fffffff;
- /* adjust address for endianness */
- if (mips3.core->bigendian)
+/*-------------------------------------------------
+ code_compile_block - compile a block of the
+ given mode at the specified pc
+-------------------------------------------------*/
+
+static void code_compile_block(drcuml_state *drcuml, UINT8 mode, offs_t pc)
+{
+ compiler_state compiler = { 0 };
+ const opcode_desc *seqhead, *seqlast;
+ const opcode_desc *desclist;
+ int override = FALSE;
+ drcuml_block *block;
+ jmp_buf errorbuf;
+
+ /* get a description of this sequence */
+ desclist = drcfe_describe_code(mips3.drcfe, pc);
+ if (LOG_UML)
+ log_opcode_desc(drcuml, desclist, 0);
+
+ /* if we get an error back, flush the cache and try again */
+ if (setjmp(errorbuf) != 0)
+ code_flush_cache(drcuml);
+
+ /* start the block */
+ block = drcuml_block_begin(drcuml, 4096, &errorbuf);
+
+ /* loop until we get through all instruction sequences */
+ for (seqhead = desclist; seqhead != NULL; seqhead = seqlast->next)
{
- if (size == 1)
- addr ^= 3;
- else if (size == 2)
- addr ^= 2;
+ const opcode_desc *curdesc;
+ UINT32 nextpc;
+
+ /* add a code log entry */
+ if (LOG_UML)
+ UML_COMMENT(block, "-------------------------"); // comment
+
+ /* determine the last instruction in this sequence */
+ for (seqlast = seqhead; seqlast != NULL; seqlast = seqlast->next)
+ if (seqlast->flags & OPFLAG_END_SEQUENCE)
+ break;
+ assert(seqlast != NULL);
+
+ /* if we don't have a hash for this mode/pc, or if we are overriding all, add one */
+ if (override || !drcuml_hash_exists(drcuml, mode, seqhead->pc))
+ UML_HASH(block, mode, seqhead->pc); // hash mode,pc
+
+ /* if we already have a hash, and this is the first sequence, assume that we */
+ /* are recompiling due to being out of sync and allow future overrides */
+ else if (seqhead == desclist)
+ {
+ override = TRUE;
+ UML_HASH(block, mode, seqhead->pc); // hash mode,pc
+ }
+
+ /* otherwise, redispatch to that fixed PC and skip the rest of the processing */
+ else
+ {
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
+ UML_HASHJMP(block, IMM(mips3.cstate->mode), IMM(seqhead->pc), mips3.nocode);
+ // hashjmp <mode>,seqhead->pc,nocode
+ continue;
+ }
+
+ /* validate this code block if we're not pointing into ROM */
+ if (memory_get_write_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, seqhead->physpc) != NULL)
+ generate_checksum_block(block, &compiler, seqhead, seqlast);
+
+ /* label this instruction, if it may be jumped to locally */
+ if (seqhead->flags & OPFLAG_IS_BRANCH_TARGET)
+ UML_LABEL(block, seqhead->pc | 0x80000000); // label seqhead->pc | 0x80000000
+
+ /* iterate over instructions in the sequence and compile them */
+ for (curdesc = seqhead; curdesc != seqlast->next; curdesc = curdesc->next)
+ generate_sequence_instruction(block, &compiler, curdesc);
+
+ /* if we need to return to the start, do it */
+ if (seqlast->flags & OPFLAG_RETURN_TO_START)
+ nextpc = pc;
+
+ /* otherwise we just go to the next instruction */
+ else
+ nextpc = seqlast->pc + (seqlast->skipslots + 1) * 4;
+
+ /* count off cycles and go there */
+ generate_update_cycles(block, &compiler, nextpc, NULL, TRUE); // <subtract cycles>
+
+ /* if the last instruction can change modes, use a variable mode; otherwise, assume the same mode */
+ if (seqlast->flags & OPFLAG_CAN_CHANGE_MODES)
+ UML_HASHJMP(block, MEM(&mips3.cstate->mode), IMM(nextpc), mips3.nocode);// hashjmp <mode>,nextpc,nocode
+ else if (seqlast->next == NULL || seqlast->next->pc != nextpc)
+ UML_HASHJMP(block, IMM(mips3.cstate->mode), IMM(nextpc), mips3.nocode); // hashjmp <mode>,nextpc,nocode
}
- /* search for fastram */
+ /* end the sequence */
+ drcuml_block_end(block);
+}
+
+
+
+/***************************************************************************
+ C FUNCTION CALLBACKS
+***************************************************************************/
+
+/*-------------------------------------------------
+ cfunc_printf_exception - log any exceptions that
+ aren't interrupts
+-------------------------------------------------*/
+
+static void cfunc_printf_exception(void *param)
+{
+ printf("Exception: EPC=%08X Cause=%08X BadVAddr=%08X Jmp=%08X\n", (UINT32)mips3.core->cpr[0][COP0_EPC], (UINT32)mips3.core->cpr[0][COP0_Cause], (UINT32)mips3.core->cpr[0][COP0_BadVAddr], mips3.core->pc);
+ cfunc_printf_probe((void *)(FPTR)mips3.core->cpr[0][COP0_EPC]);
+}
+
+
+/*-------------------------------------------------
+ cfunc_get_cycles - compute the total number
+ of cycles executed so far
+-------------------------------------------------*/
+
+static void cfunc_get_cycles(void *param)
+{
+ UINT64 *dest = param;
+ *dest = activecpu_gettotalcycles();
+}
+
+
+/*-------------------------------------------------
+ cfunc_printf_probe - print the current CPU
+ state and return
+-------------------------------------------------*/
+
+static void cfunc_printf_probe(void *param)
+{
+ UINT32 pc = (UINT32)(FPTR)param;
+
+ printf(" PC=%08X r1=%08X%08X r2=%08X%08X r3=%08X%08X\n",
+ pc,
+ (UINT32)(mips3.core->r[1] >> 32), (UINT32)mips3.core->r[1],
+ (UINT32)(mips3.core->r[2] >> 32), (UINT32)mips3.core->r[2],
+ (UINT32)(mips3.core->r[3] >> 32), (UINT32)mips3.core->r[3]);
+ printf(" r4=%08X%08X r5=%08X%08X r6=%08X%08X r7=%08X%08X\n",
+ (UINT32)(mips3.core->r[4] >> 32), (UINT32)mips3.core->r[4],
+ (UINT32)(mips3.core->r[5] >> 32), (UINT32)mips3.core->r[5],
+ (UINT32)(mips3.core->r[6] >> 32), (UINT32)mips3.core->r[6],
+ (UINT32)(mips3.core->r[7] >> 32), (UINT32)mips3.core->r[7]);
+ printf(" r8=%08X%08X r9=%08X%08X r10=%08X%08X r11=%08X%08X\n",
+ (UINT32)(mips3.core->r[8] >> 32), (UINT32)mips3.core->r[8],
+ (UINT32)(mips3.core->r[9] >> 32), (UINT32)mips3.core->r[9],
+ (UINT32)(mips3.core->r[10] >> 32), (UINT32)mips3.core->r[10],
+ (UINT32)(mips3.core->r[11] >> 32), (UINT32)mips3.core->r[11]);
+ printf("r12=%08X%08X r13=%08X%08X r14=%08X%08X r15=%08X%08X\n",
+ (UINT32)(mips3.core->r[12] >> 32), (UINT32)mips3.core->r[12],
+ (UINT32)(mips3.core->r[13] >> 32), (UINT32)mips3.core->r[13],
+ (UINT32)(mips3.core->r[14] >> 32), (UINT32)mips3.core->r[14],
+ (UINT32)(mips3.core->r[15] >> 32), (UINT32)mips3.core->r[15]);
+ printf("r16=%08X%08X r17=%08X%08X r18=%08X%08X r19=%08X%08X\n",
+ (UINT32)(mips3.core->r[16] >> 32), (UINT32)mips3.core->r[16],
+ (UINT32)(mips3.core->r[17] >> 32), (UINT32)mips3.core->r[17],
+ (UINT32)(mips3.core->r[18] >> 32), (UINT32)mips3.core->r[18],
+ (UINT32)(mips3.core->r[19] >> 32), (UINT32)mips3.core->r[19]);
+ printf("r20=%08X%08X r21=%08X%08X r22=%08X%08X r23=%08X%08X\n",
+ (UINT32)(mips3.core->r[20] >> 32), (UINT32)mips3.core->r[20],
+ (UINT32)(mips3.core->r[21] >> 32), (UINT32)mips3.core->r[21],
+ (UINT32)(mips3.core->r[22] >> 32), (UINT32)mips3.core->r[22],
+ (UINT32)(mips3.core->r[23] >> 32), (UINT32)mips3.core->r[23]);
+ printf("r24=%08X%08X r25=%08X%08X r26=%08X%08X r27=%08X%08X\n",
+ (UINT32)(mips3.core->r[24] >> 32), (UINT32)mips3.core->r[24],
+ (UINT32)(mips3.core->r[25] >> 32), (UINT32)mips3.core->r[25],
+ (UINT32)(mips3.core->r[26] >> 32), (UINT32)mips3.core->r[26],
+ (UINT32)(mips3.core->r[27] >> 32), (UINT32)mips3.core->r[27]);
+ printf("r28=%08X%08X r29=%08X%08X r30=%08X%08X r31=%08X%08X\n",
+ (UINT32)(mips3.core->r[28] >> 32), (UINT32)mips3.core->r[28],
+ (UINT32)(mips3.core->r[29] >> 32), (UINT32)mips3.core->r[29],
+ (UINT32)(mips3.core->r[30] >> 32), (UINT32)mips3.core->r[30],
+ (UINT32)(mips3.core->r[31] >> 32), (UINT32)mips3.core->r[31]);
+ printf(" hi=%08X%08X lo=%08X%08X\n",
+ (UINT32)(mips3.core->r[REG_HI] >> 32), (UINT32)mips3.core->r[REG_HI],
+ (UINT32)(mips3.core->r[REG_LO] >> 32), (UINT32)mips3.core->r[REG_LO]);
+}
+
+
+
+/***************************************************************************
+ STATIC CODEGEN
+***************************************************************************/
+
+/*-------------------------------------------------
+ static_generate_entry_point - generate a
+ static entry point
+-------------------------------------------------*/
+
+static void static_generate_entry_point(drcuml_state *drcuml)
+{
+ drcuml_codelabel skip = 1;
+ drcuml_block *block;
+ jmp_buf errorbuf;
+
+ /* if we get an error back, we're screwed */
+ if (setjmp(errorbuf) != 0)
+ fatalerror("Unrecoverable error in static_generate_entry_point");
+
+ /* begin generating */
+ block = drcuml_block_begin(drcuml, 20, &errorbuf);
+
+ /* forward references */
+ alloc_handle(drcuml, &mips3.exception_norecover[EXCEPTION_INTERRUPT], "interrupt_norecover");
+ alloc_handle(drcuml, &mips3.nocode, "nocode");
+
+ alloc_handle(drcuml, &mips3.entry, "entry");
+ UML_HANDLE(block, mips3.entry); // handle entry
+
+ /* reset the FPU mode */
+ UML_AND(block, IREG(0), CCR164(31), IMM(3)); // and i0,ccr1[31],3
+ UML_LOAD1U(block, IREG(0), &mips3.cstate->fpmode[0], IREG(0)); // load1u i0,fpmode,i0
+ UML_SETFMOD(block, IREG(0)); // setfmod i0
+
+ /* check for interrupts */
+ UML_AND(block, IREG(0), CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status]
+ UML_ANDf(block, IREG(0), IREG(0), IMM(0xfc00), FLAGS_Z); // and i0,i0,0xfc00,Z
+ UML_JMPc(block, IF_Z, skip); // jmp skip,Z
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_IE)); // test [Status],SR_IE
+ UML_JMPc(block, IF_Z, skip); // jmp skip,Z
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_EXL | SR_ERL)); // test [Status],SR_EXL | SR_ERL
+ UML_JMPc(block, IF_NZ, skip); // jmp skip,NZ
+ UML_MOV(block, IREG(0), MEM(&mips3.core->pc)); // mov i0,pc
+ UML_MOV(block, IREG(1), IMM(0)); // mov i1,0
+ UML_CALLH(block, mips3.exception_norecover[EXCEPTION_INTERRUPT]); // callh exception_norecover
+ UML_LABEL(block, skip); // skip:
+
+ /* generate a hash jump via the current mode and PC */
+ UML_HASHJMP(block, MEM(&mips3.cstate->mode), MEM(&mips3.core->pc), mips3.nocode);// hashjmp <mode>,<pc>,nocode
+
+ drcuml_block_end(block);
+}
+
+
+/*-------------------------------------------------
+ static_generate_nocode_handler - generate an
+ exception handler for "out of code"
+-------------------------------------------------*/
+
+static void static_generate_nocode_handler(drcuml_state *drcuml)
+{
+ drcuml_block *block;
+ jmp_buf errorbuf;
+
+ /* if we get an error back, we're screwed */
+ if (setjmp(errorbuf) != 0)
+ fatalerror("Unrecoverable error in static_generate_nocode_handler");
+
+ /* begin generating */
+ block = drcuml_block_begin(drcuml, 10, &errorbuf);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(drcuml, &mips3.nocode, "nocode");
+ UML_HANDLE(block, mips3.nocode); // handle nocode
+ UML_GETEXP(block, IREG(0)); // getexp i0
+ UML_MOV(block, MEM(&mips3.core->pc), IREG(0)); // mov [pc],i0
+ UML_EXIT(block, IMM(EXECUTE_MISSING_CODE)); // exit EXECUTE_MISSING_CODE
+
+ drcuml_block_end(block);
+}
+
+
+/*-------------------------------------------------
+ static_generate_out_of_cycles - generate an
+ out of cycles exception handler
+-------------------------------------------------*/
+
+static void static_generate_out_of_cycles(drcuml_state *drcuml)
+{
+ drcuml_block *block;
+ jmp_buf errorbuf;
+
+ /* if we get an error back, we're screwed */
+ if (setjmp(errorbuf) != 0)
+ fatalerror("Unrecoverable error in static_generate_out_of_cycles");
+
+ /* begin generating */
+ block = drcuml_block_begin(drcuml, 10, &errorbuf);
+
+ /* generate a hash jump via the current mode and PC */
+ alloc_handle(drcuml, &mips3.out_of_cycles, "out_of_cycles");
+ UML_HANDLE(block, mips3.out_of_cycles); // handle out_of_cycles
+ UML_GETEXP(block, IREG(0)); // getexp i0
+ UML_MOV(block, MEM(&mips3.core->pc), IREG(0)); // mov <pc>,i0
+ UML_EXIT(block, IMM(EXECUTE_OUT_OF_CYCLES)); // exit EXECUTE_OUT_OF_CYCLES
+
+ drcuml_block_end(block);
+}
+
+
+/*-------------------------------------------------
+ static_generate_exception - generate a static
+ exception handler
+-------------------------------------------------*/
+
+static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int recover, const char *name)
+{
+ UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180;
+ drcuml_codelabel next = 1;
+ drcuml_block *block;
+ jmp_buf errorbuf;
+
+ /* if we get an error back, we're screwed */
+ if (setjmp(errorbuf) != 0)
+ fatalerror("Unrecoverable error in static_generate_exception");
+
+ /* begin generating */
+ block = drcuml_block_begin(drcuml, 1024, &errorbuf);
+
+ /* add a global entry for this */
+ if (recover)
+ {
+ alloc_handle(drcuml, &mips3.exception[exception], name);
+ UML_HANDLE(block, mips3.exception[exception]); // handle name
+ }
+ else
+ {
+ alloc_handle(drcuml, &mips3.exception_norecover[exception], name);
+ UML_HANDLE(block, mips3.exception_norecover[exception]); // handle name
+ }
+
+ /* exception parameter is expected to be the fault address in this case */
+ if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE)
+ {
+ /* set BadVAddr to the fault address */
+ UML_GETEXP(block, CPR032(COP0_BadVAddr)); // mov [BadVAddr],exp
+
+ /* set the upper bits of EntryHi to the fault page */
+ UML_AND(block, IREG(0), IREG(0), IMM(0xffffe000)); // and i0,i0,0xffffe000
+ UML_AND(block, IREG(1), CPR032(COP0_EntryHi), IMM(0x000000ff)); // and i1,[EntryHi],0x000000ff
+ UML_OR(block, CPR032(COP0_EntryHi), IREG(0), IREG(1)); // or [EntryHi],i0,i1
+
+ /* set the lower bits of Context to the fault page */
+ UML_SHR(block, IREG(0), IREG(0), IMM(9)); // shr i0,i0,9
+ UML_AND(block, IREG(1), CPR032(COP0_Context), IMM(0xff800000)); // and i1,[Context],0xff800000
+ UML_OR(block, CPR032(COP0_Context), IREG(0), IREG(1)); // or [Context],i0,i1
+ }
+
+ /* set the EPC and Cause registers */
+ if (recover)
+ {
+ UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC
+ UML_RECOVER(block, IREG(1), MAPVAR_CYCLES); // recover i1,CYCLES
+ }
+
+ UML_AND(block, IREG(2), CPR032(COP0_Cause), IMM(~0x800000ff)); // and i2,[Cause],~0x800000ff
+ UML_TEST(block, IREG(0), IMM(1)); // test i0,1
+ UML_JMPc(block, IF_Z, next); // jz <next>
+ UML_OR(block, IREG(2), IREG(2), IMM(0x80000000)); // or i2,i2,0x80000000
+ UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1
+ UML_LABEL(block, next); // <next>:
+ UML_MOV(block, CPR032(COP0_EPC), IREG(0)); // mov [EPC],i0
+ UML_OR(block, CPR032(COP0_Cause), IREG(2), IMM(exception << 2)); // or [Cause],i2,exception << 2
+
+ /* set EXL in the SR */
+ UML_OR(block, CPR032(COP0_Status), CPR032(COP0_Status), IMM(SR_EXL)); // or [Status],[Status],SR_EXL
+
+ /* optionally print exceptions */
+ if (PRINTF_EXCEPTIONS && exception != EXCEPTION_INTERRUPT && exception != EXCEPTION_SYSCALL)
+ UML_CALLC(block, cfunc_printf_exception, NULL); // callc cfunc_printf_exception,NULL
+
+ /* choose our target PC */
+ UML_MOV(block, IREG(0), IMM(0xbfc00200 + offset)); // mov i0,0xbfc00200 + offset
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_BEV)); // test [Status],SR_BEV
+ UML_MOVc(block, IF_Z, IREG(0), IMM(0x80000000 + offset)); // mov i0,0x80000000 + offset,z
+
+ /* adjust cycles */
+ UML_SUBf(block, MEM(&mips3.core->icount), MEM(&mips3.core->icount), IREG(1), FLAGS_S); // sub icount,icount,cycles,S
+ UML_EXHc(block, IF_S, mips3.out_of_cycles, IREG(0)); // exh out_of_cycles,i0
+
+ UML_HASHJMP(block, MEM(&mips3.cstate->mode), IREG(0), mips3.nocode); // hashjmp <mode>,i0,nocode
+
+ drcuml_block_end(block);
+}
+
+
+/*------------------------------------------------------------------
+ static_generate_memory_accessor
+------------------------------------------------------------------*/
+
+static void static_generate_memory_accessor(drcuml_state *drcuml, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr)
+{
+ /* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
+ /* on exit, read result is in I0 */
+ /* routine trashes I0-I3 */
+ drcuml_codehandle *exception_target = mips3.exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD];
+ drcuml_block *block;
+ jmp_buf errorbuf;
+ int label = 0;
+ int ramnum;
+
+ /* if we get an error back, we're screwed */
+ if (setjmp(errorbuf) != 0)
+ fatalerror("Unrecoverable error in static_generate_exception");
+
+ /* begin generating */
+ block = drcuml_block_begin(drcuml, 1024, &errorbuf);
+
+ /* add a global entry for this */
+ alloc_handle(drcuml, handleptr, name);
+ UML_HANDLE(block, *handleptr); // handle *handleptr
+
+ /* general case: assume paging and perform a translation */
+ UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12
+ UML_LOAD4(block, IREG(3), mips3.core->tlb_table, IREG(3)); // load4 i3,[tlb_table],i3
+ UML_TEST(block, IREG(3), IMM(iswrite ? 1 : 2)); // test i3,iswrite ? 1 : 2
+ UML_EXHc(block, IF_NZ, exception_target, IREG(0)); // exnz exception_target,i0
+ UML_AND(block, IREG(0), IREG(0), IMM(0xfff)); // and i0,i0,0xfff
+ UML_AND(block, IREG(3), IREG(3), IMM(~0xfff)); // and i3,i3,~0xfff
+ UML_OR(block, IREG(0), IREG(0), IREG(3)); // or i0,i0,i3
+
for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++)
- if (mips3.fastram[ramnum].base != NULL && (!iswrite || !mips3.fastram[ramnum].readonly) &&
- addr >= mips3.fastram[ramnum].start && addr <= mips3.fastram[ramnum].end)
+ if (!Machine->debug_mode && mips3.fastram[ramnum].base != NULL && (!iswrite || !mips3.fastram[ramnum].readonly))
+ {
+ void *fastbase = (UINT8 *)mips3.fastram[ramnum].base - mips3.fastram[ramnum].start;
+ UINT32 skip = label++;
+ if (mips3.fastram[ramnum].end != 0xffffffff)
+ {
+ UML_CMP(block, IREG(0), IMM(mips3.fastram[ramnum].end)); // cmp i0,end
+ UML_JMPc(block, IF_A, skip); // ja skip
+ }
+ if (mips3.fastram[ramnum].start != 0x00000000)
+ {
+ UML_CMP(block, IREG(0), IMM(mips3.fastram[ramnum].start)); // cmp i0,fastram_start
+ UML_JMPc(block, IF_B, skip); // jb skip
+ }
+
+ if (!iswrite)
+ {
+ if (size == 1)
+ {
+ UML_XOR(block, IREG(0), IREG(0), IMM(mips3.core->bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)));
+ // xor i0,i0,bytexor
+ UML_LOAD1U(block, IREG(0), fastbase, IREG(0)); // load1u i0,fastbase,i0
+ }
+ else if (size == 2)
+ {
+ UML_SHR(block, IREG(0), IREG(0), IMM(1)); // shr i0,i0,1
+ UML_XOR(block, IREG(0), IREG(0), IMM(mips3.core->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
+ // xor i0,i0,bytexor
+ UML_LOAD2U(block, IREG(0), fastbase, IREG(0)); // load2u i0,fastbase,i0
+ }
+ else if (size == 4)
+ {
+ UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2
+ UML_LOAD4(block, IREG(0), fastbase, IREG(0)); // load4 i0,fastbase,i0
+ }
+ else if (size == 8)
+ {
+ UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3
+ UML_DLOAD8(block, IREG(0), fastbase, IREG(0)); // dload8 i0,fastbase,i0
+ UML_DROR(block, IREG(0), IREG(0), IMM(32 * (mips3.core->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))));
+ // dror i0,i0,32*bytexor
+ }
+ UML_RET(block); // ret
+ }
+ else
+ {
+ if (size == 1)
+ {
+ UML_XOR(block, IREG(0), IREG(0), IMM(mips3.core->bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0)));
+ // xor i0,i0,bytexor
+ UML_STORE1(block, fastbase, IREG(0), IREG(1)); // store1 fastbase,i0,i1
+ }
+ else if (size == 2)
+ {
+ UML_SHR(block, IREG(0), IREG(0), IMM(1)); // shr i0,i0,1
+ UML_XOR(block, IREG(0), IREG(0), IMM(mips3.core->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
+ // xor i0,i0,bytexor
+ UML_STORE2(block, fastbase, IREG(0), IREG(1)); // store2 fastbase,i0,i1
+ }
+ else if (size == 4)
+ {
+ UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2
+ if (ismasked)
+ {
+ UML_LOAD4(block, IREG(3), fastbase, IREG(0)); // load4 i3,fastbase,i0
+ UML_AND(block, IREG(1), IREG(1), IREG(2)); // and i1,i1,i2
+ UML_XOR(block, IREG(2), IREG(2), IMM(0xffffffff)); // xor i2,i2,0xfffffffff
+ UML_AND(block, IREG(3), IREG(3), IREG(2)); // and i3,i3,i2
+ UML_OR(block, IREG(1), IREG(1), IREG(3)); // or i1,i1,i3
+ }
+ UML_STORE4(block, fastbase, IREG(0), IREG(1)); // store4 fastbase,i0,i1
+ }
+ else if (size == 8)
+ {
+ UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3
+ UML_DROR(block, IREG(1), IREG(1), IMM(32 * (mips3.core->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))));
+ // dror i1,i1,32*bytexor
+ if (ismasked)
+ {
+ UML_DROR(block, IREG(2), IREG(2), IMM(32 * (mips3.core->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0))));
+ // dror i2,i2,32*bytexor
+ UML_DLOAD8(block, IREG(3), fastbase, IREG(0)); // dload8 i3,fastbase,i0
+ UML_DAND(block, IREG(1), IREG(1), IREG(2)); // dand i1,i1,i2
+ UML_DXOR(block, IREG(2), IREG(2), IMM(U64(0xffffffffffffffff)));
+ // dxor i2,i2,0xfffffffffffffffff
+ UML_DAND(block, IREG(3), IREG(3), IREG(2)); // dand i3,i3,i2
+ UML_DOR(block, IREG(1), IREG(1), IREG(3)); // dor i1,i1,i3
+ }
+ UML_DSTORE8(block, fastbase, IREG(0), IREG(1)); // dstore8 fastbase,i0,i1
+ }
+ UML_RET(block); // ret
+ }
+
+ UML_LABEL(block, skip); // skip:
+ }
+
+ switch (size)
+ {
+ case 1:
+ if (iswrite)
+ UML_WRITE1(block, PROGRAM, IREG(0), IREG(1)); // write1 i0,i1
+ else
+ UML_READ1U(block, IREG(0), PROGRAM, IREG(0)); // read1u i0,i0
+ break;
+
+ case 2:
+ if (iswrite)
+ UML_WRITE2(block, PROGRAM, IREG(0), IREG(1)); // write2 i0,i1
+ else
+ UML_READ2U(block, IREG(0), PROGRAM, IREG(0)); // read2u i0,i0
+ break;
+
+ case 4:
+ if (iswrite)
+ {
+ if (!ismasked)
+ UML_WRITE4(block, PROGRAM, IREG(0), IREG(1)); // write4 PROGRAM,i0,i1
+ else
+ UML_WRIT4M(block, PROGRAM, IREG(0), IREG(2), IREG(1)); // writ4m PROGRAM,i0,i2,i1
+ }
+ else
+ {
+ if (!ismasked)
+ UML_READ4(block, IREG(0), PROGRAM, IREG(0)); // read4 i0,PROGRAM,i0
+ else
+ UML_READ4M(block, IREG(0), PROGRAM, IREG(0), IREG(2)); // read4m i0,PROGRAM,i0,i2
+ }
+ break;
+
+ case 8:
+ if (iswrite)
+ {
+ if (!ismasked)
+ UML_DWRITE8(block, PROGRAM, IREG(0), IREG(1)); // dwrite8 PROGRAM,i0,i1
+ else
+ UML_DWRIT8M(block, PROGRAM, IREG(0), IREG(2), IREG(1)); // dwrit8m PROGRAM,i0,i2,i1
+ }
+ else
+ {
+ if (!ismasked)
+ UML_DREAD8(block, IREG(0), PROGRAM, IREG(0)); // dread8 i0,PROGRAM,i0
+ else
+ UML_DREAD8M(block, IREG(0), PROGRAM, IREG(0), IREG(2)); // dread8m i0,PROGRAM,i0,i2
+ }
+ break;
+ }
+ UML_RET(block); // ret
+
+ drcuml_block_end(block);
+}
+
+
+
+/***************************************************************************
+ CODE GENERATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generate_update_cycles - generate code to
+ subtract cycles from the icount and generate
+ an exception if out
+-------------------------------------------------*/
+
+static void generate_update_cycles(drcuml_block *block, compiler_state *compiler, UINT32 nextpc, UINT32 *mempc, int allow_exception)
+{
+ /* check software interrupts if pending */
+ if (compiler->checksoftints)
+ {
+ drcuml_codelabel skip;
+
+ compiler->checksoftints = FALSE;
+ UML_AND(block, IREG(0), CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status]
+ UML_ANDf(block, IREG(0), IREG(0), IMM(0x0300), FLAGS_Z); // and i0,i0,0x0300,Z
+ UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z
+ if (mempc == NULL)
+ UML_MOV(block, IREG(0), IMM(nextpc)); // mov i0,nextpc
+ else
+ UML_MOV(block, IREG(0), MEM(mempc)); // mov i0,[mempc]
+ UML_MOV(block, IREG(1), IMM(compiler->cycles)); // mov i1,cycles
+ UML_CALLH(block, mips3.exception_norecover[EXCEPTION_INTERRUPT]); // callh interrupt_norecover
+ UML_LABEL(block, skip); // skip:
+ }
+
+ /* check full interrupts if pending */
+ if (compiler->checkints)
+ {
+ drcuml_codelabel skip;
+
+ compiler->checkints = FALSE;
+ UML_AND(block, IREG(0), CPR032(COP0_Cause), CPR032(COP0_Status)); // and i0,[Cause],[Status]
+ UML_ANDf(block, IREG(0), IREG(0), IMM(0xfc00), FLAGS_Z); // and i0,i0,0xfc00,Z
+ UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_IE)); // test [Status],SR_IE
+ UML_JMPc(block, IF_Z, skip); // jmp skip,Z
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_EXL | SR_ERL)); // test [Status],SR_EXL | SR_ERL
+ UML_JMPc(block, IF_NZ, skip); // jmp skip,NZ
+ if (mempc == NULL)
+ UML_MOV(block, IREG(0), IMM(nextpc)); // mov i0,nextpc
+ else
+ UML_MOV(block, IREG(0), MEM(mempc)); // mov i0,[mempc]
+ UML_MOV(block, IREG(1), IMM(compiler->cycles)); // mov i1,cycles
+ UML_CALLH(block, mips3.exception_norecover[EXCEPTION_INTERRUPT]); // callh interrupt_norecover
+ UML_LABEL(block, skip); // skip:
+ }
+
+ /* account for cycles */
+ if (compiler->cycles > 0)
+ {
+ UML_SUBf(block, MEM(&mips3.core->icount), MEM(&mips3.core->icount), MAPVAR_CYCLES, allow_exception ? FLAGS_S : 0);
+ // sub icount,icount,cycles,S
+ UML_MAPVAR(block, MAPVAR_CYCLES, 0); // mapvar cycles,0
+ if (allow_exception)
{
- return (UINT8 *)mips3.fastram[ramnum].base + (addr - mips3.fastram[ramnum].start);
+ if (mempc == NULL)
+ UML_EXHc(block, IF_S, mips3.out_of_cycles, IMM(nextpc)); // exh out_of_cycles,nextpc
+ else
+ UML_EXHc(block, IF_S, mips3.out_of_cycles, MEM(mempc)); // exh out_of_cycles,<mempc>
}
+ }
+ compiler->cycles = 0;
+}
+
+
+/*-------------------------------------------------
+ generate_checksum_block - generate code to
+ validate a sequence of opcodes
+-------------------------------------------------*/
+
+static void generate_checksum_block(drcuml_block *block, compiler_state *compiler, const opcode_desc *seqhead, const opcode_desc *seqlast)
+{
+ const opcode_desc *curdesc;
+ if (LOG_UML)
+ UML_COMMENT(block, "[Validation for %08X]", seqhead->pc); // comment
+
+ /* loose verify or single instruction: just compare and fail */
+ if (!(mips3.drcoptions & MIPS3DRC_STRICT_VERIFY) || seqhead->next == NULL)
+ {
+ UML_LOAD4(block, IREG(0), seqhead->opptr.l, IMM(0)); // load4 i0,*opptr
+ UML_CMP(block, IREG(0), IMM(*seqhead->opptr.l)); // cmp i0,*opptr
+ UML_EXHc(block, IF_NE, mips3.nocode, IMM(epc(seqhead))); // exne nocode,seqhead->pc
+ }
+
+ /* full verification; sum up everything */
+ else
+ {
+ UINT32 sum = 0;
+ UML_LOAD4(block, IREG(0), seqhead->opptr.l, IMM(0)); // load4 i0,*opptr
+ sum += *seqhead->opptr.l;
+ for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next)
+ {
+ UML_LOAD4(block, IREG(1), curdesc->opptr.l, IMM(0)); // load4 i1,*opptr
+ UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1
+ sum += *curdesc->opptr.l;
+ }
+ UML_CMP(block, IREG(0), IMM(sum)); // cmp i0,sum
+ UML_EXHc(block, IF_NE, mips3.nocode, IMM(epc(seqhead))); // exne nocode,seqhead->pc
+ }
+}
+
+
+/*-------------------------------------------------
+ generate_sequence_instruction - generate code
+ for a single instruction in a sequence
+-------------------------------------------------*/
+
+static void generate_sequence_instruction(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ offs_t expc;
+ int hotnum;
+
+ /* add an entry for the log */
+ if (LOG_UML)
+ log_add_disasm_comment(block, desc->pc, *desc->opptr.l);
+
+ /* set the PC map variable */
+ expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc;
+ UML_MAPVAR(block, MAPVAR_PC, expc); // mapvar PC,expc
+
+ /* accumulate total cycles */
+ compiler->cycles += desc->cycles;
+
+ /* is this a hotspot? */
+ for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++)
+ if (desc->pc == mips3.hotspot[hotnum].pc && *desc->opptr.l == mips3.hotspot[hotnum].opcode)
+ {
+ compiler->cycles += mips3.hotspot[hotnum].cycles;
+ break;
+ }
+
+ /* update the icount map variable */
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+
+ /* if we want a probe, add it here */
+ if (desc->pc == PROBE_ADDRESS)
+ UML_CALLC(block, cfunc_printf_probe, desc->pc); // callc cfunc_printf_probe,desc->pc
+
+ /* if we are debugging, call the debugger */
+ if (Machine->debug_mode)
+ {
+ UML_MOV(block, MEM(&mips3.core->pc), IMM(desc->pc)); // mov [pc],desc->pc
+ UML_DEBUG(block, IMM(desc->pc)); // debug desc->pc
+ }
+
+ /* validate our TLB entry at this PC; if we fail, we need to recompile */
+ if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
+ {
+ UML_CMP(block, MEM(&mips3.core->tlb_table[desc->pc >> 12]),
+ IMM(mips3.core->tlb_table[desc->pc >> 12])); // cmp [tlbentry],*tlbentry
+ UML_EXHc(block, IF_NE, mips3.tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE
+ }
+
+ /* if this is an invalid opcode, generate the exception now */
+ if (desc->flags & OPFLAG_INVALID_OPCODE)
+ UML_EXH(block, mips3.exception[EXCEPTION_INVALIDOP], IMM(0)); // exh invalidop,0
+
+ /* otherwise, it's a regular instruction */
+ else
+ {
+ /* compile the instruction */
+ if (!generate_opcode(block, compiler, desc))
+ fatalerror("Unimplemented op %08X (%02X,%02X)", *desc->opptr.l, *desc->opptr.l >> 26, *desc->opptr.l & 0x3f);
+ }
+}
+
+
+/*------------------------------------------------------------------
+ generate_delay_slot_and_branch
+------------------------------------------------------------------*/
+
+static void generate_delay_slot_and_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 linkreg)
+{
+ compiler_state compiler_temp = *compiler;
+ UINT32 op = *desc->opptr.l;
+
+ /* set the link if needed */
+ if (linkreg != 0)
+ UML_DSEXT4(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dsext4 <linkreg>,desc->pc + 8
+
+ /* compile the delay slot using temporary compiler state */
+ assert(desc->delay != NULL);
+ generate_sequence_instruction(block, &compiler_temp, desc->delay); // <next instruction>
+
+ /* update the cycles and jump through the hash table to the target */
+ if (desc->targetpc != BRANCH_TARGET_DYNAMIC)
+ {
+ generate_update_cycles(block, &compiler_temp, desc->targetpc, NULL, TRUE); // <subtract cycles>
+ if (desc->flags & OPFLAG_INTRABLOCK_BRANCH)
+ UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000
+ else
+ UML_HASHJMP(block, IMM(mips3.cstate->mode), IMM(desc->targetpc), mips3.nocode);
+ // hashjmp <mode>,desc->targetpc,nocode
+ }
+ else
+ {
+ generate_update_cycles(block, &compiler_temp, 0, LOPTR(&mips3.core->r[RSREG]), TRUE);
+ // <subtract cycles>
+ UML_HASHJMP(block, IMM(mips3.cstate->mode), R32(RSREG), mips3.nocode); // hashjmp <mode>,<rsreg>,nocode
+ }
+
+ /* update the label */
+ compiler->labelnum = compiler_temp.labelnum;
+
+ /* reset the mapvar to the current cycles */
+ UML_MAPVAR(block, MAPVAR_CYCLES, compiler->cycles); // mapvar CYCLES,compiler->cycles
+}
- return NULL;
+
+/*-------------------------------------------------
+ generate_opcode - generate code for a specific
+ opcode
+-------------------------------------------------*/
+
+static int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op >> 26;
+ drcuml_codelabel skip;
+
+ switch (opswitch)
+ {
+ /* ----- sub-groups ----- */
+
+ case 0x00: /* SPECIAL - MIPS I */
+ return generate_special(block, compiler, desc);
+
+ case 0x01: /* REGIMM - MIPS I */
+ return generate_regimm(block, compiler, desc);
+
+ case 0x1c: /* IDT-specific */
+ return generate_idt(block, compiler, desc);
+
+
+ /* ----- jumps and branches ----- */
+
+ case 0x02: /* J - MIPS I */
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ return TRUE;
+
+ case 0x03: /* JAL - MIPS I */
+ generate_delay_slot_and_branch(block, compiler, desc, 31); // <next instruction + hashjmp>
+ return TRUE;
+
+ case 0x04: /* BEQ - MIPS I */
+ case 0x14: /* BEQL - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_JMPc(block, IF_NE, skip = compiler->labelnum++); // jmp skip,NE
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ return TRUE;
+
+ case 0x05: /* BNE - MIPS I */
+ case 0x15: /* BNEL - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_JMPc(block, IF_E, skip = compiler->labelnum++); // jmp skip,E
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ return TRUE;
+
+ case 0x06: /* BLEZ - MIPS I */
+ case 0x16: /* BLEZL - MIPS II */
+ if (RSREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), IMM(0)); // dcmp <rsreg>,0
+ UML_JMPc(block, IF_G, skip = compiler->labelnum++); // jmp skip,G
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ }
+ else
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ return TRUE;
+
+ case 0x07: /* BGTZ - MIPS I */
+ case 0x17: /* BGTZL - MIPS II */
+ UML_DCMP(block, R64(RSREG), IMM(0)); // dcmp <rsreg>,0
+ UML_JMPc(block, IF_LE, skip = compiler->labelnum++); // jmp skip,LE
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ return TRUE;
+
+
+ /* ----- immediate arithmetic ----- */
+
+ case 0x0f: /* LUI - MIPS I */
+ if (RTREG != 0)
+ UML_DSEXT4(block, R64(RTREG), IMM(SIMMVAL << 16)); // dsext4 <rtreg>,SIMMVAL << 16
+ return TRUE;
+
+ case 0x08: /* ADDI - MIPS I */
+ if (mips3.drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
+ {
+ UML_ADDf(block, IREG(0), R32(RSREG), IMM(SIMMVAL), FLAGS_V); // add i0,<rsreg>,SIMMVAL,V
+ UML_EXHc(block, IF_V, mips3.exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0
+ }
+ else
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ if (RTREG != 0)
+ UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0
+ return TRUE;
+
+ case 0x09: /* ADDIU - MIPS I */
+ if (RTREG != 0)
+ {
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL,V
+ UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0
+ }
+ return TRUE;
+
+ case 0x18: /* DADDI - MIPS III */
+ if (mips3.drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
+ {
+ UML_DADDf(block, IREG(0), R64(RSREG), IMM(SIMMVAL), FLAGS_V); // dadd i0,<rsreg>,SIMMVAL,V
+ UML_EXHc(block, IF_V, mips3.exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0
+ }
+ else
+ UML_DADD(block, IREG(0), R64(RSREG), IMM(SIMMVAL)); // dadd i0,<rsreg>,SIMMVAL
+ if (RTREG != 0)
+ UML_DMOV(block, R64(RTREG), IREG(0)); // dmov <rtreg>,i0
+ return TRUE;
+
+ case 0x19: /* DADDIU - MIPS III */
+ if (RTREG != 0)
+ UML_DADD(block, R64(RTREG), R64(RSREG), IMM(SIMMVAL)); // dadd <rtreg>,<rsreg>,SIMMVAL
+ return TRUE;
+
+ case 0x0c: /* ANDI - MIPS I */
+ if (RTREG != 0)
+ UML_DAND(block, R64(RTREG), R64(RSREG), IMM(UIMMVAL)); // dand <rtreg>,<rsreg>,UIMMVAL
+ return TRUE;
+
+ case 0x0d: /* ORI - MIPS I */
+ if (RTREG != 0)
+ UML_DOR(block, R64(RTREG), R64(RSREG), IMM(UIMMVAL)); // dor <rtreg>,<rsreg>,UIMMVAL
+ return TRUE;
+
+ case 0x0e: /* XORI - MIPS I */
+ if (RTREG != 0)
+ UML_DXOR(block, R64(RTREG), R64(RSREG), IMM(UIMMVAL)); // dxor <rtreg>,<rsreg>,UIMMVAL
+ return TRUE;
+
+ case 0x0a: /* SLTI - MIPS I */
+ if (RTREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_DFLAGS(block, R64(RTREG), (UINT64)~0, mips3.cstate->slt_table); // dflags <rtreg>,~0,slt_table
+ }
+ return TRUE;
+
+ case 0x0b: /* SLTIU - MIPS I */
+ if (RTREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_DFLAGS(block, R64(RTREG), (UINT64)~0, mips3.cstate->sltu_table);// dflags <rtreg>,~0,sltu_table
+ }
+ return TRUE;
+
+
+ /* ----- memory load operations ----- */
+
+ case 0x20: /* LB - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read8); // callh read8
+ if (RTREG != 0)
+ UML_DSEXT1(block, R64(RTREG), IREG(0)); // dsext1 <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x21: /* LH - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read16); // callh read16
+ if (RTREG != 0)
+ UML_DSEXT2(block, R64(RTREG), IREG(0)); // dsext2 <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x23: /* LW - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read32); // callh read32
+ if (RTREG != 0)
+ UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x24: /* LBU - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read8); // callh read8
+ if (RTREG != 0)
+ UML_DZEXT1(block, R64(RTREG), IREG(0)); // dzext1 <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x25: /* LHU - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read16); // callh read16
+ if (RTREG != 0)
+ UML_DZEXT2(block, R64(RTREG), IREG(0)); // dzext2 <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x27: /* LWU - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read32); // callh read32
+ if (RTREG != 0)
+ UML_DZEXT4(block, R64(RTREG), IREG(0)); // dzext4 <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x37: /* LD - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read64); // callh read64
+ if (RTREG != 0)
+ UML_DMOV(block, R64(RTREG), IREG(0)); // dmov <rtreg>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x22: /* LWL - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ if (!mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x18)); // xor i4,i4,0x18
+ UML_SHR(block, IREG(2), IMM(~0), IREG(4)); // shr i2,~0,i4
+ UML_CALLH(block, mips3.read32mask); // callh read32mask
+ if (RTREG != 0)
+ {
+ UML_SHL(block, IREG(2), IMM(~0), IREG(4)); // shl i2,~0,i4
+ UML_XOR(block, IREG(2), IREG(2), IMM(~0)); // xor i2,i2,~0
+ UML_SHL(block, IREG(0), IREG(0), IREG(4)); // shl i0,i0,i4
+ UML_AND(block, IREG(2), IREG(2), R32(RTREG)); // and i2,i2,<rtreg>
+ UML_OR(block, IREG(0), IREG(0), IREG(2)); // or i0,i0,i2
+ UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0
+ }
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x26: /* LWR - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ if (mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x18)); // xor i4,i4,0x18
+ UML_SHL(block, IREG(2), IMM(~0), IREG(4)); // shl i2,~0,i4
+ UML_CALLH(block, mips3.read32mask); // callh read32mask
+ if (RTREG != 0)
+ {
+ UML_SHR(block, IREG(2), IMM(~0), IREG(4)); // shr i2,~0,i4
+ UML_XOR(block, IREG(2), IREG(2), IMM(~0)); // xor i2,i2,~0
+ UML_SHR(block, IREG(0), IREG(0), IREG(4)); // shr i0,i0,i4
+ UML_AND(block, IREG(2), IREG(2), R32(RTREG)); // and i2,i2,<rtreg>
+ UML_OR(block, IREG(0), IREG(0), IREG(2)); // or i0,i0,i2
+ UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0
+ }
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x1a: /* LDL - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ if (!mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x38)); // xor i4,i4,0x38
+ UML_DSHR(block, IREG(2), IMM((UINT64)~0), IREG(4)); // dshr i2,~0,i4
+ UML_CALLH(block, mips3.read64mask); // callh read64mask
+ if (RTREG != 0)
+ {
+ UML_DSHL(block, IREG(2), IMM((UINT64)~0), IREG(4)); // dshl i2,~0,i4
+ UML_DXOR(block, IREG(2), IREG(2), IMM((UINT64)~0)); // dxor i2,i2,~0
+ UML_DSHL(block, IREG(0), IREG(0), IREG(4)); // dshl i0,i0,i4
+ UML_DAND(block, IREG(2), IREG(2), R64(RTREG)); // dand i2,i2,<rtreg>
+ UML_DOR(block, R64(RTREG), IREG(0), IREG(2)); // dor <rtreg>,i0,i2
+ }
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x1b: /* LDR - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ if (mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x38)); // xor i4,i4,0x38
+ UML_DSHL(block, IREG(2), IMM((UINT64)~0), IREG(4)); // dshl i2,~0,i4
+ UML_CALLH(block, mips3.read64mask); // callh read64mask
+ if (RTREG != 0)
+ {
+ UML_DSHR(block, IREG(2), IMM((UINT64)~0), IREG(4)); // dshr i2,~0,i4
+ UML_DXOR(block, IREG(2), IREG(2), IMM((UINT64)~0)); // dxor i2,i2,~0
+ UML_DSHR(block, IREG(0), IREG(0), IREG(4)); // dshr i0,i0,i4
+ UML_DAND(block, IREG(2), IREG(2), R64(RTREG)); // dand i2,i2,<rtreg>
+ UML_DOR(block, R64(RTREG), IREG(0), IREG(2)); // dor <rtreg>,i0,i2
+ }
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x31: /* LWC1 - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read32); // callh read32
+ UML_MOV(block, FPR32(RTREG), IREG(0)); // mov <cpr1_rt>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x35: /* LDC1 - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read64); // callh read64
+ UML_DMOV(block, FPR64(RTREG), IREG(0)); // dmov <cpr1_rt>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x32: /* LWC2 - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read32); // callh read32
+ UML_DZEXT4(block, CPR264(RTREG), IREG(0)); // dzext4 <cpr2_rt>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x36: /* LDC2 - MIPS II */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_CALLH(block, mips3.read64); // callh read64
+ UML_DMOV(block, CPR264(RTREG), IREG(0)); // dmov <cpr2_rt>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+
+ /* ----- memory store operations ----- */
+
+ case 0x28: /* SB - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_MOV(block, IREG(1), R32(RTREG)); // mov i1,<rtreg>
+ UML_CALLH(block, mips3.write8); // callh write8
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x29: /* SH - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_MOV(block, IREG(1), R32(RTREG)); // mov i1,<rtreg>
+ UML_CALLH(block, mips3.write16); // callh write16
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x2b: /* SW - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_MOV(block, IREG(1), R32(RTREG)); // mov i1,<rtreg>
+ UML_CALLH(block, mips3.write32); // callh write32
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x3f: /* SD - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_DMOV(block, IREG(1), R64(RTREG)); // dmov i1,<rtreg>
+ UML_CALLH(block, mips3.write64); // callh write64
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x2a: /* SWL - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ UML_MOV(block, IREG(1), R32(RTREG)); // mov i1,<rtreg>
+ if (!mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x18)); // xor i4,i4,0x18
+ UML_SHR(block, IREG(2), IMM(~0), IREG(4)); // shr i2,~0,i4
+ UML_SHR(block, IREG(1), IREG(1), IREG(4)); // shr i1,i1,i4
+ UML_CALLH(block, mips3.write32mask); // callh write32mask
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x2e: /* SWR - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ UML_MOV(block, IREG(1), R32(RTREG)); // mov i1,<rtreg>
+ if (mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x18)); // xor i4,i4,0x18
+ UML_SHL(block, IREG(2), IMM(~0), IREG(4)); // shl i2,~0,i4
+ UML_SHL(block, IREG(1), IREG(1), IREG(4)); // shl i1,i1,i4
+ UML_CALLH(block, mips3.write32mask); // callh write32mask
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x2c: /* SDL - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ UML_DMOV(block, IREG(1), R64(RTREG)); // dmov i1,<rtreg>
+ if (!mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x38)); // xor i4,i4,0x38
+ UML_DSHR(block, IREG(2), IMM((UINT64)~0), IREG(4)); // dshr i2,~0,i4
+ UML_DSHR(block, IREG(1), IREG(1), IREG(4)); // dshr i1,i1,i4
+ UML_CALLH(block, mips3.write64mask); // callh write64mask
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x2d: /* SDR - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_SHL(block, IREG(4), IREG(0), IMM(3)); // shl i4,i0,3
+ UML_DMOV(block, IREG(1), R64(RTREG)); // dmov i1,<rtreg>
+ if (mips3.core->bigendian)
+ UML_XOR(block, IREG(4), IREG(4), IMM(0x38)); // xor i4,i4,0x38
+ UML_DSHL(block, IREG(2), IMM((UINT64)~0), IREG(4)); // dshl i2,~0,i4
+ UML_DSHL(block, IREG(1), IREG(1), IREG(4)); // dshl i1,i1,i4
+ UML_CALLH(block, mips3.write64mask); // callh write64mask
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x39: /* SWC1 - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_MOV(block, IREG(1), FPR32(RTREG)); // mov i1,<cpr1_rt>
+ UML_CALLH(block, mips3.write32); // callh write32
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x3d: /* SDC1 - MIPS III */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_DMOV(block, IREG(1), FPR64(RTREG)); // dmov i1,<cpr1_rt>
+ UML_CALLH(block, mips3.write64); // callh write64
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x3a: /* SWC2 - MIPS I */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_MOV(block, IREG(1), CPR232(RTREG)); // mov i1,<cpr2_rt>
+ UML_CALLH(block, mips3.write32); // callh write32
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x3e: /* SDC2 - MIPS II */
+ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL
+ UML_DMOV(block, IREG(1), CPR264(RTREG)); // dmov i1,<cpr2_rt>
+ UML_CALLH(block, mips3.write64); // callh write64
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+
+ /* ----- effective no-ops ----- */
+
+ case 0x2f: /* CACHE - MIPS II */
+ case 0x33: /* PREF - MIPS IV */
+ return TRUE;
+
+
+ /* ----- coprocessor instructions ----- */
+
+ case 0x10: /* COP0 - MIPS I */
+ return generate_cop0(block, compiler, desc);
+
+ case 0x11: /* COP1 - MIPS I */
+ return generate_cop1(block, compiler, desc);
+
+ case 0x13: /* COP1X - MIPS IV */
+ return generate_cop1x(block, compiler, desc);
+
+ case 0x12: /* COP2 - MIPS I */
+ UML_EXH(block, mips3.exception[EXCEPTION_INVALIDOP], IMM(0)); // exh invalidop,0
+ return TRUE;
+
+
+ /* ----- unimplemented/illegal instructions ----- */
+
+// case 0x30: /* LL - MIPS II */ logerror("mips3 Unhandled op: LL\n"); break;
+// case 0x34: /* LLD - MIPS III */ logerror("mips3 Unhandled op: LLD\n"); break;
+// case 0x38: /* SC - MIPS II */ logerror("mips3 Unhandled op: SC\n"); break;
+// case 0x3c: /* SCD - MIPS III */ logerror("mips3 Unhandled op: SCD\n"); break;
+// default: /* ??? */ invalid_instruction(op); break;
+ }
+
+ return FALSE;
}
+
+
+/*-------------------------------------------------
+ generate_special - compile opcodes in the
+ 'SPECIAL' group
+-------------------------------------------------*/
+
+static int generate_special(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op & 63;
+
+ switch (opswitch)
+ {
+ /* ----- shift instructions ----- */
+
+ case 0x00: /* SLL - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SHL(block, IREG(0), R32(RTREG), IMM(SHIFT)); // shl i0,<rtreg>,<shift>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x02: /* SRL - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SHR(block, IREG(0), R32(RTREG), IMM(SHIFT)); // shr i0,<rtreg>,<shift>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x03: /* SRA - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SAR(block, IREG(0), R32(RTREG), IMM(SHIFT)); // sar i0,<rtreg>,<shift>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x04: /* SLLV - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SHL(block, IREG(0), R32(RTREG), R32(RSREG)); // shl i0,<rtreg>,<rsreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x06: /* SRLV - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SHR(block, IREG(0), R32(RTREG), R32(RSREG)); // shr i0,<rtreg>,<rsreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x07: /* SRAV - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SAR(block, IREG(0), R32(RTREG), R32(RSREG)); // sar i0,<rtreg>,<rsreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x38: /* DSLL - MIPS III */
+ if (RDREG != 0)
+ UML_DSHL(block, R64(RDREG), R64(RTREG), IMM(SHIFT)); // dshl <rdreg>,<rtreg>,<shift>
+ return TRUE;
+
+ case 0x3a: /* DSRL - MIPS III */
+ if (RDREG != 0)
+ UML_DSHR(block, R64(RDREG), R64(RTREG), IMM(SHIFT)); // dshr <rdreg>,<rtreg>,<shift>
+ return TRUE;
+
+ case 0x3b: /* DSRA - MIPS III */
+ if (RDREG != 0)
+ UML_DSAR(block, R64(RDREG), R64(RTREG), IMM(SHIFT)); // dsar <rdreg>,<rtreg>,<shift>
+ return TRUE;
+
+ case 0x3c: /* DSLL32 - MIPS III */
+ if (RDREG != 0)
+ UML_DSHL(block, R64(RDREG), R64(RTREG), IMM(SHIFT + 32)); // dshl <rdreg>,<rtreg>,<shift>+32
+ return TRUE;
+
+ case 0x3e: /* DSRL32 - MIPS III */
+ if (RDREG != 0)
+ UML_DSHR(block, R64(RDREG), R64(RTREG), IMM(SHIFT + 32)); // dshr <rdreg>,<rtreg>,<shift>+32
+ return TRUE;
+
+ case 0x3f: /* DSRA32 - MIPS III */
+ if (RDREG != 0)
+ UML_DSAR(block, R64(RDREG), R64(RTREG), IMM(SHIFT + 32)); // dsar <rdreg>,<rtreg>,<shift>+32
+ return TRUE;
+
+ case 0x14: /* DSLLV - MIPS III */
+ if (RDREG != 0)
+ UML_DSHL(block, R64(RDREG), R64(RTREG), R64(RSREG)); // dshl <rdreg>,<rtreg>,<rsreg>
+ return TRUE;
+
+ case 0x16: /* DSRLV - MIPS III */
+ if (RDREG != 0)
+ UML_DSHR(block, R64(RDREG), R64(RTREG), R64(RSREG)); // dshr <rdreg>,<rtreg>,<rsreg>
+ return TRUE;
+
+ case 0x17: /* DSRAV - MIPS III */
+ if (RDREG != 0)
+ UML_DSAR(block, R64(RDREG), R64(RTREG), R64(RSREG)); // dsar <rdreg>,<rtreg>,<rsreg>
+ return TRUE;
+
+
+ /* ----- basic arithmetic ----- */
+
+ case 0x20: /* ADD - MIPS I */
+ if (mips3.drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
+ {
+ UML_ADDf(block, IREG(0), R32(RSREG), R32(RTREG), FLAGS_V); // add i0,<rsreg>,<rtreg>,V
+ UML_EXHc(block, IF_V, mips3.exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0,V
+ if (RDREG != 0)
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ else if (RDREG != 0)
+ {
+ UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x21: /* ADDU - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x2c: /* DADD - MIPS III */
+ if (mips3.drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
+ {
+ UML_DADDf(block, IREG(0), R64(RSREG), R64(RTREG), FLAGS_V); // dadd i0,<rsreg>,<rtreg>,V
+ UML_EXHc(block, IF_V, mips3.exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0,V
+ if (RDREG != 0)
+ UML_DMOV(block, R64(RDREG), IREG(0)); // dmov <rdreg>,i0
+ }
+ else if (RDREG != 0)
+ UML_DADD(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dadd <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x2d: /* DADDU - MIPS III */
+ if (RDREG != 0)
+ UML_DADD(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dadd <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x22: /* SUB - MIPS I */
+ if (mips3.drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
+ {
+ UML_SUBf(block, IREG(0), R32(RSREG), R32(RTREG), FLAGS_V); // sub i0,<rsreg>,<rtreg>,V
+ UML_EXHc(block, IF_V, mips3.exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0,V
+ if (RDREG != 0)
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ else if (RDREG != 0)
+ {
+ UML_SUB(block, IREG(0), R32(RSREG), R32(RTREG)); // sub i0,<rsreg>,<rtreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x23: /* SUBU - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_SUB(block, IREG(0), R32(RSREG), R32(RTREG)); // sub i0,<rsreg>,<rtreg>
+ UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0
+ }
+ return TRUE;
+
+ case 0x2e: /* DSUB - MIPS III */
+ if (mips3.drcoptions & MIPS3DRC_CHECK_OVERFLOWS)
+ {
+ UML_DSUBf(block, IREG(0), R64(RSREG), R64(RTREG), FLAGS_V); // dsub i0,<rsreg>,<rtreg>,V
+ UML_EXHc(block, IF_V, mips3.exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0,V
+ if (RDREG != 0)
+ UML_DMOV(block, R64(RDREG), IREG(0)); // dmov <rdreg>,i0
+ }
+ else if (RDREG != 0)
+ UML_DSUB(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dsub <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x2f: /* DSUBU - MIPS III */
+ if (RDREG != 0)
+ UML_DSUB(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dsub <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x18: /* MULT - MIPS I */
+ UML_MULS(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // muls i0,i1,<rsreg>,<rtreg>
+ UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0
+ UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1
+ return TRUE;
+
+ case 0x19: /* MULTU - MIPS I */
+ UML_MULU(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // mulu i0,i1,<rsreg>,<rtreg>
+ UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0
+ UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1
+ return TRUE;
+
+ case 0x1c: /* DMULT - MIPS III */
+ UML_DMULS(block, LO64, HI64, R64(RSREG), R64(RTREG)); // dmuls lo,hi,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x1d: /* DMULTU - MIPS III */
+ UML_DMULU(block, LO64, HI64, R64(RSREG), R64(RTREG)); // dmulu lo,hi,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x1a: /* DIV - MIPS I */
+ UML_DIVS(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // divs i0,i1,<rsreg>,<rtreg>
+ UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0
+ UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1
+ return TRUE;
+
+ case 0x1b: /* DIVU - MIPS I */
+ UML_DIVU(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // divu i0,i1,<rsreg>,<rtreg>
+ UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0
+ UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i1
+ return TRUE;
+
+ case 0x1e: /* DDIV - MIPS III */
+ UML_DDIVS(block, LO64, HI64, R64(RSREG), R64(RTREG)); // ddivs lo,hi,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x1f: /* DDIVU - MIPS III */
+ UML_DDIVU(block, LO64, HI64, R64(RSREG), R64(RTREG)); // ddivu lo,hi,<rsreg>,<rtreg>
+ return TRUE;
+
+
+ /* ----- basic logical ops ----- */
+
+ case 0x24: /* AND - MIPS I */
+ if (RDREG != 0)
+ UML_DAND(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dand <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x25: /* OR - MIPS I */
+ if (RDREG != 0)
+ UML_DOR(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dor <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x26: /* XOR - MIPS I */
+ if (RDREG != 0)
+ UML_DXOR(block, R64(RDREG), R64(RSREG), R64(RTREG)); // dxor <rdreg>,<rsreg>,<rtreg>
+ return TRUE;
+
+ case 0x27: /* NOR - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_DOR(block, IREG(0), R64(RSREG), R64(RTREG)); // dor i0,<rsreg>,<rtreg>
+ UML_DXOR(block, R64(RDREG), IREG(0), IMM((UINT64)~0)); // dxor <rdreg>,i0,~0
+ }
+ return TRUE;
+
+
+ /* ----- basic comparisons ----- */
+
+ case 0x2a: /* SLT - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_DFLAGS(block, R64(RDREG), (UINT64)~0, mips3.cstate->slt_table); // dflags <rdreg>,~0,slt_table
+ }
+ return TRUE;
+
+ case 0x2b: /* SLTU - MIPS I */
+ if (RDREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_DFLAGS(block, R64(RDREG), (UINT64)~0, mips3.cstate->sltu_table);// dflags <rdreg>,~0,sltu_table
+ }
+ return TRUE;
+
+
+ /* ----- conditional traps ----- */
+
+ case 0x30: /* TGE - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_EXHc(block, IF_GE, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,GE
+ return TRUE;
+
+ case 0x31: /* TGEU - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_EXHc(block, IF_AE, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,AE
+ return TRUE;
+
+ case 0x32: /* TLT - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_EXHc(block, IF_L, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,LT
+ return TRUE;
+
+ case 0x33: /* TLTU - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_EXHc(block, IF_B, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,B
+ return TRUE;
+
+ case 0x34: /* TEQ - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_EXHc(block, IF_E, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,E
+ return TRUE;
+
+ case 0x36: /* TNE - MIPS II */
+ UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg>
+ UML_EXHc(block, IF_NE, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,NE
+ return TRUE;
+
+
+ /* ----- conditional moves ----- */
+
+ case 0x0a: /* MOVZ - MIPS IV */
+ if (RDREG != 0)
+ {
+ UML_DCMP(block, R64(RTREG), IMM(0)); // dcmp <rtreg>,0
+ UML_DMOVc(block, IF_Z, R64(RDREG), R64(RSREG)); // mov <rdreg>,<rsreg>,Z
+ }
+ return TRUE;
+
+ case 0x0b: /* MOVN - MIPS IV */
+ if (RDREG != 0)
+ {
+ UML_DCMP(block, R64(RTREG), IMM(0)); // dcmp <rtreg>,0
+ UML_DMOVc(block, IF_NZ, R64(RDREG), R64(RSREG)); // mov <rdreg>,<rsreg>,NZ
+ }
+ return TRUE;
+
+ case 0x01: /* MOVF/MOVT - MIPS IV */
+ if (RDREG != 0)
+ {
+ UML_TEST(block, CCR132(31), IMM(fcc_mask[(op >> 18) & 7])); // test ccr31,fcc_mask[x]
+ UML_DMOVc(block, ((op >> 16) & 1) ? IF_NZ : IF_Z, R64(RDREG), R64(RSREG));
+ // mov <rdreg>,<rsreg>,NZ/Z
+ }
+ return TRUE;
+
+
+ /* ----- jumps and branches ----- */
+
+ case 0x08: /* JR - MIPS I */
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ return TRUE;
+
+ case 0x09: /* JALR - MIPS I */
+ generate_delay_slot_and_branch(block, compiler, desc, 31); // <next instruction + hashjmp>
+ return TRUE;
+
+
+ /* ----- system calls ----- */
+
+ case 0x0c: /* SYSCALL - MIPS I */
+ UML_EXH(block, mips3.exception[EXCEPTION_SYSCALL], IMM(0)); // exh syscall,0
+ return TRUE;
+
+ case 0x0d: /* BREAK - MIPS I */
+ UML_EXH(block, mips3.exception[EXCEPTION_BREAK], IMM(0)); // exh break,0
+ return TRUE;
+
+
+ /* ----- effective no-ops ----- */
+
+ case 0x0f: /* SYNC - MIPS II */
+ return TRUE;
+
+
+ /* ----- hi/lo register access ----- */
+
+ case 0x10: /* MFHI - MIPS I */
+ if (RDREG != 0)
+ UML_DMOV(block, R64(RDREG), HI64); // dmov <rdreg>,hi
+ return TRUE;
+
+ case 0x11: /* MTHI - MIPS I */
+ UML_DMOV(block, HI64, R64(RSREG)); // dmov hi,<rsreg>
+ return TRUE;
+
+ case 0x12: /* MFLO - MIPS I */
+ if (RDREG != 0)
+ UML_DMOV(block, R64(RDREG), LO64); // dmov <rdreg>,lo
+ return TRUE;
+
+ case 0x13: /* MTLO - MIPS I */
+ UML_DMOV(block, LO64, R64(RSREG)); // dmov lo,<rsreg>
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ generate_regimm - compile opcodes in the
+ 'REGIMM' group
+-------------------------------------------------*/
+
+static int generate_regimm(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = RTREG;
+ drcuml_codelabel skip;
+
+ switch (opswitch)
+ {
+ case 0x00: /* BLTZ */
+ case 0x02: /* BLTZL */
+ case 0x10: /* BLTZAL */
+ case 0x12: /* BLTZALL */
+ if (RSREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), IMM(0)); // dcmp <rsreg>,0
+ UML_JMPc(block, IF_GE, skip = compiler->labelnum++); // jmp skip,GE
+ generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0);
+ // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ }
+ return TRUE;
+
+ case 0x01: /* BGEZ */
+ case 0x03: /* BGEZL */
+ case 0x11: /* BGEZAL */
+ case 0x13: /* BGEZALL */
+ if (RSREG != 0)
+ {
+ UML_DCMP(block, R64(RSREG), IMM(0)); // dcmp <rsreg>,0
+ UML_JMPc(block, IF_L, skip = compiler->labelnum++); // jmp skip,L
+ generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0);
+ // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ }
+ else
+ generate_delay_slot_and_branch(block, compiler, desc, (opswitch & 0x10) ? 31 : 0);
+ // <next instruction + hashjmp>
+ return TRUE;
+
+ case 0x08: /* TGEI */
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_EXHc(block, IF_GE, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,GE
+ return TRUE;
+
+ case 0x09: /* TGEIU */
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_EXHc(block, IF_AE, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,AE
+ return TRUE;
+
+ case 0x0a: /* TLTI */
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_EXHc(block, IF_L, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,L
+ return TRUE;
+
+ case 0x0b: /* TLTIU */
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_EXHc(block, IF_B, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,B
+ return TRUE;
+
+ case 0x0c: /* TEQI */
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_EXHc(block, IF_E, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,E
+ return TRUE;
+
+ case 0x0e: /* TNEI */
+ UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL
+ UML_EXHc(block, IF_NE, mips3.exception[EXCEPTION_TRAP], IMM(0)); // exh trap,0,NE
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ generate_idt - compile opcodes in the IDT-
+ specific group
+-------------------------------------------------*/
+
+static int generate_idt(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ fatalerror("Unimplemented IDT instructions");
+#if 0
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = op & 0x1f;
+
+ switch (opswitch)
+ {
+ case 0: /* MAD */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
+ emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg]
+ emit_imul_r32(DRCTOP, REG_EDX); // imul edx
+ emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo]
+ emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EAX); // mov [lo],edx:eax
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EAX); // mov [hi],edx:eax
+ }
+ return compile_SUCCESSFUL_CP(3,4);
+
+ case 1: /* MADU */
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
+ emit_mov_r32_m32(REG_EDX, REGADDR(RTREG)); // mov edx,[rtreg]
+ emit_mul_r32(DRCTOP, REG_EDX); // mul edx
+ emit_add_r32_m32(DRCTOP, LOADDR); // add eax,[lo]
+ emit_adc_r32_m32(DRCTOP, HIADDR); // adc edx,[hi]
+ emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax
+ emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax
+ }
+ return compile_SUCCESSFUL_CP(3,4);
+
+ case 2: /* MUL */
+ if (RDREG != 0)
+ {
+ if (RSREG != 0 && RTREG != 0)
+ {
+ emit_mov_r32_m32(REG_EAX, REGADDR(RSREG)); // mov eax,[rsreg]
+ emit_imul_r32_m32(REG_EAX, REGADDR(RTREG)); // imul eax,[rtreg]
+ emit_cdq(DRCTOP); // cdq
+ emit_mov_m64_r64(REG_ESI, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rd],edx:eax
+ }
+ else
+ emit_zero_m64(REG_ESI, REGADDR(RDREG));
+ }
+ return compile_SUCCESSFUL_CP(3,4);
+ }
#endif
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ generate_set_cop0_reg - generate code to
+ handle special COP0 registers
+-------------------------------------------------*/
+
+static int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg)
+{
+ int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
+ drcuml_codelabel link;
+
+ switch (reg)
+ {
+ case COP0_Cause:
+ UML_AND(block, IREG(0), IREG(0), IMM(~0xfc00)); // and i0,i0,~0xfc00
+ UML_AND(block, IREG(1), CPR032(COP0_Cause), IMM(0xfc00)); // and i1,[Cause],0xfc00
+ UML_OR(block, CPR032(COP0_Cause), IREG(0), IREG(1)); // or [Cause],i0,i1
+ compiler->checksoftints = TRUE;
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, NULL, TRUE);
+ return TRUE;
+
+ case COP0_Status:
+ generate_update_cycles(block, compiler, desc->pc, NULL, !in_delay_slot);// <subtract cycles>
+ UML_MOV(block, IREG(1), CPR032(COP0_Status)); // mov i1,[Status]
+ UML_MOV(block, CPR032(COP0_Status), IREG(0)); // mov [Status],i0
+ UML_SHR(block, IREG(2), IREG(1), IMM(26)); // shr i2,i1,26
+ UML_AND(block, MEM(&mips3.cstate->mode), IREG(2), IMM(1)); // and [mode],i2,1
+ UML_XOR(block, IREG(0), IREG(0), IREG(1)); // xor i0,i0,i1
+ UML_TEST(block, IREG(0), IMM(0x8000)); // test i0,0x8000
+ UML_CALLCc(block, IF_NZ, mips3com_update_cycle_counting, mips3.core); // callc mips3com_update_cycle_counting,mips.core,NZ
+ compiler->checkints = TRUE;
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, NULL, TRUE);
+ return TRUE;
+
+ case COP0_Count:
+ generate_update_cycles(block, compiler, desc->pc, NULL, !in_delay_slot);// <subtract cycles>
+ UML_MOV(block, CPR032(COP0_Count), IREG(0)); // mov [Count],i0
+ UML_CALLC(block, cfunc_get_cycles, &mips3.cstate->numcycles); // callc cfunc_get_cycles,&mips3.numcycles
+ UML_DZEXT4(block, IREG(0), IREG(0)); // dzext4 i0,i0
+ UML_DADD(block, IREG(0), IREG(0), IREG(0)); // dadd i0,i0,i0
+ UML_DSUB(block, MEM(&mips3.core->count_zero_time), MEM(&mips3.cstate->numcycles), IREG(0));
+ // dsub [count_zero_time],[mips3.numcycles],i0
+ UML_CALLC(block, mips3com_update_cycle_counting, mips3.core); // callc mips3com_update_cycle_counting,mips.core
+ return TRUE;
+
+ case COP0_Compare:
+ generate_update_cycles(block, compiler, desc->pc, NULL, !in_delay_slot);// <subtract cycles>
+ UML_MOV(block, CPR032(COP0_Compare), IREG(0)); // mov [Compare],i0
+ UML_AND(block, CPR032(COP0_Cause), CPR032(COP0_Cause), IMM(~0x8000)); // and [Cause],[Cause],~0x8000
+ UML_CALLC(block, mips3com_update_cycle_counting, mips3.core); // callc mips3com_update_cycle_counting,mips.core
+ return TRUE;
+
+ case COP0_PRId:
+ return TRUE;
+
+ case COP0_Config:
+ UML_AND(block, IREG(0), IREG(0), IMM(0x0007)); // and i0,i0,0x0007
+ UML_AND(block, IREG(1), CPR032(COP0_Config), IMM(~0x0007)); // and i1,[Config],~0x0007
+ UML_OR(block, CPR032(COP0_Config), IREG(0), IREG(1)); // or [Config],i0,i1
+ return TRUE;
+
+ case COP0_EntryHi:
+ UML_XOR(block, IREG(1), IREG(0), CPR032(reg)); // xor i1,i0,cpr0[reg]
+ UML_MOV(block, CPR032(reg), IREG(0)); // mov cpr0[reg],i0
+ UML_TEST(block, IREG(1), IMM(0xff)); // test i1,0xff
+ UML_JMPc(block, IF_Z, link = compiler->labelnum++); // jmp link,z
+ UML_CALLC(block, mips3com_unmap_tlb_entries, mips3.core); // callc mips3com_unmap_tlb_entries
+ UML_CALLC(block, mips3com_map_tlb_entries, mips3.core); // callc mips3com_map_tlb_entries
+ UML_LABEL(block, link); // link:
+ return TRUE;
+
+ default:
+ UML_MOV(block, CPR032(reg), IREG(0)); // mov cpr0[reg],i0
+ return TRUE;
+ }
+}
+
+
+/*-------------------------------------------------
+ generate_get_cop0_reg - generate code to
+ read special COP0 registers
+-------------------------------------------------*/
+
+static int generate_get_cop0_reg(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT8 reg)
+{
+ drcuml_codelabel link1, link2;
+
+ switch (reg)
+ {
+ case COP0_Count:
+ generate_update_cycles(block, compiler, desc->pc, NULL, FALSE); // <subtract cycles>
+ UML_CALLC(block, cfunc_get_cycles, &mips3.cstate->numcycles); // callc cfunc_get_cycles,&mips3.numcycles
+ UML_DSUB(block, IREG(0), MEM(&mips3.cstate->numcycles), MEM(&mips3.core->count_zero_time));
+ // dsub i0,[numcycles],[count_zero_time]
+ UML_DSHR(block, IREG(0), IREG(0), IMM(1)); // dshr i0,i0,1
+ UML_DSEXT4(block, IREG(0), IREG(0)); // dsext4 i0,i0
+ return TRUE;
+
+ case COP0_Random:
+ generate_update_cycles(block, compiler, desc->pc, NULL, FALSE); // <subtract cycles>
+ UML_CALLC(block, cfunc_get_cycles, &mips3.cstate->numcycles); // callc cfunc_get_cycles,&mips3.numcycles
+ UML_DSUB(block, IREG(0), MEM(&mips3.cstate->numcycles), MEM(&mips3.core->count_zero_time));
+ // dsub i0,[numcycles],[count_zero_time]
+ UML_AND(block, IREG(1), CPR032(COP0_Wired), IMM(0x3f)); // and i1,[Wired],0x3f
+ UML_SUBf(block, IREG(2), IMM(48), IREG(1), FLAGS_BE); // sub i2,48,i1,ALL
+ UML_JMPc(block, IF_BE, link1 = compiler->labelnum++); // jmp link1,BE
+ UML_DZEXT4(block, IREG(2), IREG(2)); // dzext4 i2,i2
+ UML_DDIVU(block, IREG(0), IREG(2), IREG(0), IREG(2)); // ddivu i0,i2,i0,i2
+ UML_ADD(block, IREG(0), IREG(2), IREG(1)); // add i0,i2,i1
+ UML_DAND(block, IREG(0), IREG(0), IMM(0x3f)); // dand i0,i0,0x3f
+ UML_JMP(block, link2 = compiler->labelnum++); // jmp link2
+ UML_LABEL(block, link1); // link1:
+ UML_DSEXT4(block, IREG(0), IMM(47)); // dsext4 i0,47
+ UML_LABEL(block, link2); // link2:
+ return TRUE;
+
+ default:
+ UML_DSEXT4(block, IREG(0), CPR032(reg)); // dsext4 i0,cpr0[reg]
+ return TRUE;
+ }
+}
+
+
+/*-------------------------------------------------
+ generate_cop0 - compile COP0 opcodes
+-------------------------------------------------*/
+
+static int generate_cop0(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ UINT8 opswitch = RSREG;
+
+ /* generate an exception if COP0 is disabled or we are not in kernel mode */
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP0)
+ {
+ drcuml_codelabel okay;
+
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_KSU_MASK)); // test [Status],SR_KSU_MASK
+ UML_JMPc(block, IF_Z, okay = compiler->labelnum++); // jmp okay,Z
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_COP0)); // test [Status],SR_COP0
+ UML_EXHc(block, IF_Z, mips3.exception[EXCEPTION_BADCOP], IMM(0)); // exh cop,0,Z
+ UML_LABEL(block, okay); // okay:
+ }
+
+ switch (opswitch)
+ {
+ case 0x00: /* MFCz */
+ if (RTREG != 0)
+ {
+ generate_get_cop0_reg(block, compiler, desc, RDREG); // <get cop0 reg>
+ UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0
+ }
+ return TRUE;
+
+ case 0x01: /* DMFCz */
+ if (RTREG != 0)
+ {
+ generate_get_cop0_reg(block, compiler, desc, RDREG); // <get cop0 reg>
+ UML_DMOV(block, R64(RTREG), IREG(0)); // dmov <rtreg>,i0
+ }
+ return TRUE;
+
+ case 0x02: /* CFCz */
+ if (RTREG != 0)
+ UML_DSEXT4(block, R32(RTREG), CCR032(RDREG)); // dsext4 <rtreg>,ccr0[rdreg]
+ return TRUE;
+
+ case 0x04: /* MTCz */
+ UML_DSEXT4(block, IREG(0), R32(RTREG)); // dsext4 i0,<rtreg>
+ generate_set_cop0_reg(block, compiler, desc, RDREG); // <set cop0 reg>
+ return TRUE;
+
+ case 0x05: /* DMTCz */
+ UML_DMOV(block, IREG(0), R64(RTREG)); // dmov i0,<rtreg>
+ generate_set_cop0_reg(block, compiler, desc, RDREG); // <set cop0 reg>
+ return TRUE;
+
+ case 0x06: /* CTCz */
+ UML_DSEXT4(block, CCR064(RDREG), R32(RTREG)); // dsext4 ccr0[rdreg],<rtreg>
+ return TRUE;
+
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ case 0x19:
+ case 0x1a:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x1e:
+ case 0x1f: /* COP */
+ switch (op & 0x01ffffff)
+ {
+ case 0x01: /* TLBR */
+ UML_CALLC(block, mips3com_tlbr, mips3.core); // callc mips3com_tlbr,mips3.core
+ return TRUE;
+
+ case 0x02: /* TLBWI */
+ UML_CALLC(block, mips3com_tlbwi, mips3.core); // callc mips3com_tlbwi,mips3.core
+ return TRUE;
+
+ case 0x06: /* TLBWR */
+ UML_CALLC(block, mips3com_tlbwr, mips3.core); // callc mips3com_tlbwr,mips3.core
+ return TRUE;
+
+ case 0x08: /* TLBP */
+ UML_CALLC(block, mips3com_tlbp, mips3.core); // callc mips3com_tlbp,mips3.core
+ return TRUE;
+
+ case 0x18: /* ERET */
+ UML_AND(block, CPR032(COP0_Status), CPR032(COP0_Status), IMM(~SR_EXL));
+ // and [Status],[Status],~SR_EXL
+ compiler->checkints = TRUE;
+ generate_update_cycles(block, compiler, 0, LOPTR(&mips3.core->cpr[0][COP0_EPC]), TRUE);
+ // <subtract cycles>
+ UML_HASHJMP(block, IMM(mips3.cstate->mode), CPR032(COP0_EPC), mips3.nocode);
+ // hashjmp <mode>,[EPC],nocode
+ return TRUE;
+
+ case 0x20: /* WAIT */
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ COP1 RECOMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generate_cop1 - compile COP1 opcodes
+-------------------------------------------------*/
+
+static int generate_cop1(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ UINT32 op = *desc->opptr.l;
+ drcuml_codelabel skip;
+ int condition;
+
+ /* generate an exception if COP1 is disabled */
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
+ {
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_COP1)); // test [Status],SR_COP1
+ UML_EXHc(block, IF_Z, mips3.exception[EXCEPTION_BADCOP], IMM(0)); // exh cop,0,Z
+ }
+
+ switch (RSREG)
+ {
+ case 0x00: /* MFCz - MIPS I */
+ if (RTREG != 0)
+ UML_DSEXT4(block, R64(RTREG), FPR32(RDREG)); // dsext4 <rtreg>,fpr[rdreg]
+ return TRUE;
+
+ case 0x01: /* DMFCz - MIPS III */
+ if (RTREG != 0)
+ UML_DMOV(block, R64(RTREG), FPR64(RDREG)); // dmov <rtreg>,fpr[rdreg]
+ return TRUE;
+
+ case 0x02: /* CFCz - MIPS I */
+ if (RTREG != 0)
+ UML_DSEXT4(block, R64(RTREG), CCR132(RDREG)); // dsext4 <rtreg>,ccr132[rdreg]
+ return TRUE;
+
+ case 0x04: /* MTCz - MIPS I */
+ UML_MOV(block, FPR32(RDREG), R32(RTREG)); // mov fpr[rdreg],<rtreg>
+ return TRUE;
+
+ case 0x05: /* DMTCz - MIPS III */
+ UML_DMOV(block, FPR64(RDREG), R64(RTREG)); // dmov fpr[rdreg],<rtreg>
+ return TRUE;
+
+ case 0x06: /* CTCz - MIPS I */
+ if (RDREG != 31)
+ UML_DSEXT4(block, CCR164(RDREG), R32(RTREG)); // dsext4 ccr1[rdreg],<rtreg>
+ else
+ {
+ UML_XOR(block, IREG(0), CCR132(31), R32(RTREG)); // xor i0,ccr1[31],<rtreg>
+ UML_DSEXT4(block, CCR164(31), R32(RTREG)); // dsext4 ccr1[31],<rtreg>
+ UML_TEST(block, IREG(0), IMM(3)); // test i0,3
+ UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z
+ UML_AND(block, IREG(0), CCR132(31), IMM(3)); // and i0,ccr1[31],3
+ UML_LOAD1U(block, IREG(0), &mips3.cstate->fpmode[0], IREG(0)); // load1u i0,fpmode,i0
+ UML_SETFMOD(block, IREG(0)); // setfmod i0
+ UML_LABEL(block, skip); // skip:
+ }
+ return TRUE;
+
+ case 0x08: /* BC */
+ switch ((op >> 16) & 3)
+ {
+ case 0x00: /* BCzF - MIPS I */
+ case 0x02: /* BCzFL - MIPS II */
+ UML_TEST(block, CCR132(31), IMM(FCCMASK(op >> 18))); // test ccr1[31],fccmask[which]
+ UML_JMPc(block, IF_NZ, skip = compiler->labelnum++); // jmp skip,NZ
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ return TRUE;
+
+ case 0x01: /* BCzT - MIPS I */
+ case 0x03: /* BCzTL - MIPS II */
+ UML_TEST(block, CCR132(31), IMM(FCCMASK(op >> 18))); // test ccr1[31],fccmask[which]
+ UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z
+ generate_delay_slot_and_branch(block, compiler, desc, 0); // <next instruction + hashjmp>
+ UML_LABEL(block, skip); // skip:
+ return TRUE;
+ }
+ break;
+
+ default:
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ if (IS_SINGLE(op)) /* ADD.S - MIPS I */
+ UML_FSADD(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsadd <fdreg>,<fsreg>,<ftreg>
+ else /* ADD.D - MIPS I */
+ UML_FDADD(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fdadd <fdreg>,<fsreg>,<ftreg>
+ return TRUE;
+
+ case 0x01:
+ if (IS_SINGLE(op)) /* SUB.S - MIPS I */
+ UML_FSSUB(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fssub <fdreg>,<fsreg>,<ftreg>
+ else /* SUB.D - MIPS I */
+ UML_FDSUB(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fdsub <fdreg>,<fsreg>,<ftreg>
+ return TRUE;
+
+ case 0x02:
+ if (IS_SINGLE(op)) /* MUL.S - MIPS I */
+ UML_FSMUL(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsmul <fdreg>,<fsreg>,<ftreg>
+ else /* MUL.D - MIPS I */
+ UML_FDMUL(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fdmul <fdreg>,<fsreg>,<ftreg>
+ return TRUE;
+
+ case 0x03:
+ if (IS_SINGLE(op)) /* DIV.S - MIPS I */
+ UML_FSDIV(block, FPR32(FDREG), FPR32(FSREG), FPR32(FTREG)); // fsdiv <fdreg>,<fsreg>,<ftreg>
+ else /* DIV.D - MIPS I */
+ UML_FDDIV(block, FPR64(FDREG), FPR64(FSREG), FPR64(FTREG)); // fddiv <fdreg>,<fsreg>,<ftreg>
+ return TRUE;
+
+ case 0x04:
+ if (IS_SINGLE(op)) /* SQRT.S - MIPS II */
+ UML_FSSQRT(block, FPR32(FDREG), FPR32(FSREG)); // fssqrt <fdreg>,<fsreg>
+ else /* SQRT.D - MIPS II */
+ UML_FDSQRT(block, FPR64(FDREG), FPR64(FSREG)); // fdsqrt <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x05:
+ if (IS_SINGLE(op)) /* ABS.S - MIPS I */
+ UML_FSABS(block, FPR32(FDREG), FPR32(FSREG)); // fsabs <fdreg>,<fsreg>
+ else /* ABS.D - MIPS I */
+ UML_FDABS(block, FPR64(FDREG), FPR64(FSREG)); // fdabs <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x06:
+ if (IS_SINGLE(op)) /* MOV.S - MIPS I */
+ UML_FSMOV(block, FPR32(FDREG), FPR32(FSREG)); // fsmov <fdreg>,<fsreg>
+ else /* MOV.D - MIPS I */
+ UML_FDMOV(block, FPR64(FDREG), FPR64(FSREG)); // fdmov <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x07:
+ if (IS_SINGLE(op)) /* NEG.S - MIPS I */
+ UML_FSNEG(block, FPR32(FDREG), FPR32(FSREG)); // fsneg <fdreg>,<fsreg>
+ else /* NEG.D - MIPS I */
+ UML_FDNEG(block, FPR64(FDREG), FPR64(FSREG)); // fdneg <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x08:
+ if (IS_SINGLE(op)) /* ROUND.L.S - MIPS III */
+ UML_FSTOI8R(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8r <fdreg>,<fsreg>
+ else /* ROUND.L.D - MIPS III */
+ UML_FDTOI8R(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8r <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x09:
+ if (IS_SINGLE(op)) /* TRUNC.L.S - MIPS III */
+ UML_FSTOI8T(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8t <fdreg>,<fsreg>
+ else /* TRUNC.L.D - MIPS III */
+ UML_FDTOI8T(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8t <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x0a:
+ if (IS_SINGLE(op)) /* CEIL.L.S - MIPS III */
+ UML_FSTOI8C(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8c <fdreg>,<fsreg>
+ else /* CEIL.L.D - MIPS III */
+ UML_FDTOI8C(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8c <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x0b:
+ if (IS_SINGLE(op)) /* FLOOR.L.S - MIPS III */
+ UML_FSTOI8F(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8f <fdreg>,<fsreg>
+ else /* FLOOR.L.D - MIPS III */
+ UML_FDTOI8F(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8f <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x0c:
+ if (IS_SINGLE(op)) /* ROUND.W.S - MIPS II */
+ UML_FSTOI4R(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4r <fdreg>,<fsreg>
+ else /* ROUND.W.D - MIPS II */
+ UML_FDTOI4R(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4r <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x0d:
+ if (IS_SINGLE(op)) /* TRUNC.W.S - MIPS II */
+ UML_FSTOI4T(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4t <fdreg>,<fsreg>
+ else /* TRUNC.W.D - MIPS II */
+ UML_FDTOI4T(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4t <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x0e:
+ if (IS_SINGLE(op)) /* CEIL.W.S - MIPS II */
+ UML_FSTOI4C(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4c <fdreg>,<fsreg>
+ else /* CEIL.W.D - MIPS II */
+ UML_FDTOI4C(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4c <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x0f:
+ if (IS_SINGLE(op)) /* FLOOR.W.S - MIPS II */
+ UML_FSTOI4F(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4f <fdreg>,<fsreg>
+ else /* FLOOR.W.D - MIPS II */
+ UML_FDTOI4F(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4f <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x11:
+ condition = ((op >> 16) & 1) ? IF_NZ : IF_Z;
+ UML_TEST(block, CCR132(31), IMM(FCCMASK(op >> 18))); // test ccr31,fccmask[op]
+ if (IS_SINGLE(op)) /* MOVT/F.S - MIPS IV */
+ UML_FSMOVc(block, condition, FPR32(FDREG), FPR32(FSREG)); // fsmov <fdreg>,<fsreg>,condition
+ else /* MOVT/F.D - MIPS IV */
+ UML_FDMOVc(block, condition, FPR64(FDREG), FPR64(FSREG)); // fdmov <fdreg>,<fsreg>,condition
+ return TRUE;
+
+ case 0x12:
+ UML_DCMP(block, R64(RTREG), IMM(0)); // dcmp <rtreg>,0
+ if (IS_SINGLE(op)) /* MOVZ.S - MIPS IV */
+ UML_FSMOVc(block, IF_Z, FPR32(FDREG), FPR32(FSREG)); // fsmov <fdreg>,<fsreg>,Z
+ else /* MOVZ.D - MIPS IV */
+ UML_FDMOVc(block, IF_Z, FPR64(FDREG), FPR64(FSREG)); // fdmov <fdreg>,<fsreg>,Z
+ return TRUE;
+
+ case 0x13:
+ UML_DCMP(block, R64(RTREG), IMM(0)); // dcmp <rtreg>,0
+ if (IS_SINGLE(op)) /* MOVN.S - MIPS IV */
+ UML_FSMOVc(block, IF_NZ, FPR32(FDREG), FPR32(FSREG)); // fsmov <fdreg>,<fsreg>,NZ
+ else /* MOVN.D - MIPS IV */
+ UML_FDMOVc(block, IF_NZ, FPR64(FDREG), FPR64(FSREG)); // fdmov <fdreg>,<fsreg>,NZ
+ return TRUE;
+
+ case 0x15:
+ if (IS_SINGLE(op)) /* RECIP.S - MIPS IV */
+ UML_FSRECIP(block, FPR32(FDREG), FPR32(FSREG)); // fsrecip <fdreg>,<fsreg>
+ else /* RECIP.D - MIPS IV */
+ UML_FDRECIP(block, FPR64(FDREG), FPR64(FSREG)); // fdrecip <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x16:
+ if (IS_SINGLE(op)) /* RSQRT.S - MIPS IV */
+ UML_FSRSQRT(block, FPR32(FDREG), FPR32(FSREG)); // fsrsqrt <fdreg>,<fsreg>
+ else /* RSQRT.D - MIPS IV */
+ UML_FDRSQRT(block, FPR64(FDREG), FPR64(FSREG)); // fdrsqrt <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x20:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.S.W - MIPS I */
+ UML_FSFRI4(block, FPR32(FDREG), FPR32(FSREG)); // fsfri4 <fdreg>,<fsreg>
+ else /* CVT.S.L - MIPS I */
+ UML_FSFRI8(block, FPR32(FDREG), FPR64(FSREG)); // fsfri8 <fdreg>,<fsreg>
+ }
+ else /* CVT.S.D - MIPS I */
+ UML_FSFRFD(block, FPR32(FDREG), FPR64(FSREG)); // fsfrfd <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x21:
+ if (IS_INTEGRAL(op))
+ {
+ if (IS_SINGLE(op)) /* CVT.D.W - MIPS I */
+ UML_FDFRI4(block, FPR64(FDREG), FPR32(FSREG)); // fdfri4 <fdreg>,<fsreg>
+ else /* CVT.D.L - MIPS I */
+ UML_FDFRI8(block, FPR64(FDREG), FPR64(FSREG)); // fdfri8 <fdreg>,<fsreg>
+ }
+ else /* CVT.D.S - MIPS I */
+ UML_FDFRFS(block, FPR64(FDREG), FPR32(FSREG)); // fdfrfs <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x24:
+ if (IS_SINGLE(op)) /* CVT.W.S - MIPS I */
+ UML_FSTOI4(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4 <fdreg>,<fsreg>
+ else /* CVT.W.D - MIPS I */
+ UML_FDTOI4(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4 <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x25:
+ if (IS_SINGLE(op)) /* CVT.L.S - MIPS I */
+ UML_FSTOI8(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8 <fdreg>,<fsreg>
+ else /* CVT.L.D - MIPS I */
+ UML_FDTOI8(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8 <fdreg>,<fsreg>
+ return TRUE;
+
+ case 0x30:
+ case 0x38: /* C.F.S/D - MIPS I */
+ UML_AND(block, CCR132(31), CCR132(31), IMM(~FCCMASK(op >> 8))); // and ccr31,ccr31,~fccmask[op]
+ return TRUE;
+
+ case 0x31:
+ case 0x39:
+ if (IS_SINGLE(op)) /* C.UN.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.UN.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_un_table);
+ // flags ccr31,fccmask[op],c_eq_table
+ return TRUE;
+
+ case 0x32:
+ case 0x3a:
+ if (IS_SINGLE(op)) /* C.EQ.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.EQ.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_eq_table);
+ // flags ccr31,fccmask[op],c_eq_table
+ return TRUE;
+
+ case 0x33:
+ case 0x3b:
+ if (IS_SINGLE(op)) /* C.UEQ.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.UEQ.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_ueq_table);
+ // flags ccr31,fccmask[op],c_eq_table
+ return TRUE;
+
+ case 0x34:
+ case 0x3c:
+ if (IS_SINGLE(op)) /* C.OLT.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.OLT.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_olt_table);
+ // flags ccr31,fccmask[op],c_lt_table
+ return TRUE;
+
+ case 0x35:
+ case 0x3d:
+ if (IS_SINGLE(op)) /* C.ULT.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.ULT.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_ult_table);
+ // flags ccr31,fccmask[op],c_lt_table
+ return TRUE;
+
+ case 0x36:
+ case 0x3e:
+ if (IS_SINGLE(op)) /* C.OLE.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.OLE.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_ole_table);
+ // flags ccr31,fccmask[op],c_le_table
+ return TRUE;
+
+ case 0x37:
+ case 0x3f:
+ if (IS_SINGLE(op)) /* C.ULE.S - MIPS I */
+ UML_FSCMP(block, FPR32(FSREG), FPR32(FTREG)); // fscmp <fsreg>,<ftreg>
+ else /* C.ULE.D - MIPS I */
+ UML_FDCMP(block, FPR64(FSREG), FPR64(FTREG)); // fdcmp <fsreg>,<ftreg>
+ UML_FLAGS(block, CCR132(31), FCCMASK(op >> 8), mips3.cstate->c_ule_table);
+ // flags ccr31,fccmask[op],c_le_table
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ COP1X RECOMPILATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ generate_cop1x - compile COP1X opcodes
+-------------------------------------------------*/
+
+static int generate_cop1x(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc)
+{
+ int in_delay_slot = ((desc->flags & OPFLAG_IN_DELAY_SLOT) != 0);
+ UINT32 op = *desc->opptr.l;
+
+ if (mips3.drcoptions & MIPS3DRC_STRICT_COP1)
+ {
+ UML_TEST(block, CPR032(COP0_Status), IMM(SR_COP1)); // test [Status],SR_COP1
+ UML_EXHc(block, IF_Z, mips3.exception[EXCEPTION_BADCOP], IMM(0)); // exh cop,0,Z
+ }
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* LWXC1 - MIPS IV */
+ UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg>
+ UML_CALLH(block, mips3.read32); // callh read32
+ UML_MOV(block, FPR32(RDREG), IREG(0)); // mov <cpr1_rd>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x01: /* LDXC1 - MIPS IV */
+ UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg>
+ UML_CALLH(block, mips3.read64); // callh read64
+ UML_DMOV(block, FPR64(RDREG), IREG(0)); // dmov <cpr1_rd>,i0
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x08: /* SWXC1 - MIPS IV */
+ UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg>
+ UML_MOV(block, IREG(1), FPR32(RTREG)); // mov i1,<cpr1_rt>
+ UML_CALLH(block, mips3.write32); // callh write32
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x09: /* SDXC1 - MIPS IV */
+ UML_ADD(block, IREG(0), R32(RSREG), R32(RTREG)); // add i0,<rsreg>,<rtreg>
+ UML_DMOV(block, IREG(1), FPR64(RTREG)); // dmov i1,<cpr1_rt>
+ UML_CALLH(block, mips3.write64); // callh write64
+ if (!in_delay_slot)
+ generate_update_cycles(block, compiler, desc->pc + 4, 0, TRUE);
+ return TRUE;
+
+ case 0x0f: /* PREFX */
+ return TRUE;
+
+ case 0x20: /* MADD.S - MIPS IV */
+ UML_FSMUL(block, FREG(0), FPR32(FSREG), FPR32(FTREG)); // fsmul f0,<fsreg>,<ftreg>
+ UML_FSADD(block, FPR32(FDREG), FREG(0), FPR32(FRREG)); // fsadd <fdreg>,f0,<frreg>
+ return TRUE;
+
+ case 0x21: /* MADD.D - MIPS IV */
+ UML_FDMUL(block, FREG(0), FPR64(FSREG), FPR64(FTREG)); // fdmul f0,<fsreg>,<ftreg>
+ UML_FDADD(block, FPR64(FDREG), FREG(0), FPR64(FRREG)); // fdadd <fdreg>,f0,<frreg>
+ return TRUE;
+
+ case 0x28: /* MSUB.S - MIPS IV */
+ UML_FSMUL(block, FREG(0), FPR32(FSREG), FPR32(FTREG)); // fsmul f0,<fsreg>,<ftreg>
+ UML_FSSUB(block, FPR32(FDREG), FREG(0), FPR32(FRREG)); // fssub <fdreg>,f0,<frreg>
+ return TRUE;
+
+ case 0x29: /* MSUB.D - MIPS IV */
+ UML_FDMUL(block, FREG(0), FPR64(FSREG), FPR64(FTREG)); // fdmul f0,<fsreg>,<ftreg>
+ UML_FDSUB(block, FPR64(FDREG), FREG(0), FPR64(FRREG)); // fdsub <fdreg>,f0,<frreg>
+ return TRUE;
+
+ case 0x30: /* NMADD.S - MIPS IV */
+ UML_FSMUL(block, FREG(0), FPR32(FSREG), FPR32(FTREG)); // fsmul f0,<fsreg>,<ftreg>
+ UML_FSADD(block, FREG(0), FREG(0), FPR32(FRREG)); // fsadd f0,f0,<frreg>
+ UML_FSNEG(block, FPR32(FDREG), FREG(0)); // fsneg <fdreg>,f0
+ return TRUE;
+
+ case 0x31: /* NMADD.D - MIPS IV */
+ UML_FDMUL(block, FREG(0), FPR64(FSREG), FPR64(FTREG)); // fdmul f0,<fsreg>,<ftreg>
+ UML_FDADD(block, FREG(0), FREG(0), FPR64(FRREG)); // fdadd f0,f0,<frreg>
+ UML_FDNEG(block, FPR64(FDREG), FREG(0)); // fdneg <fdreg>,f0
+ return TRUE;
+
+ case 0x38: /* NMSUB.S - MIPS IV */
+ UML_FSMUL(block, FREG(0), FPR32(FSREG), FPR32(FTREG)); // fsmul f0,<fsreg>,<ftreg>
+ UML_FSSUB(block, FPR32(FDREG), FPR32(FRREG), FREG(0)); // fssub <fdreg>,<frreg>,f0
+ return TRUE;
+
+ case 0x39: /* NMSUB.D - MIPS IV */
+ UML_FDMUL(block, FREG(0), FPR64(FSREG), FPR64(FTREG)); // fdmul f0,<fsreg>,<ftreg>
+ UML_FDSUB(block, FPR64(FDREG), FPR64(FRREG), FREG(0)); // fdsub <fdreg>,<frreg>,f0
+ return TRUE;
+
+ default:
+ fprintf(stderr, "cop1x %X\n", op);
+ break;
+ }
+ return FALSE;
+}
@@ -366,27 +3375,23 @@ static void *fastram_ptr(offs_t addr, int size, int iswrite)
including disassembly of a MIPS instruction
-------------------------------------------------*/
-static void log_add_disasm_comment(x86log_context *log, x86code *base, UINT32 pc, UINT32 op)
+static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op)
{
-#if (LOG_CODE)
- {
- char buffer[100];
- dasmmips3(buffer, pc, op);
- x86log_add_comment(log, base, "%08X: %s", pc, buffer);
- }
+#if (LOG_UML)
+ char buffer[100];
+ dasmmips3(buffer, pc, op);
+ UML_COMMENT(block, "%08X: %s", pc, buffer); // comment
#endif
}
-#ifdef PTR64
-
/*-------------------------------------------------
- desc_flags_to_string - generate a string
+ log_desc_flags_to_string - generate a string
representing the instruction description
flags
-------------------------------------------------*/
-static const char *desc_flags_to_string(UINT32 flags)
+static const char *log_desc_flags_to_string(UINT32 flags)
{
static char tempbuf[30];
char *dest = tempbuf;
@@ -440,7 +3445,7 @@ static const char *desc_flags_to_string(UINT32 flags)
log_register_list - log a list of GPR registers
-------------------------------------------------*/
-static void log_register_list(x86log_context *log, const char *string, UINT64 gprmask, UINT64 fprmask)
+static void log_register_list(drcuml_state *drcuml, const char *string, UINT64 gprmask, UINT64 fprmask)
{
int count = 0;
int regnum;
@@ -449,22 +3454,22 @@ static void log_register_list(x86log_context *log, const char *string, UINT64 gp
if ((gprmask & ~1) == 0 && fprmask == 0)
return;
- x86log_printf(log, "[%s:", string);
+ drcuml_log_printf(drcuml, "[%s:", string);
for (regnum = 1; regnum < 32; regnum++)
if (gprmask & ((UINT64)1 << regnum))
- x86log_printf(log, "%sr%d", (count++ == 0) ? "" : ",", regnum);
+ drcuml_log_printf(drcuml, "%sr%d", (count++ == 0) ? "" : ",", regnum);
if (gprmask & ((UINT64)1 << REG_LO))
- x86log_printf(log, "%slo", (count++ == 0) ? "" : ",");
+ drcuml_log_printf(drcuml, "%slo", (count++ == 0) ? "" : ",");
if (gprmask & ((UINT64)1 << REG_HI))
- x86log_printf(log, "%shi", (count++ == 0) ? "" : ",");
+ drcuml_log_printf(drcuml, "%shi", (count++ == 0) ? "" : ",");
for (regnum = 0; regnum < 32; regnum++)
if (fprmask & ((UINT64)1 << regnum))
- x86log_printf(log, "%sfpr%d", (count++ == 0) ? "" : ",", regnum);
+ drcuml_log_printf(drcuml, "%sfpr%d", (count++ == 0) ? "" : ",", regnum);
if (fprmask & REGFLAG_FCC)
- x86log_printf(log, "%sfcc", (count++ == 0) ? "" : ",");
- x86log_printf(log, "] ");
+ drcuml_log_printf(drcuml, "%sfcc", (count++ == 0) ? "" : ",");
+ drcuml_log_printf(drcuml, "] ");
}
@@ -472,11 +3477,11 @@ static void log_register_list(x86log_context *log, const char *string, UINT64 gp
log_opcode_desc - log a list of descriptions
-------------------------------------------------*/
-static void log_opcode_desc(x86log_context *log, const opcode_desc *desclist, int indent)
+static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent)
{
/* open the file, creating it if necessary */
if (indent == 0)
- x86log_printf(log, "\nDescriptor list @ %08X\n", desclist->pc);
+ drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc);
/* output each descriptor */
for ( ; desclist != NULL; desclist = desclist->next)
@@ -484,42 +3489,29 @@ static void log_opcode_desc(x86log_context *log, const opcode_desc *desclist, in
char buffer[100];
/* disassemle the current instruction and output it to the log */
-#if LOG_CODE
+#if LOG_UML
dasmmips3(buffer, desclist->pc, *desclist->opptr.l);
#else
strcpy(buffer, "???");
#endif
- x86log_printf(log, "%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, desc_flags_to_string(desclist->flags), buffer);
+ drcuml_log_printf(drcuml, "%08X [%08X] t:%08X f:%s: %-30s", desclist->pc, desclist->physpc, desclist->targetpc, log_desc_flags_to_string(desclist->flags), buffer);
/* output register states */
- log_register_list(log, "use", desclist->gpr.used, desclist->fpr.used);
- log_register_list(log, "mod", desclist->gpr.modified, desclist->fpr.modified);
- log_register_list(log, "lrd", desclist->gpr.liveread, desclist->fpr.liveread);
- log_register_list(log, "lwr", desclist->gpr.livewrite, desclist->fpr.livewrite);
- x86log_printf(log, "\n");
+ log_register_list(drcuml, "use", desclist->gpr.used, desclist->fpr.used);
+ log_register_list(drcuml, "mod", desclist->gpr.modified, desclist->fpr.modified);
+ log_register_list(drcuml, "lrd", desclist->gpr.liveread, desclist->fpr.liveread);
+ log_register_list(drcuml, "lwr", desclist->gpr.livewrite, desclist->fpr.livewrite);
+ drcuml_log_printf(drcuml, "\n");
/* if we have a delay slot, output it recursively */
if (desclist->delay != NULL)
- log_opcode_desc(log, desclist->delay, indent + 1);
+ log_opcode_desc(drcuml, desclist->delay, indent + 1);
/* at the end of a sequence add a dividing line */
if (desclist->flags & OPFLAG_END_SEQUENCE)
- x86log_printf(log, "-----\n");
+ drcuml_log_printf(drcuml, "-----\n");
}
}
-#endif
-
-
-
-/***************************************************************************
- RECOMPILER CORE
-***************************************************************************/
-
-#ifdef PTR64
-#include "mdrc64.c"
-#else
-#include "mdrcold.c"
-#endif
@@ -725,7 +3717,6 @@ void r4700be_get_info(UINT32 state, cpuinfo *info)
}
}
-
void r4700le_get_info(UINT32 state, cpuinfo *info)
{
switch (state)
@@ -913,390 +3904,7 @@ void rm7000le_get_info(UINT32 state, cpuinfo *info)
DISASSEMBLERS
***************************************************************************/
-#if !defined(ENABLE_DEBUGGER) && (LOG_CODE)
+#if !defined(MAME_DEBUG) && (LOG_UML)
#include "mips3dsm.c"
#endif
-
-
-/***************************************************************************
- C CORE FOR COMPARISON
-***************************************************************************/
-
-#if COMPARE_AGAINST_C
-
-static UINT8 dummy_read_byte_32le(offs_t offs)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 1;
- mips3.access_size = 1;
- mips3.access_addr = offs;
- mips3.access_mask = 0;
- mips3.access_data = program_read_byte_32le(offs);
- }
- else
- {
- assert(mips3.access_type == 1);
- assert(mips3.access_size == 1);
- assert(mips3.access_addr == offs);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- }
- return mips3.access_data;
-}
-
-static UINT16 dummy_read_word_32le(offs_t offs)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 1;
- mips3.access_size = 2;
- mips3.access_addr = offs;
- mips3.access_mask = 0;
- mips3.access_data = program_read_word_32le(offs);
- }
- else
- {
- assert(mips3.access_type == 1);
- assert(mips3.access_size == 2);
- assert(mips3.access_addr == offs);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- }
- return mips3.access_data;
-}
-
-static UINT32 dummy_read_dword_32le(offs_t offs)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 1;
- mips3.access_size = 4;
- mips3.access_addr = offs;
- mips3.access_mask = 0;
- mips3.access_data = program_read_dword_32le(offs);
- }
- else
- {
- assert(mips3.access_type == 1);
- assert(mips3.access_size == 4);
- assert(mips3.access_addr == offs);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- }
- return mips3.access_data;
-}
-
-static UINT32 dummy_read_masked_32le(offs_t offs, UINT32 mask)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 1;
- mips3.access_size = 4;
- mips3.access_addr = offs;
- mips3.access_mask = mask;
- mips3.access_data = program_read_masked_32le(offs, mask);
- }
- else
- {
- assert(mips3.access_type == 1);
- assert(mips3.access_size == 4);
- assert(mips3.access_addr == offs);
- assert(mips3.access_mask == mask);
- mips3.access_type = 0;
- }
- return mips3.access_data;
-}
-
-static UINT64 dummy_read_qword_32le(offs_t offs)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 1;
- mips3.access_size = 8;
- mips3.access_addr = offs;
- mips3.access_mask = 0;
- mips3.access_data = (*mips3.orighandler.readdouble)(offs);
- }
- else
- {
- assert(mips3.access_type == 1);
- assert(mips3.access_size == 8);
- assert(mips3.access_addr == offs);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- }
- return mips3.access_data;
-}
-
-static UINT64 dummy_read_qword_masked_32le(offs_t offs, UINT64 mask)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 1;
- mips3.access_size = 8;
- mips3.access_addr = offs;
- mips3.access_mask = mask;
- mips3.access_data = (*mips3.orighandler.readdouble_masked)(offs, mask);
- }
- else
- {
- assert(mips3.access_type == 1);
- assert(mips3.access_size == 8);
- assert(mips3.access_addr == offs);
- assert(mips3.access_mask == mask);
- mips3.access_type = 0;
- }
- return mips3.access_data;
-}
-
-static void dummy_write_byte_32le(offs_t offs, UINT8 data)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 2;
- mips3.access_size = 1;
- mips3.access_addr = offs;
- mips3.access_data = data;
- mips3.access_mask = 0;
- }
- else
- {
- assert(mips3.access_type == 2);
- assert(mips3.access_size == 1);
- assert(mips3.access_addr == offs);
- assert(mips3.access_data == data);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- program_write_byte_32le(offs, data);
- }
-}
-
-static void dummy_write_word_32le(offs_t offs, UINT16 data)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 2;
- mips3.access_size = 2;
- mips3.access_addr = offs;
- mips3.access_data = data;
- mips3.access_mask = 0;
- }
- else
- {
- assert(mips3.access_type == 2);
- assert(mips3.access_size == 2);
- assert(mips3.access_addr == offs);
- assert(mips3.access_data == data);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- program_write_word_32le(offs, data);
- }
-}
-
-static void dummy_write_dword_32le(offs_t offs, UINT32 data)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 2;
- mips3.access_size = 4;
- mips3.access_addr = offs;
- mips3.access_data = data;
- mips3.access_mask = 0;
- }
- else
- {
- assert(mips3.access_type == 2);
- assert(mips3.access_size == 4);
- assert(mips3.access_addr == offs);
- assert(mips3.access_data == data);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- program_write_dword_32le(offs, data);
- }
-}
-
-static void dummy_write_masked_32le(offs_t offs, UINT32 data, UINT32 mask)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 2;
- mips3.access_size = 4;
- mips3.access_addr = offs;
- mips3.access_data = data;
- mips3.access_mask = mask;
- }
- else
- {
- assert(mips3.access_type == 2);
- assert(mips3.access_size == 4);
- assert(mips3.access_addr == offs);
- assert(mips3.access_data == data);
- assert(mips3.access_mask == mask);
- mips3.access_type = 0;
- program_write_masked_32le(offs, data, mask);
- }
-}
-
-static void dummy_write_qword_32le(offs_t offs, UINT64 data)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 2;
- mips3.access_size = 8;
- mips3.access_addr = offs;
- mips3.access_data = data;
- mips3.access_mask = 0;
- }
- else
- {
- assert(mips3.access_type == 2);
- assert(mips3.access_size == 8);
- assert(mips3.access_addr == offs);
- assert(mips3.access_data == data);
- assert(mips3.access_mask == 0);
- mips3.access_type = 0;
- (*mips3.orighandler.writedouble)(offs, data);
- }
-}
-
-static void dummy_write_qword_masked_32le(offs_t offs, UINT64 data, UINT64 mask)
-{
- if (mips3.access_type == 0)
- {
- mips3.access_type = 2;
- mips3.access_size = 8;
- mips3.access_addr = offs;
- mips3.access_data = data;
- mips3.access_mask = mask;
- }
- else
- {
- assert(mips3.access_type == 2);
- assert(mips3.access_size == 8);
- assert(mips3.access_addr == offs);
- assert(mips3.access_data == data);
- assert(mips3.access_mask == mask);
- mips3.access_type = 0;
- (*mips3.orighandler.writedouble_masked)(offs, data, mask);
- }
-}
-
-static const memory_handlers override_memory =
-{
- dummy_read_byte_32le,
- dummy_read_word_32le,
- dummy_read_dword_32le,
- dummy_read_masked_32le,
- dummy_read_qword_32le,
- dummy_read_qword_masked_32le,
-
- dummy_write_byte_32le,
- dummy_write_word_32le,
- dummy_write_dword_32le,
- dummy_write_masked_32le,
- dummy_write_qword_32le,
- dummy_write_qword_masked_32le
-};
-
-#undef SR
-
-#define mips3 c_mips3
-#define mips3_regs c_mips3_regs
-
-#define mips3_get_context c_mips3_get_context
-#define mips3_set_context c_mips3_set_context
-#define mips3_reset c_mips3_reset
-#define mips3_translate c_mips3_translate
-#define mips3_dasm c_mips3_dasm
-#define mips3_execute c_mips3_execute
-#define mips3_set_info c_mips3_set_info
-#define mips3_get_info c_mips3_get_info
-
-#define r4600be_init c_r4600be_init
-#define r4600le_init c_r4600le_init
-#define r4600be_get_info c_r4600be_get_info
-#define r4600le_get_info c_r4600le_get_info
-
-#define r4650be_init c_r4650be_init
-#define r4650le_init c_r4650le_init
-#define r4650be_get_info c_r4650be_get_info
-#define r4650le_get_info c_r4650le_get_info
-
-#define r4700be_init c_r4700be_init
-#define r4700le_init c_r4700le_init
-#define r4700be_get_info c_r4700be_get_info
-#define r4700le_get_info c_r4700le_get_info
-
-#define r5000be_init c_r5000be_init
-#define r5000le_init c_r5000le_init
-#define r5000be_get_info c_r5000be_get_info
-#define r5000le_get_info c_r5000le_get_info
-
-#define qed5271be_init c_qed5271be_init
-#define qed5271le_init c_qed5271le_init
-#define qed5271be_get_info c_qed5271be_get_info
-#define qed5271le_get_info c_qed5271le_get_info
-
-#define rm7000be_init c_rm7000be_init
-#define rm7000le_init c_rm7000le_init
-#define rm7000be_get_info c_rm7000be_get_info
-#define rm7000le_get_info c_rm7000le_get_info
-
-#include "mips3.c"
-
-#undef mips3
-
-static void mips3c_init(mips3_flavor flavor, int bigendian, int index, int clock, const struct mips3_config *config, int (*irqcallback)(int))
-{
- size_t memsize = mips3com_init(&c_mips3.core, flavor, bigendian, index, clock, config, irqcallback, NULL);
- void *memory = auto_malloc(memsize);
- mips3com_init(&c_mips3.core, flavor, bigendian, index, clock, config, irqcallback, memory);
- mips3.orighandler = mips3.core->memory;
- mips3.core->memory = override_memory;
- c_mips3.core.memory = override_memory;
-}
-
-static void mips3c_reset(void)
-{
- c_mips3_reset();
-}
-
-static void execute_c_version(void)
-{
- int save_debug_mode = Machine->debug_mode;
- int i;
-
- assert(mips3.access_type == 0);
-
- c_mips3.core.cpr[0][COP0_Cause] = (c_mips3.core.cpr[0][COP0_Cause] & ~0xfc00) | (mips3.core->cpr[0][COP0_Cause] & 0xfc00);
- check_irqs();
-
- assert(c_mips3.core.pc == mips3.core->pc);
- assert(c_mips3.core.r[REG_HI] == mips3.core->r[REG_HI]);
- assert(c_mips3.core.r[REG_LO] == mips3.core->r[REG_LO]);
- for (i = 0; i < 32; i++)
- {
- assert(c_mips3.core.r[i] == mips3.core->r[i]);
- assert(c_mips3.core.cpr[0][i] == mips3.core->cpr[0][i]);
- assert(c_mips3.core.ccr[0][i] == mips3.core->ccr[0][i]);
- assert(c_mips3.core.cpr[1][i] == mips3.core->cpr[1][i]);
- assert(c_mips3.core.ccr[1][i] == mips3.core->ccr[1][i]);
- }
- for (i = 0; i < 8; i++)
- assert(c_mips3.core.cf[1][i] == mips3.core->cf[1][i]);
- assert(c_mips3.core.count_zero_time == mips3.core->count_zero_time);
-
- mips3.access_type = 0;
-
- Machine->debug_mode = 0;
- c_mips3_execute(0);
- Machine->debug_mode = save_debug_mode;
-}
-
-static void compare_c_version(void)
-{
-}
-
-#endif
diff --git a/src/emu/cpu/mips/mips3dsm.c b/src/emu/cpu/mips/mips3dsm.c
index a3f4cc6aeb2..197c5775437 100644
--- a/src/emu/cpu/mips/mips3dsm.c
+++ b/src/emu/cpu/mips/mips3dsm.c
@@ -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;
diff --git a/src/emu/cpu/mips/mips3fe.c b/src/emu/cpu/mips/mips3fe.c
index 5bef908d7ac..eadf1b1e5e4 100644
--- a/src/emu/cpu/mips/mips3fe.c
+++ b/src/emu/cpu/mips/mips3fe.c
@@ -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;
diff --git a/src/emu/cpu/mips/mips3fe.h b/src/emu/cpu/mips/mips3fe.h
index 1f6661657dd..ebb02429cab 100644
--- a/src/emu/cpu/mips/mips3fe.h
+++ b/src/emu/cpu/mips/mips3fe.h
@@ -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.
***************************************************************************/
diff --git a/src/emu/cpu/mips/r3000.c b/src/emu/cpu/mips/r3000.c
index 57f795e974e..6449c5b3a87 100644
--- a/src/emu/cpu/mips/r3000.c
+++ b/src/emu/cpu/mips/r3000.c
@@ -7,6 +7,7 @@
***************************************************************************/
#include "debugger.h"
+#include "deprecat.h"
#include "r3000.h"
diff --git a/src/emu/cpu/x86emit.h b/src/emu/cpu/x86emit.h
index fc05d632b30..fb7ff742e48 100644
--- a/src/emu/cpu/x86emit.h
+++ b/src/emu/cpu/x86emit.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_*
@@ -2754,6 +2773,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
***************************************************************************/
diff --git a/src/emu/video/voodoo.c b/src/emu/video/voodoo.c
index 005aa55b0a1..d1026e708a1 100644
--- a/src/emu/video/voodoo.c
+++ b/src/emu/video/voodoo.c
@@ -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;