summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/mips/mips3drc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/mips/mips3drc.c')
-rw-r--r--src/emu/cpu/mips/mips3drc.c3720
1 files changed, 3164 insertions, 556 deletions
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