diff options
author | Aaron Giles <aaron@aarongiles.com> | 2008-06-05 08:34:13 +0000 |
---|---|---|
committer | Aaron Giles <aaron@aarongiles.com> | 2008-06-05 08:34:13 +0000 |
commit | ed6ad8b4f933fa4c18b683a2f2362c2c8cbe8c82 (patch) | |
tree | d077746962ad9a3bbb4bda243d417de7e98a6f4d | |
parent | 8ea2d9e334e001ec58ba6bbd057bebe7009bb1ff (diff) |
PowerPC dynamic recompiler: [Aaron Giles]
- rewrote PowerPC implementation as a dynamic recompiler on top
of the universal recompiler engine
- wrote a front-end to analyze PowerPC code paths and register usage
- wrote a common shared module with C implementations of tricky
CPU behaviors
- added separate CPU types for the variants supported, instead of
relying on a hidden model enum
- rewrote the serial port emulation for the 4xx series to be more
accurate and not rely on separate DMA handlers
- rewrote the MMU handling to implement a software TLB that faults
in pages and handles changed bits appropriately
- implemented emulation of the PowerPC 603's software TLB, which
allows the model 3 games to run without a hack to disable the MMU
Updated the PowerPC disassembler to share constants with the rest of
the core, and to more aggressively use simplified mnemonics, especially
for branches. [Aaron Giles]
Universal recompiler:
- fixed frontend to handle opcode widths different from bus width
- added several new opcodes:
* (D)GETFLGS - copies the UML flags to a destination operand
* FDRNDS - rounds a double precision value to single precision
- renamed several opcodes:
* SETC -> CARRY
* XTRACT -> ROLAND
* INSERT -> ROLINS
- consolidated the following opcodes:
* LOAD?U -> LOAD
* LOAD?S -> LOADS
* STORE? -> STORE
* READ?U -> READ
* READ?M -> READM
* WRITE? -> WRITE
* WRITM? -> WRITEM
* SEXT? -> SEXT
* FTOI?? -> FTOINT
* FFRI? -> FFRINT
* FFRF? -> FFRFLT
- removed some opcodes:
* FLAGS - can be done with GETFLGS/LOAD4/ROLINS
* ZEXT - can be achieved with AND
* READ?S - can be achieved with READ/SEXT
- updated C, x86, and x64 back-ends to support these opcode changes
- updated disassembler to support these opcode changes
MIPS3 dynamic recompiler:
- updated to use new/changed opcode forms
- changed context switch so that it only swaps a single pointer
Konami Hornet changes: [Aaron Giles]
- updated to new PowerPC configurations
- updated some memory handlers to be native 8-bit handlers
- cleaned up JVS implementation to work with new serial code
- added fast RAM for the work RAM to give a small speed boost
Konami GTI Club changes: [Aaron Giles]
- updated to new PowerPC configurations
- updated some memory handlers to be native 8-bit handlers
Konami Viper/ZR107 changes: [Aaron Giles]
- updated to new PowerPC configurations
Sega Model 3 changes: [Aaron Giles]
- updated to new PowerPC configurations
- reimplemented/centralized interrupt handling
- these games are broken for the moment
Fixed crasher due to some Konami games using 8 layers in
the K056832 implementation, even though it was only written
for 4. [Aaron Giles]
Added fisttp opcode to i386 disassembler. [Aaron Giles]
43 files changed, 10338 insertions, 9424 deletions
diff --git a/.gitattributes b/.gitattributes index c9441f52f98..43c25630a71 100644 --- a/.gitattributes +++ b/.gitattributes @@ -320,7 +320,11 @@ src/emu/cpu/powerpc/ppc_dasm.c svneol=native#text/plain src/emu/cpu/powerpc/ppc_mem.c svneol=native#text/plain src/emu/cpu/powerpc/ppc_ops.c svneol=native#text/plain src/emu/cpu/powerpc/ppc_ops.h svneol=native#text/plain -src/emu/cpu/powerpc/ppcdrco.c svneol=native#text/plain +src/emu/cpu/powerpc/ppccom.c svneol=native#text/plain +src/emu/cpu/powerpc/ppccom.h svneol=native#text/plain +src/emu/cpu/powerpc/ppcdrc.c svneol=native#text/plain +src/emu/cpu/powerpc/ppcfe.c svneol=native#text/plain +src/emu/cpu/powerpc/ppcfe.h svneol=native#text/plain src/emu/cpu/rsp/rsp.c svneol=native#text/plain src/emu/cpu/rsp/rsp.h svneol=native#text/plain src/emu/cpu/rsp/rsp_dasm.c svneol=native#text/plain @@ -448,10 +452,6 @@ src/emu/cpu/v60/v60mem.c svneol=native#text/plain src/emu/cpu/v810/v810.c svneol=native#text/plain src/emu/cpu/v810/v810.h svneol=native#text/plain src/emu/cpu/v810/v810dasm.c svneol=native#text/plain -src/emu/cpu/x64drc.c svneol=native#text/plain -src/emu/cpu/x64drc.h svneol=native#text/plain -src/emu/cpu/x86drc.c svneol=native#text/plain -src/emu/cpu/x86drc.h svneol=native#text/plain src/emu/cpu/x86emit.h svneol=native#text/plain src/emu/cpu/x86log.c svneol=native#text/plain src/emu/cpu/x86log.h svneol=native#text/plain @@ -111,9 +111,6 @@ endif # a native backend # FORCE_DRC_C_BACKEND = 1 -# uncomment next line to use DRC PowerPC engine -X86_PPC_DRC = 1 - #------------------------------------------------- @@ -159,11 +156,6 @@ BUILD_ZLIB = 1 # sanity check the configuration #------------------------------------------------- -# disable DRC cores for 64-bit builds -ifdef PTR64 -X86_PPC_DRC = -endif - # specify a default optimization level if none explicitly stated ifndef OPTIMIZE ifndef SYMBOLS diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak index 31e249b6c05..945a836cfbe 100644 --- a/src/emu/cpu/cpu.mak +++ b/src/emu/cpu/cpu.mak @@ -41,13 +41,10 @@ ifdef PTR64 DRCOBJ += \ $(CPUOBJ)/drcbex64.o \ - $(CPUOBJ)/x64drc.o \ - $(CPUOBJ)/x86log.o \ + $(CPUOBJ)/x86log.o DRCDEPS += \ - $(CPUSRC)/x86emit.h \ - $(CPUSRC)/x64drc.c \ - $(CPUSRC)/x64drc.h \ + $(CPUSRC)/x86emit.h DEFS += -DNATIVE_DRC=drcbe_x64_be_interface @@ -55,13 +52,10 @@ else DRCOBJ += \ $(CPUOBJ)/drcbex86.o \ - $(CPUOBJ)/x86drc.o \ - $(CPUOBJ)/x86log.o \ + $(CPUOBJ)/x86log.o DRCDEPS += \ - $(CPUSRC)/x86emit.h \ - $(CPUSRC)/x86drc.c \ - $(CPUSRC)/x86drc.h \ + $(CPUSRC)/x86emit.h DEFS += -DNATIVE_DRC=drcbe_x86_be_interface @@ -839,7 +833,7 @@ CPUDEFS += -DHAS_RM7000=$(if $(filter RM7000,$(CPUS)),1,0) ifneq ($(filter R4600 R4650 R4700 R5000 QED5271 RM7000,$(CPUS)),) OBJDIRS += $(CPUOBJ)/mips -CPUOBJS += $(CPUOBJ)/mips/mips3com.o $(CPUOBJ)/mips/mips3drc.o $(CPUOBJ)/mips/mips3fe.o $(DRCOBJ) +CPUOBJS += $(CPUOBJ)/mips/mips3com.o $(CPUOBJ)/mips/mips3fe.o $(CPUOBJ)/mips/mips3drc.o $(DRCOBJ) DBGOBJS += $(CPUOBJ)/mips/mips3dsm.o endif @@ -1125,41 +1119,26 @@ $(CPUOBJ)/pdp1/pdp1.o: $(CPUSRC)/pdp1/pdp1.c \ # Motorola PowerPC series #------------------------------------------------- -CPUDEFS += -DHAS_PPC403=$(if $(filter PPC403,$(CPUS)),1,0) +CPUDEFS += -DHAS_PPC403GA=$(if $(filter PPC403GA,$(CPUS)),1,0) +CPUDEFS += -DHAS_PPC403GCX=$(if $(filter PPC403GCX,$(CPUS)),1,0) CPUDEFS += -DHAS_PPC601=$(if $(filter PPC601,$(CPUS)),1,0) CPUDEFS += -DHAS_PPC602=$(if $(filter PPC602,$(CPUS)),1,0) CPUDEFS += -DHAS_PPC603=$(if $(filter PPC603,$(CPUS)),1,0) +CPUDEFS += -DHAS_PPC603E=$(if $(filter PPC603E,$(CPUS)),1,0) +CPUDEFS += -DHAS_PPC603R=$(if $(filter PPC603R,$(CPUS)),1,0) CPUDEFS += -DHAS_PPC604=$(if $(filter PPC604,$(CPUS)),1,0) CPUDEFS += -DHAS_MPC8240=$(if $(filter MPC8240,$(CPUS)),1,0) -ifneq ($(filter PPC403 PPC601 PPC602 PPC603 PPC604 MPC8240,$(CPUS)),) +ifneq ($(filter PPC403GA PPC403GCX PPC601 PPC602 PPC603 PPC603E PPC603R PPC604 MPC8240,$(CPUS)),) OBJDIRS += $(CPUOBJ)/powerpc +CPUOBJS += $(CPUOBJ)/powerpc/ppccom.o $(CPUOBJ)/powerpc/ppcfe.o $(CPUOBJ)/powerpc/ppcdrc.o $(DRCOBJ) DBGOBJS += $(CPUOBJ)/powerpc/ppc_dasm.o - -ifdef X86_PPC_DRC -CPUOBJS += $(CPUOBJ)/powerpc/ppcdrco.o $(DRCOBJ) -else -CPUOBJS += $(CPUOBJ)/powerpc/ppc.o -endif endif -$(CPUOBJ)/powerpc/ppc.o: $(CPUSRC)/powerpc/ppc.c \ - $(CPUSRC)/powerpc/ppc.h \ - $(CPUSRC)/powerpc/ppc_ops.c \ - $(CPUSRC)/powerpc/ppc_mem.c \ - $(CPUSRC)/powerpc/ppc403.c \ - $(CPUSRC)/powerpc/ppc602.c \ - $(CPUSRC)/powerpc/ppc603.c - -$(CPUOBJ)/powerpc/ppcdrco.o:$(CPUSRC)/powerpc/ppcdrco.c \ +$(CPUOBJ)/powerpc/ppcdrc.o: $(CPUSRC)/powerpc/ppcdrc.c \ $(CPUSRC)/powerpc/ppc.h \ - $(CPUSRC)/powerpc/drc_ops.c \ - $(CPUSRC)/powerpc/drc_ops.h \ - $(CPUSRC)/powerpc/ppc_ops.c \ - $(CPUSRC)/powerpc/ppc_mem.c \ - $(CPUSRC)/powerpc/ppc403.c \ - $(CPUSRC)/powerpc/ppc602.c \ - $(CPUSRC)/powerpc/ppc603.c \ + $(CPUSRC)/powerpc/ppccom.h \ + $(CPUSRC)/powerpc/ppcfe.h \ $(DRCDEPS) diff --git a/src/emu/cpu/drcbec.c b/src/emu/cpu/drcbec.c index a0edfd84c06..4506d4f2651 100644 --- a/src/emu/cpu/drcbec.c +++ b/src/emu/cpu/drcbec.c @@ -47,6 +47,58 @@ #define LEBIT (0x1000 << (DRCUML_COND_LE & 15)) +/* internal opcodes */ +enum +{ + DRCUML_OP_LOAD1 = DRCUML_OP_MAX, + DRCUML_OP_LOAD2, + DRCUML_OP_LOAD4, + DRCUML_OP_LOAD8, + DRCUML_OP_LOADS1, + DRCUML_OP_LOADS2, + DRCUML_OP_LOADS4, + DRCUML_OP_LOADS8, + DRCUML_OP_STORE1, + DRCUML_OP_STORE2, + DRCUML_OP_STORE4, + DRCUML_OP_STORE8, + DRCUML_OP_READ1, + DRCUML_OP_READ2, + DRCUML_OP_READ4, + DRCUML_OP_READ8, + DRCUML_OP_READM1, + DRCUML_OP_READM2, + DRCUML_OP_READM4, + DRCUML_OP_READM8, + DRCUML_OP_WRITE1, + DRCUML_OP_WRITE2, + DRCUML_OP_WRITE4, + DRCUML_OP_WRITE8, + DRCUML_OP_WRITEM1, + DRCUML_OP_WRITEM2, + DRCUML_OP_WRITEM4, + DRCUML_OP_WRITEM8, + DRCUML_OP_SEXT1, + DRCUML_OP_SEXT2, + DRCUML_OP_SEXT4, + DRCUML_OP_SEXT8, + DRCUML_OP_FTOI4T, + DRCUML_OP_FTOI4R, + DRCUML_OP_FTOI4C, + DRCUML_OP_FTOI4F, + DRCUML_OP_FTOI4, + DRCUML_OP_FTOI8T, + DRCUML_OP_FTOI8R, + DRCUML_OP_FTOI8C, + DRCUML_OP_FTOI8F, + DRCUML_OP_FTOI8, + DRCUML_OP_FFRI4, + DRCUML_OP_FFRI8, + DRCUML_OP_FFRFS, + DRCUML_OP_FFRFD, +}; + + /*************************************************************************** MACROS @@ -337,10 +389,11 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum UINT8 psize[ARRAY_LENGTH(instlist->param)]; drcuml_instruction modified_inst; int immedbytes, immedwords, pnum; + drcuml_opcode opcode = inst->opcode; void *immed; /* handle most instructions generally, but a few special cases */ - switch (inst->opcode) + switch (opcode) { /* when we hit a HANDLE opcode, register the current pointer for the handle */ case DRCUML_OP_HANDLE: @@ -378,7 +431,7 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum case DRCUML_OP_JMP: assert(inst->numparams == 1); assert(inst->param[0].type == DRCUML_PTYPE_IMMEDIATE); - (dst++)->i = MAKE_OPCODE_FULL(inst->opcode, inst->size, inst->condflags, 1); + (dst++)->i = MAKE_OPCODE_FULL(opcode, inst->size, inst->condflags, 1); dst->inst = (drcbec_instruction *)drclabel_get_codeptr(drcbe->labels, inst->param[0].value, fixup_label, dst); dst++; break; @@ -387,7 +440,7 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum default: /* for RECOVER opcodes, we need to fixup the second parameter into an immediate */ - if (inst->opcode == DRCUML_OP_RECOVER) + if (opcode == DRCUML_OP_RECOVER) { assert(inst->param[1].type == DRCUML_PTYPE_MAPVAR); modified_inst = *inst; @@ -398,22 +451,44 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum /* determine the operand size for each operand; mostly this is just the instruction size */ for (pnum = 0; pnum < inst->numparams; pnum++) psize[pnum] = inst->size; - if ((inst->opcode >= DRCUML_OP_LOAD1U && inst->opcode <= DRCUML_OP_LOAD8U) || inst->opcode == DRCUML_OP_FLOAD) + if (opcode == DRCUML_OP_LOAD || opcode == DRCUML_OP_FLOAD) psize[2] = 4; - if ((inst->opcode >= DRCUML_OP_STORE1 && inst->opcode <= DRCUML_OP_STORE8) || inst->opcode == DRCUML_OP_FSTORE) + if (opcode == DRCUML_OP_STORE || opcode == DRCUML_OP_FSTORE) psize[1] = 4; - if ((inst->opcode >= DRCUML_OP_READ1U && inst->opcode <= DRCUML_OP_READ8M) || inst->opcode == DRCUML_OP_FREAD) - psize[1] = psize[2] = 4; - if ((inst->opcode >= DRCUML_OP_WRITE1 && inst->opcode <= DRCUML_OP_WRIT8M) || inst->opcode == DRCUML_OP_FWRITE) + if (opcode == DRCUML_OP_READ || opcode == DRCUML_OP_READM || opcode == DRCUML_OP_FREAD) + psize[0] = psize[1] = 4; + if (opcode == DRCUML_OP_WRITE || opcode == DRCUML_OP_WRITEM || opcode == DRCUML_OP_FWRITE) psize[0] = psize[1] = 4; - if (inst->opcode >= DRCUML_OP_FTOI4 && inst->opcode <= DRCUML_OP_FTOI4C) - psize[0] = 4; - if (inst->opcode >= DRCUML_OP_FTOI8 && inst->opcode <= DRCUML_OP_FTOI8C) - psize[0] = 8; - if ((inst->opcode >= DRCUML_OP_ZEXT1 && inst->opcode <= DRCUML_OP_SEXT4) || inst->opcode == DRCUML_OP_FFRFS || inst->opcode == DRCUML_OP_FFRI4) + if (opcode == DRCUML_OP_SEXT && inst->param[2].value != DRCUML_SIZE_QWORD) psize[1] = 4; - if (inst->opcode == DRCUML_OP_FFRFD || inst->opcode == DRCUML_OP_FFRI8) - psize[1] = 8; + if (opcode == DRCUML_OP_FTOINT) + psize[0] = 1 << inst->param[2].value; + if (opcode == DRCUML_OP_FFRINT || opcode == DRCUML_OP_FFRFLT) + psize[1] = 1 << inst->param[2].value; + + /* pre-expand opcodes that encode size in them */ + if (opcode == DRCUML_OP_LOAD) + opcode = DRCUML_OP_LOAD1 + (inst->param[3].value & 3); + if (opcode == DRCUML_OP_LOADS) + opcode = DRCUML_OP_LOADS1 + (inst->param[3].value & 3); + if (opcode == DRCUML_OP_STORE) + opcode = DRCUML_OP_STORE1 + (inst->param[3].value & 3); + if (opcode == DRCUML_OP_READ) + opcode = DRCUML_OP_READ1 + (inst->param[2].value & 3); + if (opcode == DRCUML_OP_READM) + opcode = DRCUML_OP_READM1 + (inst->param[3].value & 3); + if (opcode == DRCUML_OP_WRITE) + opcode = DRCUML_OP_WRITE1 + (inst->param[2].value & 3); + if (opcode == DRCUML_OP_WRITEM) + opcode = DRCUML_OP_WRITEM1 + (inst->param[3].value & 3); + if (opcode == DRCUML_OP_SEXT) + opcode = DRCUML_OP_SEXT1 + (inst->param[2].value & 3); + if (opcode == DRCUML_OP_FTOINT) + opcode = DRCUML_OP_FTOI4T + 5 * ((inst->param[2].value & 3) - 2) + inst->param[3].value; + if (opcode == DRCUML_OP_FFRINT) + opcode = DRCUML_OP_FFRI4 + ((inst->param[2].value & 3) - 2); + if (opcode == DRCUML_OP_FFRFLT) + opcode = DRCUML_OP_FFRFS + ((inst->param[2].value & 3) - 2); /* count how many bytes of immediates we need */ immedbytes = 0; @@ -426,7 +501,7 @@ static void drcbec_generate(drcbe_state *drcbe, drcuml_block *block, const drcum immedwords = (immedbytes + sizeof(drcbec_instruction) - 1) / sizeof(drcbec_instruction); /* first item is the opcode, size, condition flags and length */ - (dst++)->i = MAKE_OPCODE_FULL(inst->opcode, inst->size, inst->condflags, inst->numparams + immedwords); + (dst++)->i = MAKE_OPCODE_FULL(opcode, inst->size, inst->condflags, inst->numparams + immedwords); /* immediates start after parameters */ immed = dst + inst->numparams; @@ -504,6 +579,7 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) while (TRUE) { UINT32 opcode = (inst++)->i; + switch (OPCODE_GET_SHORT(opcode)) { /* ----------------------- Control Flow Operations ----------------------- */ @@ -623,6 +699,11 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) PARAM0 = drcbe->state.exp; break; + case MAKE_OPCODE_SHORT(DRCUML_OP_GETFLGS, 4, 0): /* GETFLGS dst[,f] */ + case MAKE_OPCODE_SHORT(DRCUML_OP_GETFLGS, 4, 1): /* GETFLGS dst[,f] */ + PARAM0 = flags; + break; + case MAKE_OPCODE_SHORT(DRCUML_OP_SAVE, 4, 0): /* SAVE dst */ *inst[0].state = drcbe->state; inst[0].state->flags = flags; @@ -636,91 +717,83 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) /* ----------------------- 32-Bit Integer Operations ----------------------- */ - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1U, 4, 0): /* LOAD1U dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1, 4, 0): /* LOAD dst,base,index,BYTE */ PARAM0 = inst[1].puint8[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1S, 4, 0): /* LOAD1S dst,base,index */ - PARAM0 = inst[1].pint8[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2, 4, 0): /* LOAD dst,base,index,WORD */ + PARAM0 = inst[1].puint16[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2U, 4, 0): /* LOAD2U dst,base,index */ - PARAM0 = inst[1].puint16[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4, 4, 0): /* LOAD dst,base,index,DWORD */ + PARAM0 = inst[1].puint32[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2S, 4, 0): /* LOAD2S dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_LOADS1, 4, 0): /* LOADS dst,base,index,BYTE */ + PARAM0 = inst[1].pint8[PARAM2]; + break; + + case MAKE_OPCODE_SHORT(DRCUML_OP_LOADS2, 4, 0): /* LOADS dst,base,index,WORD */ PARAM0 = inst[1].pint16[PARAM2]; break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4U, 4, 0): /* LOAD4U dst,base,index */ - PARAM0 = inst[1].puint32[PARAM2]; + + case MAKE_OPCODE_SHORT(DRCUML_OP_LOADS4, 4, 0): /* LOADS dst,base,index,DWORD */ + PARAM0 = inst[1].pint32[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE1, 4, 0): /* STORE1 dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE1, 4, 0): /* STORE dst,base,index,BYTE */ inst[0].puint8[PARAM1] = PARAM2; break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE2, 4, 0): /* STORE2 dst,base,index */ + + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE2, 4, 0): /* STORE dst,base,index,WORD */ inst[0].puint16[PARAM1] = PARAM2; break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE4, 4, 0): /* STORE4 dst,base,index */ + + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE4, 4, 0): /* STORE dst,base,index,DWORD */ inst[0].puint32[PARAM1] = PARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ1U, 4, 0): /* READ1U dst,space,src1 */ - PARAM0 = (UINT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_READ1S, 4, 0): /* READ1S dst,space,src1 */ - PARAM0 = (INT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_READ2U, 4, 0): /* READ2U dst,space,src1 */ - PARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_READ2S, 4, 0): /* READ2S dst,space,src1 */ - PARAM0 = (INT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ1, 4, 0): /* READ dst,src1,space_BYTE */ + PARAM0 = (UINT8)(*active_address_space[PARAM2 / 16].accessors->read_byte)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ2M, 4, 0): /* READ2M dst,space,src1,mask */ - PARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word_masked)(PARAM2, PARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ2, 4, 0): /* READ dst,src1,space_WORD */ + PARAM0 = (UINT16)(*active_address_space[PARAM2 / 16].accessors->read_word)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ4U, 4, 0): /* READ4U dst,space,src1 */ - PARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ4, 4, 0): /* READ dst,src1,space_DWORD */ + PARAM0 = (UINT32)(*active_address_space[PARAM2 / 16].accessors->read_dword)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ4M, 4, 0): /* READ4M dst,space,src1,mask */ - PARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword_masked)(PARAM2, PARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_READM2, 4, 0): /* READM dst,src1,mask,space_WORD */ + PARAM0 = (UINT16)(*active_address_space[PARAM3 / 16].accessors->read_word_masked)(PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE1, 4, 0): /* WRITE1 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_byte)(PARAM1, PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READM4, 4, 0): /* READM dst,src1,mask,space_DWORD */ + PARAM0 = (UINT32)(*active_address_space[PARAM3 / 16].accessors->read_dword_masked)(PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE2, 4, 0): /* WRITE2 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_word)(PARAM1, PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE1, 4, 0): /* WRITE dst,src1,space_BYTE */ + (*active_address_space[PARAM2 / 16].accessors->write_byte)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT2M, 4, 0): /* WRIT2M space,dst,mask,src1 */ - (*active_address_space[PARAM0].accessors->write_word_masked)(PARAM1, PARAM2, PARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE2, 4, 0): /* WRITE dst,src1,space_WORD */ + (*active_address_space[PARAM2 / 16].accessors->write_word)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE4, 4, 0): /* WRITE4 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_dword)(PARAM1, PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE4, 4, 0): /* WRITE dst,src1,space_DWORD */ + (*active_address_space[PARAM2 / 16].accessors->write_dword)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT4M, 4, 0): /* WRIT4M space,dst,mask,src1 */ - (*active_address_space[PARAM0].accessors->write_dword_masked)(PARAM1, PARAM2, PARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITEM2, 4, 0): /* WRITEM dst,src1,mask,space_WORD */ + (*active_address_space[PARAM3 / 16].accessors->write_word_masked)(PARAM0, PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FLAGS, 4, 0): /* FLAGS dst,mask,table */ - PARAM0 = (PARAM0 & ~PARAM1) | (inst[2].puint32[flags & 0x1f] & PARAM1); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITEM4, 4, 0): /* WRITEM dst,src1,mask,space_DWORD */ + (*active_address_space[PARAM3 / 16].accessors->write_dword_masked)(PARAM0, PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_SETC, 4, 0): /* SETC src,bitnum */ + case MAKE_OPCODE_SHORT(DRCUML_OP_CARRY, 4, 0): /* CARRY src,bitnum */ flags = (flags & ~DRCUML_FLAG_C) | ((PARAM0 >> (PARAM1 & 31)) & DRCUML_FLAG_C); break; @@ -733,12 +806,8 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) PARAM0 = PARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT1, 4, 0): /* ZEXT1 dst,src */ - PARAM0 = (UINT8)PARAM1; - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT2, 4, 0): /* ZEXT2 dst,src */ - PARAM0 = (UINT16)PARAM1; + case MAKE_OPCODE_SHORT(DRCUML_OP_SET, 4, 1): /* SET dst,c */ + PARAM0 = OPCODE_FAIL_CONDITION(opcode, flags) ? 0 : 1; break; case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT1, 4, 0): /* SEXT1 dst,src */ @@ -749,12 +818,12 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) PARAM0 = (INT16)PARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_XTRACT, 4, 0): /* XTRACT dst,src,count,mask[,f] */ + case MAKE_OPCODE_SHORT(DRCUML_OP_ROLAND, 4, 0): /* ROLAND dst,src,count,mask[,f] */ shift = PARAM2 & 31; PARAM0 = ((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_INSERT, 4, 0): /* INSERT dst,src,count,mask[,f] */ + case MAKE_OPCODE_SHORT(DRCUML_OP_ROLINS, 4, 0): /* ROLINS dst,src,count,mask[,f] */ shift = PARAM2 & 31; PARAM0 = (PARAM0 & ~PARAM3) | (((PARAM1 << shift) | (PARAM1 >> (32 - shift))) & PARAM3); break; @@ -1025,123 +1094,107 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) /* ----------------------- 64-Bit Integer Operations ----------------------- */ - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1U, 8, 0): /* DLOAD1U dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1, 8, 0): /* DLOAD dst,base,index,BYTE */ DPARAM0 = inst[1].puint8[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD1S, 8, 0): /* DLOAD1S dst,base,index */ - DPARAM0 = inst[1].pint8[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2, 8, 0): /* DLOAD dst,base,index,WORD */ + DPARAM0 = inst[1].puint16[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2U, 8, 0): /* DLOAD2U dst,base,index */ - DPARAM0 = inst[1].puint16[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4, 8, 0): /* DLOAD dst,base,index,DWORD */ + DPARAM0 = inst[1].puint32[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD2S, 8, 0): /* DLOAD2S dst,base,index */ - DPARAM0 = inst[1].pint16[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD8, 8, 0): /* DLOAD dst,base,index,QWORD */ + DPARAM0 = inst[1].puint64[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4U, 8, 0): /* DLOAD4U dst,base,index */ - DPARAM0 = inst[1].puint32[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOADS1, 8, 0): /* DLOADS dst,base,index,BYTE */ + DPARAM0 = inst[1].pint8[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD4S, 8, 0): /* DLOAD4S dst,base,index */ - DPARAM0 = inst[1].pint32[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOADS2, 8, 0): /* DLOADS dst,base,index,WORD */ + DPARAM0 = inst[1].pint16[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_LOAD8U, 8, 0): /* DLOAD8U dst,base,index */ - DPARAM0 = inst[1].puint64[PARAM2]; + case MAKE_OPCODE_SHORT(DRCUML_OP_LOADS4, 8, 0): /* DLOADS dst,base,index,DWORD */ + DPARAM0 = inst[1].pint32[PARAM2]; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE1, 8, 0): /* DSTORE1 dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE1, 8, 0): /* DSTORE dst,base,index,BYTE */ inst[0].puint8[PARAM1] = DPARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE2, 8, 0): /* DSTORE2 dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE2, 8, 0): /* DSTORE dst,base,index,WORD */ inst[0].puint16[PARAM1] = DPARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE4, 8, 0): /* DSTORE4 dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE4, 8, 0): /* DSTORE dst,base,index,DWORD */ inst[0].puint32[PARAM1] = DPARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_STORE8, 8, 0): /* DSTORE8 dst,base,index */ + case MAKE_OPCODE_SHORT(DRCUML_OP_STORE8, 8, 0): /* DSTORE dst,base,index,QWORD */ inst[0].puint64[PARAM1] = DPARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ1U, 8, 0): /* DREAD1U dst,space,src1 */ - DPARAM0 = (UINT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_READ1S, 8, 0): /* DREAD1S dst,space,src1 */ - DPARAM0 = (INT8)(*active_address_space[PARAM1].accessors->read_byte)(PARAM2); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_READ2U, 8, 0): /* DREAD2U dst,space,src1 */ - DPARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ1, 8, 0): /* DREAD dst,src1,space_BYTE */ + DPARAM0 = (UINT8)(*active_address_space[PARAM2 / 16].accessors->read_byte)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ2S, 8, 0): /* DREAD2S dst,space,src1 */ - DPARAM0 = (INT16)(*active_address_space[PARAM1].accessors->read_word)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ2, 8, 0): /* DREAD dst,src1,space_WORD */ + DPARAM0 = (UINT16)(*active_address_space[PARAM2 / 16].accessors->read_word)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ2M, 8, 0): /* DREAD2M dst,space,src1,mask */ - DPARAM0 = (UINT16)(*active_address_space[PARAM1].accessors->read_word_masked)(PARAM2, DPARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ4, 8, 0): /* DREAD dst,src1,space_DWORD */ + DPARAM0 = (UINT32)(*active_address_space[PARAM2 / 16].accessors->read_dword)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ4U, 8, 0): /* DREAD4U dst,space,src1 */ - DPARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READ8, 8, 0): /* DREAD dst,src1,space_QOWRD */ + DPARAM0 = (UINT64)(*active_address_space[PARAM2 / 16].accessors->read_qword)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ4S, 8, 0): /* DREAD4S dst,space,src1 */ - DPARAM0 = (INT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READM2, 8, 0): /* DREADM dst,src1,mask,space_WORD */ + DPARAM0 = (UINT16)(*active_address_space[PARAM3 / 16].accessors->read_word_masked)(PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ4M, 8, 0): /* DREAD4M dst,space,src1,mask */ - DPARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword_masked)(PARAM2, DPARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_READM4, 8, 0): /* DREADM dst,src1,mask,space_DWORD */ + DPARAM0 = (UINT32)(*active_address_space[PARAM3 / 16].accessors->read_dword_masked)(PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ8U, 8, 0): /* DREAD8U dst,space,src1 */ - DPARAM0 = (UINT64)(*active_address_space[PARAM1].accessors->read_qword)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_READM8, 8, 0): /* DREADM dst,src1,mask,space_QWORD */ + DPARAM0 = (UINT64)(*active_address_space[PARAM3 / 16].accessors->read_qword_masked)(PARAM1, PARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_READ8M, 8, 0): /* DREAD8M dst,space,src1,mask */ - DPARAM0 = (UINT64)(*active_address_space[PARAM1].accessors->read_qword_masked)(PARAM2, DPARAM3); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE1, 8, 0): /* DWRITE dst,src1,space_BYTE */ + (*active_address_space[PARAM2 / 16].accessors->write_byte)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE1, 8, 0): /* DWRITE1 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_byte)(PARAM1, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE2, 8, 0): /* DWRITE dst,src1,space_WORD */ + (*active_address_space[PARAM2 / 16].accessors->write_word)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE2, 8, 0): /* DWRITE2 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_word)(PARAM1, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE4, 8, 0): /* DWRITE dst,src1,space_DWORD */ + (*active_address_space[PARAM2 / 16].accessors->write_dword)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT2M, 8, 0): /* DWRIT2M space,dst,mask,src1 */ - (*active_address_space[PARAM0].accessors->write_word_masked)(PARAM1, DPARAM3, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE8, 8, 0): /* DWRITE dst,src1,space_QWORD */ + (*active_address_space[PARAM2 / 16].accessors->write_qword)(PARAM0, PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE4, 8, 0): /* DWRITE4 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_dword)(PARAM1, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITEM2, 8, 0): /* DWRITEM dst,src1,mask,space_WORD */ + (*active_address_space[PARAM3 / 16].accessors->write_word_masked)(PARAM0, DPARAM1, DPARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT4M, 8, 0): /* DWRIT4M space,dst,mask,src1 */ - (*active_address_space[PARAM0].accessors->write_dword_masked)(PARAM1, DPARAM3, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITEM4, 8, 0): /* DWRITEM dst,src1,mask,space_DWORD */ + (*active_address_space[PARAM3 / 16].accessors->write_dword_masked)(PARAM0, DPARAM1, DPARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRITE8, 8, 0): /* DWRITE8 space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_qword)(PARAM1, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_WRITEM8, 8, 0): /* DWRITEM dst,src1,mask,space_QWORD */ + (*active_address_space[PARAM3 / 16].accessors->write_qword_masked)(PARAM0, DPARAM1, DPARAM2); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_WRIT8M, 8, 0): /* DWRIT8M space,dst,mask,src1 */ - (*active_address_space[PARAM0].accessors->write_qword_masked)(PARAM1, DPARAM3, DPARAM2); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_FLAGS, 8, 0): /* DFLAGS dst,mask,table */ - DPARAM0 = (DPARAM0 & ~DPARAM1) | (inst[2].puint64[flags & 0x0f] & DPARAM1); - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_SETC, 8, 0): /* DSETC src,bitnum */ + case MAKE_OPCODE_SHORT(DRCUML_OP_CARRY, 8, 0): /* DCARRY src,bitnum */ flags = (flags & ~DRCUML_FLAG_C) | ((DPARAM0 >> (DPARAM1 & 63)) & DRCUML_FLAG_C); break; @@ -1154,36 +1207,28 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) DPARAM0 = DPARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT1, 8, 0): /* DZEXT1 dst,src */ - DPARAM0 = (UINT8)PARAM1; - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT2, 8, 0): /* DZEXT2 dst,src */ - DPARAM0 = (UINT16)PARAM1; + case MAKE_OPCODE_SHORT(DRCUML_OP_SET, 8, 1): /* DSET dst,c */ + DPARAM0 = OPCODE_FAIL_CONDITION(opcode, flags) ? 0 : 1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_ZEXT4, 8, 0): /* DZEXT4 dst,src */ - DPARAM0 = (UINT32)PARAM1; - break; - - case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT1, 8, 0): /* DSEXT1 dst,src */ + case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT1, 8, 0): /* DSEXT dst,src,BYTE */ DPARAM0 = (INT8)PARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT2, 8, 0): /* DSEXT2 dst,src */ + case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT2, 8, 0): /* DSEXT dst,src,WORD */ DPARAM0 = (INT16)PARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT4, 8, 0): /* DSEXT4 dst,src */ + case MAKE_OPCODE_SHORT(DRCUML_OP_SEXT4, 8, 0): /* DSEXT dst,src,DWORD */ DPARAM0 = (INT32)PARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_XTRACT, 8, 0): /* DXTRACT dst,src,count,mask[,f] */ + case MAKE_OPCODE_SHORT(DRCUML_OP_ROLAND, 8, 0): /* DROLAND dst,src,count,mask[,f] */ shift = DPARAM2 & 63; DPARAM0 = ((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_INSERT, 8, 0): /* DINSERT dst,src,count,mask[,f] */ + case MAKE_OPCODE_SHORT(DRCUML_OP_ROLINS, 8, 0): /* DROLINS dst,src,count,mask[,f] */ shift = DPARAM2 & 63; DPARAM0 = (DPARAM0 & ~DPARAM3) | (((DPARAM1 << shift) | (DPARAM1 >> (64 - shift))) & DPARAM3); break; @@ -1455,12 +1500,12 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) inst[0].pfloat[PARAM1] = FSPARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FREAD, 4, 0): /* FSREAD dst,space,src1 */ - PARAM0 = (UINT32)(*active_address_space[PARAM1].accessors->read_dword)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_FREAD, 4, 0): /* FSREAD dst,src1,space */ + PARAM0 = (UINT32)(*active_address_space[PARAM2].accessors->read_dword)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FWRITE, 4, 0): /* FSWRITE space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_dword)(PARAM1, PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_FWRITE, 4, 0): /* FSWRITE dst,src1,space */ + (*active_address_space[PARAM2].accessors->write_dword)(PARAM0, PARAM1); break; case MAKE_OPCODE_SHORT(DRCUML_OP_FMOV, 4, 1): /* FSMOV dst,src[,c] */ @@ -1472,10 +1517,6 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) FSPARAM0 = FSPARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4, 4, 0): /* FSTOI4 dst,src1 */ - *inst[0].pint32 = FSPARAM1; - break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4T, 4, 0): /* FSTOI4T dst,src1 */ if (FSPARAM1 >= 0) *inst[0].pint32 = floor(FSPARAM1); @@ -1498,8 +1539,8 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) *inst[0].pint32 = ceil(FSPARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8, 4, 0): /* FSTOI8 dst,src1 */ - *inst[0].pint64 = FSPARAM1; + case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4, 4, 0): /* FSTOI4 dst,src1 */ + *inst[0].pint32 = FSPARAM1; break; case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8T, 4, 0): /* FSTOI8T dst,src1 */ @@ -1524,8 +1565,8 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) *inst[0].pint64 = ceil(FSPARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FFRFD, 4, 0): /* FSFRFD dst,src1 */ - FSPARAM0 = FDPARAM1; + case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8, 4, 0): /* FSTOI8 dst,src1 */ + *inst[0].pint64 = FSPARAM1; break; case MAKE_OPCODE_SHORT(DRCUML_OP_FFRI4, 4, 0): /* FSFRI4 dst,src1 */ @@ -1536,6 +1577,10 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) FSPARAM0 = *inst[1].pint64; break; + case MAKE_OPCODE_SHORT(DRCUML_OP_FFRFD, 4, 0): /* FSFRFD dst,src1 */ + FSPARAM0 = FDPARAM1; + break; + case MAKE_OPCODE_SHORT(DRCUML_OP_FADD, 4, 0): /* FSADD dst,src1,src2 */ FSPARAM0 = FSPARAM1 + FSPARAM2; break; @@ -1590,12 +1635,12 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) inst[0].pdouble[PARAM1] = FDPARAM2; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FREAD, 8, 0): /* FDREAD dst,space,src1 */ - DPARAM0 = (UINT64)(*active_address_space[PARAM1].accessors->read_qword)(PARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_FREAD, 8, 0): /* FDREAD dst,src1,space */ + DPARAM0 = (UINT64)(*active_address_space[PARAM2].accessors->read_qword)(PARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FWRITE, 8, 0): /* FDWRITE space,dst,src1 */ - (*active_address_space[PARAM0].accessors->write_qword)(PARAM1, DPARAM2); + case MAKE_OPCODE_SHORT(DRCUML_OP_FWRITE, 8, 0): /* FDWRITE dst,src1,space */ + (*active_address_space[PARAM2].accessors->write_qword)(PARAM0, DPARAM1); break; case MAKE_OPCODE_SHORT(DRCUML_OP_FMOV, 8, 1): /* FDMOV dst,src[,c] */ @@ -1607,10 +1652,6 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) FDPARAM0 = FDPARAM1; break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4, 8, 0): /* FDTOI4 dst,src1 */ - *inst[0].pint32 = FDPARAM1; - break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4T, 8, 0): /* FDTOI4T dst,src1 */ if (FDPARAM1 >= 0) *inst[0].pint32 = floor(FDPARAM1); @@ -1633,8 +1674,8 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) *inst[0].pint32 = ceil(FDPARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8, 8, 0): /* FDTOI8 dst,src1 */ - *inst[0].pint64 = FDPARAM1; + case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI4, 8, 0): /* FDTOI4 dst,src1 */ + *inst[0].pint32 = FDPARAM1; break; case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8T, 8, 0): /* FDTOI8T dst,src1 */ @@ -1659,8 +1700,8 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) *inst[0].pint64 = ceil(FDPARAM1); break; - case MAKE_OPCODE_SHORT(DRCUML_OP_FFRFS, 8, 0): /* FDFRFS dst,src1 */ - FDPARAM0 = FSPARAM1; + case MAKE_OPCODE_SHORT(DRCUML_OP_FTOI8, 8, 0): /* FDTOI8 dst,src1 */ + *inst[0].pint64 = FDPARAM1; break; case MAKE_OPCODE_SHORT(DRCUML_OP_FFRI4, 8, 0): /* FDFRI4 dst,src1 */ @@ -1671,6 +1712,14 @@ static int drcbec_execute(drcbe_state *drcbe, drcuml_codehandle *entry) FDPARAM0 = *inst[1].pint64; break; + case MAKE_OPCODE_SHORT(DRCUML_OP_FFRFS, 8, 0): /* FDFRFS dst,src1 */ + FDPARAM0 = FSPARAM1; + break; + + case MAKE_OPCODE_SHORT(DRCUML_OP_FRNDS, 8, 0): /* FDRNDS dst,src1 */ + FDPARAM0 = (float)FDPARAM1; + break; + case MAKE_OPCODE_SHORT(DRCUML_OP_FADD, 8, 0): /* FDADD dst,src1,src2 */ FDPARAM0 = FDPARAM1 + FDPARAM2; break; diff --git a/src/emu/cpu/drcbex64.c b/src/emu/cpu/drcbex64.c index 29dc2377f2d..1e4dd02e44b 100644 --- a/src/emu/cpu/drcbex64.c +++ b/src/emu/cpu/drcbex64.c @@ -18,6 +18,8 @@ * Identify common pairs and optimize output + * Convert AND 0xff/0xffff to movzx + **************************************************************************** ------------------------- @@ -396,48 +398,23 @@ static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instru static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); @@ -466,20 +443,10 @@ static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruc static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); @@ -514,50 +481,25 @@ static const opcode_table_entry opcode_table_source[] = /* Internal Register Operations */ { DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */ { DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */ - { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */ - { DRCUML_OP_SAVE, op_save }, /* SAVE dst,index */ - { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst,index */ + { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst */ + { DRCUML_OP_GETFLGS, op_getflgs }, /* GETFLGS dst[,f] */ + { DRCUML_OP_SAVE, op_save }, /* SAVE dst */ + { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst */ /* Integer Operations */ - { DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */ - { DRCUML_OP_LOAD1S, op_load1s }, /* LOAD1S dst,base,index */ - { DRCUML_OP_LOAD2U, op_load2u }, /* LOAD2U dst,base,index */ - { DRCUML_OP_LOAD2S, op_load2s }, /* LOAD2S dst,base,index */ - { DRCUML_OP_LOAD4U, op_load4u }, /* LOAD4U dst,base,index */ - { DRCUML_OP_LOAD4S, op_load4s }, /* LOAD4S dst,base,index */ - { DRCUML_OP_LOAD8U, op_load8u }, /* LOAD8U dst,base,index */ - { DRCUML_OP_STORE1, op_store1 }, /* STORE1 base,index,src */ - { DRCUML_OP_STORE2, op_store2 }, /* STORE2 base,index,src */ - { DRCUML_OP_STORE4, op_store4 }, /* STORE4 base,index,src */ - { DRCUML_OP_STORE8, op_store8 }, /* STORE8 base,index,src */ - { DRCUML_OP_READ1U, op_read1u }, /* READ1U dst,space,src1 */ - { DRCUML_OP_READ1S, op_read1s }, /* READ1S dst,space,src1 */ - { DRCUML_OP_READ2U, op_read2u }, /* READ2U dst,space,src1 */ - { DRCUML_OP_READ2S, op_read2s }, /* READ2S dst,space,src1 */ - { DRCUML_OP_READ2M, op_read2m }, /* READ2M dst,space,src1,mask */ - { DRCUML_OP_READ4U, op_read4u }, /* READ4U dst,space,src1 */ - { DRCUML_OP_READ4S, op_read4s }, /* READ4S dst,space,src1 */ - { DRCUML_OP_READ4M, op_read4m }, /* READ4M dst,space,src1,mask */ - { DRCUML_OP_READ8U, op_read8u }, /* READ8U dst,space,src1 */ - { DRCUML_OP_READ8M, op_read8m }, /* READ8M dst,space,src1,mask */ - { DRCUML_OP_WRITE1, op_write1 }, /* WRITE1 space,dst,src1 */ - { DRCUML_OP_WRITE2, op_write2 }, /* WRITE2 space,dst,src1 */ - { DRCUML_OP_WRIT2M, op_writ2m }, /* WRIT2M space,dst,src1 */ - { DRCUML_OP_WRITE4, op_write4 }, /* WRITE4 space,dst,src1 */ - { DRCUML_OP_WRIT4M, op_writ4m }, /* WRIT4M space,dst,mask,src1 */ - { DRCUML_OP_WRITE8, op_write8 }, /* WRITE8 space,dst,src1 */ - { DRCUML_OP_WRIT8M, op_writ8m }, /* WRIT8M space,dst,mask,src1 */ - { DRCUML_OP_FLAGS, op_flags }, /* FLAGS dst,mask,table */ - { DRCUML_OP_SETC, op_setc }, /* FLAGS src,bitnum */ + { DRCUML_OP_LOAD, op_load }, /* LOAD dst,base,index,size */ + { DRCUML_OP_LOADS, op_loads }, /* LOADS dst,base,index,size */ + { DRCUML_OP_STORE, op_store }, /* STORE base,index,src,size */ + { DRCUML_OP_READ, op_read }, /* READ dst,src1,spacesize */ + { DRCUML_OP_READM, op_readm }, /* READM dst,src1,mask,spacesize */ + { DRCUML_OP_WRITE, op_write }, /* WRITE dst,src1,spacesize */ + { DRCUML_OP_WRITEM, op_writem }, /* WRITEM dst,src1,spacesize */ + { DRCUML_OP_CARRY, op_carry }, /* CARRY src,bitnum */ + { DRCUML_OP_SET, op_set }, /* SET dst,c */ { DRCUML_OP_MOV, op_mov }, /* MOV dst,src[,c] */ - { DRCUML_OP_ZEXT1, op_zext1 }, /* ZEXT1 dst,src */ - { DRCUML_OP_ZEXT2, op_zext2 }, /* ZEXT2 dst,src */ - { DRCUML_OP_ZEXT4, op_zext4 }, /* ZEXT4 dst,src */ - { DRCUML_OP_SEXT1, op_sext1 }, /* SEXT1 dst,src */ - { DRCUML_OP_SEXT2, op_sext2 }, /* SEXT2 dst,src */ - { DRCUML_OP_SEXT4, op_sext4 }, /* SEXT4 dst,src */ - { DRCUML_OP_XTRACT, op_xtract }, /* XTRACT dst,src1,src2,src3 */ - { DRCUML_OP_INSERT, op_insert }, /* INSERT dst,src1,src2,src3 */ + { DRCUML_OP_SEXT, op_sext }, /* SEXT dst,src */ + { DRCUML_OP_ROLAND, op_roland }, /* ROLAND dst,src1,src2,src3 */ + { DRCUML_OP_ROLINS, op_rolins }, /* ROLINS dst,src1,src2,src3 */ { DRCUML_OP_ADD, op_add }, /* ADD dst,src1,src2[,f] */ { DRCUML_OP_ADDC, op_addc }, /* ADDC dst,src1,src2[,f] */ { DRCUML_OP_SUB, op_sub }, /* SUB dst,src1,src2[,f] */ @@ -587,20 +529,10 @@ static const opcode_table_entry opcode_table_source[] = { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,space,src1 */ { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE space,dst,src1 */ { DRCUML_OP_FMOV, op_fmov }, /* FMOV dst,src1[,c] */ - { DRCUML_OP_FTOI4, op_ftoi4 }, /* FTOI4 dst,src1 */ - { DRCUML_OP_FTOI4T, op_ftoi4t }, /* FTOI4T dst,src1 */ - { DRCUML_OP_FTOI4R, op_ftoi4r }, /* FTOI4R dst,src1 */ - { DRCUML_OP_FTOI4F, op_ftoi4f }, /* FTOI4F dst,src1 */ - { DRCUML_OP_FTOI4C, op_ftoi4c }, /* FTOI4C dst,src1 */ - { DRCUML_OP_FTOI8, op_ftoi8 }, /* FTOI8 dst,src1 */ - { DRCUML_OP_FTOI8T, op_ftoi8t }, /* FTOI8T dst,src1 */ - { DRCUML_OP_FTOI8R, op_ftoi8r }, /* FTOI8R dst,src1 */ - { DRCUML_OP_FTOI8F, op_ftoi8f }, /* FTOI8F dst,src1 */ - { DRCUML_OP_FTOI8C, op_ftoi8c }, /* FTOI8C dst,src1 */ - { DRCUML_OP_FFRFS, op_ffrfs }, /* FFRFS dst,src1 */ - { DRCUML_OP_FFRFD, op_ffrfd }, /* FFRFD dst,src1 */ - { DRCUML_OP_FFRI4, op_ffri4 }, /* FFRI4 dst,src1 */ - { DRCUML_OP_FFRI8, op_ffri8 }, /* FFRI8 dst,src1 */ + { DRCUML_OP_FTOINT, op_ftoint }, /* FTOINT dst,src1,size,round */ + { DRCUML_OP_FFRINT, op_ffrint }, /* FFRINT dst,src1,size */ + { DRCUML_OP_FFRFLT, op_ffrflt }, /* FFRFLT dst,src1,size */ + { DRCUML_OP_FRNDS, op_frnds }, /* FRNDS dst,src1 */ { DRCUML_OP_FADD, op_fadd }, /* FADD dst,src1,src2 */ { DRCUML_OP_FSUB, op_fsub }, /* FSUB dst,src1,src2 */ { DRCUML_OP_FCMP, op_fcmp }, /* FCMP src1,src2 */ @@ -3553,6 +3485,133 @@ static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- + op_getflgs - process a GETFLGS opcode +-------------------------------------------------*/ + +static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +{ + drcuml_parameter dstp; + int dstreg; + + /* validate instruction */ + assert(inst->size == 4); + assert(inst->condflags != DRCUML_COND_ALWAYS); + + /* normalize parameters */ + param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); + + /* pick a target register for the general case */ + dstreg = param_select_register(REG_EAX, &dstp, NULL); + + switch (inst->condflags) + { + /* single flags only */ + case DRCUML_FLAG_C: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + break; + + case DRCUML_FLAG_V: + emit_setcc_r8(&dst, COND_O, REG_AL); // seto al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 + break; + + case DRCUML_FLAG_Z: + emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 + break; + + case DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_S, REG_AL); // sets al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 3); // shl dstreg,3 + break; + + case DRCUML_FLAG_U: + emit_setcc_r8(&dst, COND_P, REG_AL); // setp al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 4); // shl dstreg,4 + break; + + /* carry plus another flag */ + case DRCUML_FLAG_C | DRCUML_FLAG_V: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_setcc_r8(&dst, COND_O, REG_CL); // seto cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + break; + + case DRCUML_FLAG_C | DRCUML_FLAG_Z: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + break; + + case DRCUML_FLAG_C | DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 8, 0)); // lea dstreg,[eax+ecx*8] + break; + + /* overflow plus another flag */ + case DRCUML_FLAG_V | DRCUML_FLAG_Z: + emit_setcc_r8(&dst, COND_O, REG_AL); // seto al + emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 + break; + + case DRCUML_FLAG_V | DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_O, REG_AL); // seto al + emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 + break; + + /* zero plus another flag */ + case DRCUML_FLAG_Z | DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al + emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 + break; + + /* default cases */ + default: + emit_pushf(&dst); // pushf + emit_pop_r64(&dst, REG_EAX); // pop eax + emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 + emit_movzx_r32_m8(&dst, dstreg, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsmap[0]))); + // movzx dstreg,[flags_map] + break; + } + + /* 32-bit form */ + if (inst->size == 4) + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + + /* 64-bit form */ + else if (inst->size == 8) + emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + + return dst; +} + + +/*------------------------------------------------- op_save - process a SAVE opcode -------------------------------------------------*/ @@ -3680,12 +3739,12 @@ static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instru ***************************************************************************/ /*------------------------------------------------- - op_load1u - process a LOAD1U opcode + op_load - process a LOAD opcode -------------------------------------------------*/ -static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, basep, indp; + drcuml_parameter dstp, basep, indp, sizep; int basereg, dstreg; INT32 baseoffs; @@ -3694,30 +3753,46 @@ static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); /* determine the pointer base */ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); + /* pick a target register for the general case */ + dstreg = param_select_register(REG_EAX, &dstp, NULL); + /* immediate index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movzx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp] + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movzx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movzx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movzx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp] + } /* other index */ else { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movzx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movzx dstreg,[basep + 1*indp] + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movzx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movzx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movzx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movzx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp] } - /* store to appropriate target size */ + /* store result */ if (inst->size == 4) emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - else if (inst->size == 8) + else emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg return dst; @@ -3725,12 +3800,12 @@ static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_load1s - process a LOAD1S opcode + op_loads - process a LOADS opcode -------------------------------------------------*/ -static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, basep, indp; + drcuml_parameter dstp, basep, indp, sizep; int basereg, dstreg; INT32 baseoffs; @@ -3739,325 +3814,139 @@ static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); /* determine the pointer base */ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - /* 32-bit form */ - if (inst->size == 4) - { - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx eax,[basep + 1*indp] - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx eax,[basep + 1*indp] - } - - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ - else - { - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsx_r64_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx rax,[basep + 1*indp] - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsx_r64_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx rax,[basep + 1*indp] - } - - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - return dst; -} - - -/*------------------------------------------------- - op_load2u - process a LOAD2U opcode --------------------------------------------------*/ - -static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int basereg, dstreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - /* immediate index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movzx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movzx dstreg,[basep + 2*indp] - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movzx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movzx dstreg,[basep + 2*indp] - } - - /* store to appropriate target size */ - if (inst->size == 4) - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_load2s - process a LOAD2S opcode --------------------------------------------------*/ - -static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int basereg, dstreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - - /* 32-bit form */ - if (inst->size == 4) { - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movsx eax,[basep + 2*indp] - - /* other index */ - else + if (inst->size == 4) { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx eax,[basep + 2*indp] + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movsx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value));// movsx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] } - - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ - else - { - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsx_r64_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value)); // movsx rax,[basep + 2*indp] - - /* other index */ - else + else if (inst->size == 8) { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsx_r64_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx rax,[basep + 2*indp] + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r64_m8(&dst, dstreg, MBD(basereg, baseoffs + 1*indp.value)); // movzx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r64_m16(&dst, dstreg, MBD(basereg, baseoffs + 2*indp.value));// movzx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_movsxd_r64_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value));// movsxd dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp] } - - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg } - return dst; -} - - -/*------------------------------------------------- - op_load4u - process a LOAD4U opcode --------------------------------------------------*/ - -static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int basereg, dstreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_r32_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] /* other index */ else { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp] + if (inst->size == 4) + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // mov dstreg,[basep + 4*indp] + } + else if (inst->size == 8) + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r64_m8(&dst, dstreg, MBISD(basereg, indreg, 1, baseoffs)); // movsx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r64_m16(&dst, dstreg, MBISD(basereg, indreg, 2, baseoffs)); // movsx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_movsxd_r64_m32(&dst, dstreg, MBISD(basereg, indreg, 4, baseoffs)); // movsxd dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp] + } } - /* store to appropriate target size */ + /* store result */ if (inst->size == 4) emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_load4s - process a LOAD4S opcode --------------------------------------------------*/ - -static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int basereg, dstreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsxd_r64_m32(&dst, dstreg, MBD(basereg, baseoffs + 4*indp.value)); // mov dstreg,[basep + 4*indp] - - /* other index */ else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsxd_r64_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // movsx dstreg,[basep + 4*indp] - } - - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg return dst; } /*------------------------------------------------- - op_load8u - process a LOAD8U opcode + op_store - process a STORE opcode -------------------------------------------------*/ -static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, basep, indp; - int basereg, dstreg; + drcuml_parameter srcp, basep, indp, sizep; + int srcreg, basereg; INT32 baseoffs; /* validate instruction */ - assert(inst->size == 8); + assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); + param_normalize_4(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI, &sizep, PTYPE_I); /* determine the pointer base */ basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_r64_m64(&dst, dstreg, MBD(basereg, baseoffs + 8*indp.value)); // mov dstreg,[basep + 8*indp] - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_mov_r64_m64(&dst, dstreg, MBISD(basereg, indreg, 8, baseoffs)); // mov dstreg,[basep + 8*indp] - } - - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,edx:dstreg - - return dst; -} - - -/*------------------------------------------------- - op_store1 - process a STORE1 opcode --------------------------------------------------*/ - -static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; - int basereg, srcreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); - /* pick a source register for the general case */ srcreg = param_select_register(REG_EAX, &srcp, NULL); - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - /* degenerate case: constant index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) { + /* immediate source */ if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m8_imm(&dst, MBD(basereg, baseoffs + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_imm(&dst, MBD(basereg, baseoffs + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_imm(&dst, MBD(basereg, baseoffs + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp + else if (sizep.value == DRCUML_SIZE_QWORD) + { + if (short_immediate(srcp.value)) + emit_mov_m64_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value);// mov [basep + 8*indp],srcp + else + { + emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value);// mov [basep + 8*indp],srcp + emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 8*indp.value + 4), srcp.value >> 32); + // mov [basep + 8*indp + 4],srcp >> 32 + } + } + } + + /* variable source */ else { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m8_r8(&dst, MBD(basereg, baseoffs + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg + if (sizep.value != DRCUML_SIZE_QWORD) + emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_r8(&dst, MBD(basereg, baseoffs + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_r16(&dst, MBD(basereg, baseoffs + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_r32(&dst, MBD(basereg, baseoffs + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_m64_r64(&dst, MBD(basereg, baseoffs + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg } } @@ -4066,64 +3955,44 @@ static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruc { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m8_imm(&dst, MBISD(basereg, indreg, 1, baseoffs), srcp.value); // mov [basep + 1*ecx],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m8_r8(&dst, MBISD(basereg, indreg, 1, baseoffs), srcreg); // mov [basep + 1*ecx],srcreg - } - } - return dst; -} - - -/*------------------------------------------------- - op_store2 - process a STORE2 opcode --------------------------------------------------*/ - -static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; - int basereg, srcreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); - /* pick a source register for the general case */ - srcreg = param_select_register(REG_EAX, &srcp, NULL); - - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - - /* degenerate case: constant index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - { + /* immediate source */ if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m16_imm(&dst, MBD(basereg, baseoffs + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp - else { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m16_r16(&dst, MBD(basereg, baseoffs + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_imm(&dst, MBISD(basereg, indreg, 1, baseoffs), srcp.value); // mov [basep + 1*ecx],srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_imm(&dst, MBISD(basereg, indreg, 2, baseoffs), srcp.value);// mov [basep + 2*ecx],srcp + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 4, baseoffs), srcp.value);// mov [basep + 4*ecx],srcp + else if (sizep.value == DRCUML_SIZE_QWORD) + { + if (short_immediate(srcp.value)) + emit_mov_m64_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value);// mov [basep + 8*indp],srcp + else + { + emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value);// mov [basep + 8*ecx],srcp + emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 8, baseoffs + 4), srcp.value >> 32); + // mov [basep + 8*ecx + 4],srcp >> 32 + } + } } - } - /* normal case: variable index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m16_imm(&dst, MBISD(basereg, indreg, 2, baseoffs), srcp.value); // mov [basep + 2*ecx],srcp + /* variable source */ else { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m16_r16(&dst, MBISD(basereg, indreg, 2, baseoffs), srcreg); // mov [basep + 2*ecx],srcreg + if (sizep.value != DRCUML_SIZE_QWORD) + emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov edx:srcreg,srcp + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_r8(&dst, MBISD(basereg, indreg, 1, baseoffs), srcreg); // mov [basep + 1*ecx],srcreg + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_r16(&dst, MBISD(basereg, indreg, 2, baseoffs), srcreg); // mov [basep + 2*ecx],srcreg + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_r32(&dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // mov [basep + 4*ecx],srcreg + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_m64_r64(&dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // mov [basep + 8*ecx],srcreg } } return dst; @@ -4131,137 +4000,57 @@ static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_store4 - process a STORE4 opcode + op_read - process a READ opcode -------------------------------------------------*/ -static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter srcp, basep, indp; - int basereg, srcreg; - INT32 baseoffs; + drcuml_parameter dstp, addrp, spacesizep; + int dstreg; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &spacesizep, PTYPE_I); - /* pick a source register for the general case */ - srcreg = param_select_register(REG_EAX, &srcp, NULL); - - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); + /* pick a target register for the general case */ + dstreg = param_select_register(REG_EAX, &dstp, NULL); - /* degenerate case: constant index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) + /* set up a call to the read byte handler */ + emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp + if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) { - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m32_imm(&dst, MBD(basereg, baseoffs + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m32_r32(&dst, MBD(basereg, baseoffs + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg - } + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_byte); + // call read_byte + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al } - - /* normal case: variable index */ - else + else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m32_imm(&dst, MBISD(basereg, indreg, 4, baseoffs), srcp.value); // mov [basep + 4*ecx],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m32_r32(&dst, MBISD(basereg, indreg, 4, baseoffs), srcreg); // mov [basep + 4*ecx],srcreg - } + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_word); + // call read_word + emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax } - return dst; -} - - -/*------------------------------------------------- - op_store8 - process a STORE8 opcode --------------------------------------------------*/ - -static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; - int basereg, srcreg; - INT32 baseoffs; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* pick a source register for the general case */ - srcreg = param_select_register(REG_EAX, &srcp, NULL); - - /* determine the pointer base */ - basereg = get_base_register_and_offset(drcbe, &dst, basep.value, REG_RDX, &baseoffs); - - /* degenerate case: constant index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) { - if (srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value)) - emit_mov_m64_imm(&dst, MBD(basereg, baseoffs + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp - else - { - emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m64_r64(&dst, MBD(basereg, baseoffs + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg - } + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_dword); + // call read_dword + if (dstreg != REG_EAX || inst->size == 8) + emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax } - - /* normal case: variable index */ - else + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE && short_immediate(srcp.value)) - emit_mov_m64_imm(&dst, MBISD(basereg, indreg, 8, baseoffs), srcp.value); // mov [basep + 8*ecx],srcp - else - { - emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m64_r64(&dst, MBISD(basereg, indreg, 8, baseoffs), srcreg); // mov [basep + 8*ecx],srcreg - } + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_qword); + // call read_qword + if (dstreg != REG_RAX) + emit_mov_r64_r64(&dst, dstreg, REG_RAX); // mov dstreg,rax } - return dst; -} - - -/*------------------------------------------------- - op_read1u - process a READ1U opcode --------------------------------------------------*/ - -static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read byte handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_byte);// call read_byte - emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al - /* store to appropriate target size */ + /* store result */ if (inst->size == 4) emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - else if (inst->size == 8) + else emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg return dst; @@ -4269,12 +4058,12 @@ static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_read1s - process a READ1S opcode + op_readm - process a READM opcode -------------------------------------------------*/ -static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, spacep, addrp; + drcuml_parameter dstp, addrp, maskp, spacesizep; int dstreg; /* validate instruction */ @@ -4282,139 +4071,42 @@ static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); /* set up a call to the read byte handler */ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_byte);// call read_byte - - /* 32-bit form */ - if (inst->size == 4) - { - /* general case */ - emit_movsx_r32_r8(&dst, dstreg, REG_AL); // movsx dstreg,al - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) + emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp else + emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp + if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) { - /* general case */ - emit_movsx_r64_r8(&dst, dstreg, REG_AL); // movsx dstreg,al - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_word_masked); + // call read_word_masked + emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax } - return dst; -} - - -/*------------------------------------------------- - op_read2u - process a READ2U opcode --------------------------------------------------*/ - -static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read word handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word);// call read_word - emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax - - /* store to appropriate target size */ - if (inst->size == 4) - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_read2s - process a READ2S opcode --------------------------------------------------*/ - -static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read word handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word);// call read_word - - /* 32-bit form */ - if (inst->size == 4) + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) { - /* general case */ - emit_movsx_r32_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_dword_masked); + // call read_dword_masked + if (dstreg != REG_EAX || inst->size == 8) + emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax } - - /* 64-bit form */ - else + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) { - /* general case */ - emit_movsx_r64_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].read_qword_masked); + // call read_qword_masked + if (dstreg != REG_RAX) + emit_mov_r64_r64(&dst, dstreg, REG_RAX); // mov dstreg,rax } - return dst; -} - -/*------------------------------------------------- - op_read2m - process a READ2M opcode --------------------------------------------------*/ - -static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp, maskp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read dword masked handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param1,maskp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_word_masked);// call read_word_masked - emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax - - /* store to appropriate target size */ + /* store result */ if (inst->size == 4) emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - else if (inst->size == 8) + else emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg return dst; @@ -4422,410 +4114,87 @@ static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_read4u - process a READ4U opcode --------------------------------------------------*/ - -static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* set up a call to the read dword handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword - - /* store to appropriate target size */ - if (inst->size == 4) - emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax - - return dst; -} - - -/*------------------------------------------------- - op_read4s - process a READ4S opcode --------------------------------------------------*/ - -static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read dword handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword);// call read_dword - - /* 64-bit form */ - emit_movsxd_r64_r32(&dst, dstreg, REG_EAX); // movsxd dstreg,eax - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_read4m - process a READ4M opcode + op_write - process a WRITE opcode -------------------------------------------------*/ -static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, spacep, addrp, maskp; + drcuml_parameter addrp, srcp, spacesizep; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); - - /* set up a call to the read dword masked handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_dword_masked);// call read_dword_masked - - /* store to appropriate target size */ - if (inst->size == 4) - emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax - - return dst; -} - - -/*------------------------------------------------- - op_read8u - process a READ8U opcode --------------------------------------------------*/ - -static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* set up a call to the read qword handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword);// call read_qword - - /* 64-bit form */ - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax - - return dst; -} - - -/*------------------------------------------------- - op_read8m - process a READ8M opcode --------------------------------------------------*/ - -static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp, maskp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); - - /* set up a call to the read qword masked handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &maskp); // mov param2,maskp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].read_qword_masked);// call read_qword_masked - - /* 64-bit form */ - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax - - return dst; -} - - -/*------------------------------------------------- - op_write1 - process a WRITE1 opcode --------------------------------------------------*/ - -static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &spacesizep, PTYPE_I); /* set up a call to the write byte handler */ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_byte);// call write_byte - - return dst; -} - - -/*------------------------------------------------- - op_write2 - process a WRITE2 opcode --------------------------------------------------*/ - -static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_word);// call write_word - - return dst; -} - - -/*------------------------------------------------- - op_writ2m - process a WRIT2M opcode --------------------------------------------------*/ - -static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, maskp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_word_masked);// call write_word_masked - return dst; -} - - -/*------------------------------------------------- - op_write4 - process a WRITE4 opcode --------------------------------------------------*/ - -static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write dword handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword);// call write_dword - + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) + emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param1,srcp + else + emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param1,srcp + if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_byte); + // call write_byte + else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_word); + // call write_word + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_dword); + // call write_dword + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) + emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacesizep.value / 16].write_qword); + // call write_qword return dst; } /*------------------------------------------------- - op_writ4m - process a WRIT4M opcode + op_writem - process a WRITEM opcode -------------------------------------------------*/ -static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter spacep, addrp, maskp, srcp; + drcuml_parameter addrp, srcp, maskp, spacesizep; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_dword_masked);// call write_dword_masked - return dst; -} - - -/*------------------------------------------------- - op_write8 - process a WRITE8 opcode --------------------------------------------------*/ - -static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write qword handler */ - emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword);// call write_qword - - return dst; -} - - -/*------------------------------------------------- - op_writ8m - process a WRIT8M opcode --------------------------------------------------*/ - -static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, maskp, srcp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); + param_normalize_4(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); - /* set up a call to the write word handler */ + /* set up a call to the write byte handler */ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp - emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp - emit_mov_r64_p64(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp - emit_smart_call_m64(drcbe, &dst, (x86code **)&drcbe->accessors[spacep.value].write_qword_masked);// call write_qword_masked - return dst; -} - - -/*------------------------------------------------- - op_flags - process a FLAGS opcode --------------------------------------------------*/ - -static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, maskp, tablep; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &maskp, PTYPE_I, &tablep, PTYPE_M); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_ECX, &dstp, NULL); - - /* translate live flags into UML flags */ - emit_pushf(&dst); // pushf - emit_pop_r64(&dst, REG_RAX); // pop rax - emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 - emit_movzx_r32_m8(&dst, REG_EAX, MBISD(REG_RBP, REG_RAX, 1, offset_from_rbp(drcbe, (FPTR)&drcbe->flagsmap[0]))); - // movzx eax,[flags_map] - - /* 32-bit form */ - if (inst->size == 4) + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) { - /* no masking */ - if (maskp.value == 0xffffffff) - { - emit_mov_r32_m32(&dst, dstreg, MBISD(REG_RBP, REG_EAX, 4, offset_from_rbp(drcbe, tablep.value))); - // mov dstreg,[eax*4+table] - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* general case */ - else - { - emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp - emit_mov_r32_m32(&dst, REG_EDX, MBISD(REG_RBP, REG_EAX, 4, offset_from_rbp(drcbe, tablep.value))); - // mov edx,[eax*4+table] - emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask - emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask - emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } + emit_mov_r32_p32(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp + emit_mov_r32_p32(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp } - - /* 64-bit form */ else { - /* no masking */ - if (maskp.value == U64(0xffffffffffffffff)) - { - emit_mov_r64_m64(&dst, dstreg, MBISD(REG_RBP, REG_EAX, 8, offset_from_rbp(drcbe, tablep.value))); - // mov dstreg,[eax*8+table] - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* general case */ - else - { - emit_mov_r64_p64(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp - emit_mov_r64_m64(&dst, REG_EDX, MBISD(REG_RBP, REG_EAX, 8, offset_from_rbp(drcbe, tablep.value))); - // mov edx,[eax*84+table] - if (short_immediate(~maskp.value)) - emit_and_r64_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask - else - { - emit_mov_r64_imm(&dst, REG_R11, ~maskp.value); // mov r11,~mask - emit_and_r64_r64(&dst, dstreg, REG_R11); // and dstreg,r11 - } - if (short_immediate(maskp.value)) - emit_and_r64_imm(&dst, REG_EDX, maskp.value); // and edx,mask - else - { - emit_mov_r64_imm(&dst, REG_R11, maskp.value); // mov r11,mask - emit_and_r64_r64(&dst, REG_EDX, REG_R11); // and edx,r11 - } - emit_or_r64_r64(&dst, dstreg, REG_EDX); // or dstreg,edx - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - } + emit_mov_r64_p64(drcbe, &dst, REG_PARAM2, &srcp); // mov param2,srcp + emit_mov_r64_p64(drcbe, &dst, REG_PARAM3, &maskp); // mov param3,maskp + } + if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) + emit_call(&dst, (x86code *)drcbe->accessors[spacesizep.value / 16].write_word_masked); + // call write_word_masked + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) + emit_call(&dst, (x86code *)drcbe->accessors[spacesizep.value / 16].write_dword_masked); + // call write_dword_masked + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) + emit_call(&dst, (x86code *)drcbe->accessors[spacesizep.value / 16].write_qword_masked); + // call write_qword_masked return dst; } /*------------------------------------------------- - op_setc - process a SETC opcode + op_carry - process a CARRY opcode -------------------------------------------------*/ -static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter srcp, bitp; @@ -4895,6 +4264,41 @@ static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instructi /*------------------------------------------------- + op_set - process a SET opcode +-------------------------------------------------*/ + +static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +{ + drcuml_parameter dstp; + int dstreg; + + /* validate instruction */ + assert(inst->size == 4 || inst->size == 8); + assert(inst->condflags >= DRCUML_COND_Z && inst->condflags < DRCUML_COND_MAX); + + /* normalize parameters */ + param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); + + /* pick a target register for the general case */ + dstreg = param_select_register(REG_EAX, &dstp, NULL); + + /* set to AL */ + emit_setcc_r8(&dst, X86_CONDITION(inst->condflags), REG_AL); // setcc al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + + /* 32-bit form */ + if (inst->size == 4) + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + + /* 64-bit form */ + else if (inst->size == 8) + emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + + return dst; +} + + +/*------------------------------------------------- op_mov - process a MOV opcode -------------------------------------------------*/ @@ -5012,12 +4416,12 @@ static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instructio /*------------------------------------------------- - op_zext1 - process a ZEXT1 opcode + op_sext - process a SEXT opcode -------------------------------------------------*/ -static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep; int dstreg; /* validate instruction */ @@ -5025,183 +4429,19 @@ static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruct assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI, &sizep, PTYPE_I); /* degenerate cases -- convert to a move */ if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT8)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movzx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movzx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp - - /* 32-bit form */ - if (inst->size == 4) - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - /* 64-bit form */ - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_zext2 - process a ZEXT2 opcode --------------------------------------------------*/ - -static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT16)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movzx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movzx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp - - /* 32-bit form */ - if (inst->size == 4) - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - /* 64-bit form */ - else if (inst->size == 8) - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_zext4 - process a ZEXT4 opcode --------------------------------------------------*/ - -static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_mov_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_sext1 - process a SEXT1 opcode --------------------------------------------------*/ - -static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* convert 8-bit source registers */ - if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) - { - emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp - srcp.value = REG_EAX; - } - - /* 32-bit form */ - if (inst->size == 4) { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + if (sizep.value == DRCUML_SIZE_BYTE) + return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); + else if (sizep.value == DRCUML_SIZE_WORD) + return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); + else if (sizep.value == DRCUML_SIZE_DWORD) + return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); } - /* 64-bit form */ - else if (inst->size == 8) - { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r64_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r64_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - return dst; -} - - -/*------------------------------------------------- - op_sext2 - process a SEXT2 opcode --------------------------------------------------*/ - -static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); - /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); @@ -5210,9 +4450,23 @@ static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruct { /* general case */ if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp] + } else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp + } emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg } @@ -5221,46 +4475,27 @@ static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruct { /* general case */ if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r64_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r64_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - return dst; -} - - -/*------------------------------------------------- - op_sext4 - process a SEXT4 opcode --------------------------------------------------*/ - -static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* 64-bit form */ - if (inst->size == 8) - { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsxd_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // movsxd dstreg,[srcp] + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r64_m8(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r64_m16(&dst, dstreg, MABS(drcbe, srcp.value)); // movsx dstreg,[srcp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_movsxd_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // movsxd dstreg,[srcp] + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // mov dstreg,[srcp] + } else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsxd_r64_r32(&dst, dstreg, srcp.value); // movsxd dstreg,srcp + { + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r64_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r64_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_movsxd_r64_r32(&dst, dstreg, srcp.value); // movsxd dstreg,srcp + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_mov_r64_r64(&dst, dstreg, srcp.value); // mov dstreg,srcp + } emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg } return dst; @@ -5268,10 +4503,10 @@ static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruct /*------------------------------------------------- - op_xtract - process an XTRACT opcode + op_roland - process an ROLAND opcode -------------------------------------------------*/ -static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter dstp, srcp, shiftp, maskp; int dstreg; @@ -5333,10 +4568,10 @@ static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_insert - process an INSERT opcode + op_rolins - process an ROLINS opcode -------------------------------------------------*/ -static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter dstp, srcp, shiftp, maskp; int dstreg; @@ -5753,6 +4988,27 @@ static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax if (compute_hi) emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx + + /* compute flags */ + if (inst->condflags != 0) + { + if (compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax + } } /* 64-bit form */ @@ -5772,6 +5028,27 @@ static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax if (compute_hi) emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx + + /* compute flags */ + if (inst->condflags != 0) + { + if (compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r64_r64(&dst, REG_RDX, REG_RDX); // test rdx,rdx + else + { + emit_mov_r32_r32(&dst, REG_ECX, REG_EAX); // mov ecx,eax + emit_shr_r64_imm(&dst, REG_RAX, 32); // shr rax,32 + emit_or_r64_r64(&dst, REG_RDX, REG_RCX); // or rdx,rcx + emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax + } + } + else + emit_test_r64_r64(&dst, REG_RAX, REG_RAX); // test rax,rax + } } return dst; } @@ -5850,6 +5127,27 @@ static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx } + + /* compute flags */ + if (inst->condflags != 0) + { + if (compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax + } } /* 64-bit form */ @@ -5892,6 +5190,27 @@ static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_p64_r64(drcbe, &dst, &dstp, REG_RAX); // mov dstp,rax emit_mov_p64_r64(drcbe, &dst, &edstp, REG_RDX); // mov edstp,rdx } + + /* compute flags */ + if (inst->condflags != 0) + { + if (compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r64_r64(&dst, REG_RDX, REG_RDX); // test rdx,rdx + else + { + emit_mov_r32_r32(&dst, REG_ECX, REG_EAX); // mov ecx,eax + emit_shr_r64_imm(&dst, REG_RAX, 32); // shr rax,32 + emit_or_r64_r64(&dst, REG_RDX, REG_RCX); // or rdx,rcx + emit_or_r64_r64(&dst, REG_RDX, REG_RAX); // or rdx,rax + } + } + else + emit_test_r64_r64(&dst, REG_RAX, REG_RAX); // test rax,rax + } } return dst; } @@ -6945,7 +6264,7 @@ static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruct assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &spacep, PTYPE_I, &addrp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &addrp, PTYPE_MRI, &spacep, PTYPE_I); /* set up a call to the read dword/qword handler */ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp @@ -6986,7 +6305,7 @@ static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MF); + param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MF, &spacep, PTYPE_I); /* general case */ emit_mov_r32_p32(drcbe, &dst, REG_PARAM1, &addrp); // mov param1,addrp @@ -7061,12 +6380,12 @@ static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instructi /*------------------------------------------------- - op_ftoi4 - process a FTOI4 opcode + op_ftoint - process a FTOINT opcode -------------------------------------------------*/ -static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep, roundp; int dstreg; /* validate instruction */ @@ -7074,213 +6393,123 @@ static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruct assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF, &sizep, PTYPE_I, &roundp, PTYPE_I); /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); - /* 32-bit form */ - if (inst->size == 4) + /* set rounding mode if necessary */ + if (roundp.value != DRCUML_FMOD_DEFAULT && roundp.value != DRCUML_FMOD_TRUNC) { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp - } - - /* 64-bit form */ - else if (inst->size == 8) - { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp + emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave] + emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[roundp.value])); // ldmxcsr fpcontrol[mode] } - - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - return dst; -} - - -/*------------------------------------------------- - op_ftoi4t - process a FTOI4T opcode --------------------------------------------------*/ - -static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - + /* 32-bit form */ if (inst->size == 4) { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvttss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvttss2si_r32_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp + /* 32-bit integer source */ + if (sizep.value == DRCUML_SIZE_DWORD) + { + if (srcp.type == DRCUML_PTYPE_MEMORY) + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] + else + emit_cvttss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] + } + else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp + else + emit_cvttss2si_r32_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp + } + } + + /* 64-bit integer source */ + else if (sizep.value == DRCUML_SIZE_QWORD) + { + if (srcp.type == DRCUML_PTYPE_MEMORY) + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] + else + emit_cvttss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] + } + else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp + else + emit_cvttss2si_r64_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp + } + } } /* 64-bit form */ else if (inst->size == 8) { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvttsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvttsd2si_r32_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp - } - - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - return dst; -} - - -/*------------------------------------------------- - op_ftoi4x - process a FTOI4R/F/C opcode --------------------------------------------------*/ - -static x86code *op_ftoi4x(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, int mode) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* non-SSE4.1 case */ - if (!drcbe->sse41 || inst->size == 8) - { - /* save and set the control word */ - emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave] - emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[mode])); // ldmxcsr fpcontrol[mode] - - /* 32-bit form */ - if (inst->size == 4) + /* 32-bit integer source */ + if (sizep.value == DRCUML_SIZE_DWORD) { if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtss2si_r32_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] + else + emit_cvttsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] + } else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtss2si_r32_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp + else + emit_cvttsd2si_r32_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp + } } - - /* 64-bit form */ - else if (inst->size == 8) + + /* 64-bit integer source */ + else if (sizep.value == DRCUML_SIZE_QWORD) { if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsd2si_r32_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] + else + emit_cvttsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] + } else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtsd2si_r32_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp + { + if (roundp.value != DRCUML_FMOD_TRUNC) + emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp + else + emit_cvttsd2si_r64_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp + } } - - /* restore control word and proceed */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave] } - /* SSE4.1 case */ + /* general case */ + if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg else - { - /* 32-bit form */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_roundss_r128_m32_imm(&dst, REG_XMM0, MABS(drcbe, srcp.value), fprnd_map[mode]); - // roundss xmm0,[srcp],mode - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_roundss_r128_r128_imm(&dst, REG_XMM0, srcp.value, fprnd_map[mode]); // roundss xmm0,srcp,mode - - /* store to the destination */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_movd_m32_r128(&dst, MABS(drcbe, dstp.value), REG_XMM0); // movd [dstp],xmm0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movd_r32_r128(&dst, dstp.value, REG_XMM0); // movd dstp,xmm0 - } - return dst; - -} - -static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - return op_ftoi4x(drcbe, dst, inst, DRCUML_FMOD_ROUND); -} - -static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - return op_ftoi4x(drcbe, dst, inst, DRCUML_FMOD_FLOOR); -} - -static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - return op_ftoi4x(drcbe, dst, inst, DRCUML_FMOD_CEIL); -} - - -/*------------------------------------------------- - op_ftoi8 - process a FTOI8 opcode --------------------------------------------------*/ - -static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* 32-bit form */ - if (inst->size == 4) - { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp - } + emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - /* 64-bit form */ - else if (inst->size == 8) - { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp - } + /* restore rounding mode */ + if (roundp.value != DRCUML_FMOD_DEFAULT && roundp.value != DRCUML_FMOD_TRUNC) + emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave] - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg return dst; } /*------------------------------------------------- - op_ftoi8t - process a FTOI8T opcode + op_ffrint - process a FFRINT opcode -------------------------------------------------*/ -static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep; int dstreg; /* validate instruction */ @@ -7288,187 +6517,83 @@ static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI, &sizep, PTYPE_I); /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); + dstreg = param_select_register(REG_XMM0, &dstp, NULL); /* 32-bit form */ if (inst->size == 4) { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvttss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttss2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvttss2si_r64_r128(&dst, dstreg, srcp.value); // cvttss2si dstreg,srcp + /* 32-bit integer source */ + if (sizep.value == DRCUML_SIZE_DWORD) + { + if (srcp.type == DRCUML_PTYPE_MEMORY) + emit_cvtsi2ss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] + else + { + int srcreg = param_select_register(REG_EAX, &srcp, NULL); + emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + emit_cvtsi2ss_r128_r32(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg + } + } + + /* 64-bit integer source */ + else + { + if (srcp.type == DRCUML_PTYPE_MEMORY) + emit_cvtsi2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] + else + { + int srcreg = param_select_register(REG_RAX, &srcp, NULL); + emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + emit_cvtsi2ss_r128_r64(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg + } + } + emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg } /* 64-bit form */ else if (inst->size == 8) { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvttsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvttsd2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvttsd2si_r64_r128(&dst, dstreg, srcp.value); // cvttsd2si dstreg,srcp - } - - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - return dst; -} - - -/*------------------------------------------------- - op_ftoi8x - process a FTOI8R/F/C opcode --------------------------------------------------*/ - -static x86code *op_ftoi8x(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst, int mode) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* non-SSE4.1 case */ - if (!drcbe->sse41 || inst->size == 4) - { - /* save and set the control word */ - emit_stmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // stmxcsr [ssemodesave] - emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssecontrol[mode])); // ldmxcsr fpcontrol[mode] - - /* 32-bit form */ - if (inst->size == 4) + /* 32-bit integer source */ + if (sizep.value == DRCUML_SIZE_DWORD) { if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtss2si_r64_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtss2si_r64_r128(&dst, dstreg, srcp.value); // cvtss2si dstreg,srcp + emit_cvtsi2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] + else + { + int srcreg = param_select_register(REG_EAX, &srcp, NULL); + emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + emit_cvtsi2sd_r128_r32(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg + } } - - /* 64-bit form */ - else if (inst->size == 8) + + /* 64-bit integer source */ + else { if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsd2si_r64_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2si dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtsd2si_r64_r128(&dst, dstreg, srcp.value); // cvtsd2si dstreg,srcp + emit_cvtsi2sd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] + else + { + int srcreg = param_select_register(REG_EAX, &srcp, NULL); + emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + emit_cvtsi2sd_r128_r64(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg + } } - - /* restore control word and proceed */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - emit_ldmxcsr_m32(&dst, MABS(drcbe, &drcbe->ssemodesave)); // ldmxcsr [ssemodesave] - } - - /* SSE4.1 case */ - else - { - /* 64-bit form */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_roundsd_r128_m64_imm(&dst, REG_XMM0, MABS(drcbe, srcp.value), fprnd_map[mode]); - // roundsd xmm0,[srcp],mode - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_roundsd_r128_r128_imm(&dst, REG_XMM0, srcp.value, fprnd_map[mode]); // roundsd xmm0,srcp,mode - - /* store to the destination */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_movq_m64_r128(&dst, MABS(drcbe, dstp.value), REG_XMM0); // movq [dstp],xmm0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movq_r64_r128(&dst, dstp.value, REG_XMM0); // movq dstp,xmm0 + emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg } return dst; - -} - -static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - return op_ftoi8x(drcbe, dst, inst, DRCUML_FMOD_ROUND); -} - -static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - return op_ftoi8x(drcbe, dst, inst, DRCUML_FMOD_FLOOR); -} - -static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - return op_ftoi8x(drcbe, dst, inst, DRCUML_FMOD_CEIL); } /*------------------------------------------------- - op_ffrfs - process a FFRFS opcode + op_ffrflt - process a FFRFLT opcode -------------------------------------------------*/ -static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_XMM0, &dstp, NULL); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtss2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2sd dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtss2sd_r128_r128(&dst, dstreg, srcp.value); // cvtss2sd dstreg,srcp - emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_ffrfd - process a FFRFD opcode --------------------------------------------------*/ - -static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_XMM0, &dstp, NULL); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) - emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp - emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg - - return dst; -} - - -/*------------------------------------------------- - op_ffri4 - process a FFRI4 opcode --------------------------------------------------*/ - -static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep; int dstreg; /* validate instruction */ @@ -7476,53 +6601,45 @@ static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruct assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF, &sizep, PTYPE_I); /* pick a target register for the general case */ dstreg = param_select_register(REG_XMM0, &dstp, NULL); - /* 32-bit form */ - if (inst->size == 4) + /* single-to-double */ + if (inst->size == 8 && sizep.value == DRCUML_SIZE_DWORD) { if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsi2ss_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] - else - { - int srcreg = param_select_register(REG_EAX, &srcp, NULL); - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_cvtsi2ss_r128_r32(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg - } - emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg + emit_cvtss2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtss2sd dstreg,[srcp] + else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) + emit_cvtss2sd_r128_r128(&dst, dstreg, srcp.value); // cvtss2sd dstreg,srcp + emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg } - - /* 64-bit form */ - else if (inst->size == 8) + + /* double-to-single */ + else if (inst->size == 4 && sizep.value == DRCUML_SIZE_QWORD) { if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsi2sd_r128_m32(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] - else - { - int srcreg = param_select_register(REG_EAX, &srcp, NULL); - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_cvtsi2sd_r128_r32(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg - } - emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg + emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp] + else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) + emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp + emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg } return dst; } /*------------------------------------------------- - op_ffri8 - process a FFRI8 opcode + op_frnds - process a FRNDS opcode -------------------------------------------------*/ -static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter dstp, srcp; int dstreg; /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); + assert(inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ @@ -7531,33 +6648,13 @@ static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruct /* pick a target register for the general case */ dstreg = param_select_register(REG_XMM0, &dstp, NULL); - /* 32-bit form */ - if (inst->size == 4) - { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsi2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2ss dstreg,[srcp] - else - { - int srcreg = param_select_register(REG_EAX, &srcp, NULL); - emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_cvtsi2ss_r128_r64(&dst, dstreg, srcreg); // cvtsi2ss dstreg,srcreg - } - emit_movss_p32_r128(drcbe, &dst, &dstp, dstreg); // movss dstp,dstreg - } - /* 64-bit form */ - else if (inst->size == 8) - { - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_cvtsi2sd_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsi2sd dstreg,[srcp] - else - { - int srcreg = param_select_register(REG_EAX, &srcp, NULL); - emit_mov_r64_p64(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_cvtsi2sd_r128_r64(&dst, dstreg, srcreg); // cvtsi2sd dstreg,srcreg - } - emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg - } + if (srcp.type == DRCUML_PTYPE_MEMORY) + emit_cvtsd2ss_r128_m64(&dst, dstreg, MABS(drcbe, srcp.value)); // cvtsd2ss dstreg,[srcp] + else if (srcp.type == DRCUML_PTYPE_FLOAT_REGISTER) + emit_cvtsd2ss_r128_r128(&dst, dstreg, srcp.value); // cvtsd2ss dstreg,srcp + emit_cvtss2sd_r128_r128(&dst, dstreg, dstreg); // cvtss2sd dstreg,dstreg + emit_movsd_p64_r128(drcbe, &dst, &dstp, dstreg); // movsd dstp,dstreg return dst; } diff --git a/src/emu/cpu/drcbex86.c b/src/emu/cpu/drcbex86.c index ea4e7cc4085..f0bffc6829f 100644 --- a/src/emu/cpu/drcbex86.c +++ b/src/emu/cpu/drcbex86.c @@ -17,6 +17,8 @@ - also FCMP/FLAGS has unnecessary PUSHF/POP EAX * Identify common pairs and optimize output + + * Convert AND 0xff/0xffff to movzx **************************************************************************** @@ -282,48 +284,23 @@ static x86code *op_recover(drcbe_state *drcbe, x86code *dst, const drcuml_instru static x86code *op_setfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_getfmod(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_save(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_add(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_addc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_sub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); @@ -352,20 +329,10 @@ static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruc static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); -static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); +static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fadd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fsub(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); static x86code *op_fcmp(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst); @@ -400,50 +367,25 @@ static const opcode_table_entry opcode_table_source[] = /* Internal Register Operations */ { DRCUML_OP_SETFMOD, op_setfmod }, /* SETFMOD src */ { DRCUML_OP_GETFMOD, op_getfmod }, /* GETFMOD dst */ - { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst,index */ - { DRCUML_OP_SAVE, op_save }, /* SAVE dst,index */ - { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst,index */ + { DRCUML_OP_GETEXP, op_getexp }, /* GETEXP dst */ + { DRCUML_OP_GETFLGS, op_getflgs }, /* GETFLGS dst[,f] */ + { DRCUML_OP_SAVE, op_save }, /* SAVE dst */ + { DRCUML_OP_RESTORE, op_restore }, /* RESTORE dst */ /* Integer Operations */ - { DRCUML_OP_LOAD1U, op_load1u }, /* LOAD1U dst,base,index */ - { DRCUML_OP_LOAD1S, op_load1s }, /* LOAD1S dst,base,index */ - { DRCUML_OP_LOAD2U, op_load2u }, /* LOAD2U dst,base,index */ - { DRCUML_OP_LOAD2S, op_load2s }, /* LOAD2S dst,base,index */ - { DRCUML_OP_LOAD4U, op_load4u }, /* LOAD4U dst,base,index */ - { DRCUML_OP_LOAD4S, op_load4s }, /* LOAD4S dst,base,index */ - { DRCUML_OP_LOAD8U, op_load8u }, /* LOAD8U dst,base,index */ - { DRCUML_OP_STORE1, op_store1 }, /* STORE1 base,index,src */ - { DRCUML_OP_STORE2, op_store2 }, /* STORE2 base,index,src */ - { DRCUML_OP_STORE4, op_store4 }, /* STORE4 base,index,src */ - { DRCUML_OP_STORE8, op_store8 }, /* STORE8 base,index,src */ - { DRCUML_OP_READ1U, op_read1u }, /* READ1U dst,space,src1 */ - { DRCUML_OP_READ1S, op_read1s }, /* READ1S dst,space,src1 */ - { DRCUML_OP_READ2U, op_read2u }, /* READ2U dst,space,src1 */ - { DRCUML_OP_READ2S, op_read2s }, /* READ2S dst,space,src1 */ - { DRCUML_OP_READ2M, op_read2m }, /* READ2M dst,space,src1,mask */ - { DRCUML_OP_READ4U, op_read4u }, /* READ4U dst,space,src1 */ - { DRCUML_OP_READ4S, op_read4s }, /* READ4S dst,space,src1 */ - { DRCUML_OP_READ4M, op_read4m }, /* READ4M dst,space,src1,mask */ - { DRCUML_OP_READ8U, op_read8u }, /* READ8U dst,space,src1 */ - { DRCUML_OP_READ8M, op_read8m }, /* READ8M dst,space,src1,mask */ - { DRCUML_OP_WRITE1, op_write1 }, /* WRITE1 space,dst,src1 */ - { DRCUML_OP_WRITE2, op_write2 }, /* WRITE2 space,dst,src1 */ - { DRCUML_OP_WRIT2M, op_writ2m }, /* WRIT2M space,dst,src1 */ - { DRCUML_OP_WRITE4, op_write4 }, /* WRITE4 space,dst,src1 */ - { DRCUML_OP_WRIT4M, op_writ4m }, /* WRIT4M space,dst,mask,src1 */ - { DRCUML_OP_WRITE8, op_write8 }, /* WRITE8 space,dst,src1 */ - { DRCUML_OP_WRIT8M, op_writ8m }, /* WRIT8M space,dst,mask,src1 */ - { DRCUML_OP_FLAGS, op_flags }, /* FLAGS dst,mask,table */ - { DRCUML_OP_SETC, op_setc }, /* FLAGS src,bitnum */ + { DRCUML_OP_LOAD, op_load }, /* LOAD dst,base,index,size */ + { DRCUML_OP_LOADS, op_loads }, /* LOADS dst,base,index,size */ + { DRCUML_OP_STORE, op_store }, /* STORE base,index,src,size */ + { DRCUML_OP_READ, op_read }, /* READ dst,src1,spacesize */ + { DRCUML_OP_READM, op_readm }, /* READM dst,src1,mask,spacesize */ + { DRCUML_OP_WRITE, op_write }, /* WRITE dst,src1,spacesize */ + { DRCUML_OP_WRITEM, op_writem }, /* WRITEM dst,src1,spacesize */ + { DRCUML_OP_CARRY, op_carry }, /* CARRY src,bitnum */ + { DRCUML_OP_SET, op_set }, /* SET dst,c */ { DRCUML_OP_MOV, op_mov }, /* MOV dst,src[,c] */ - { DRCUML_OP_ZEXT1, op_zext1 }, /* ZEXT1 dst,src */ - { DRCUML_OP_ZEXT2, op_zext2 }, /* ZEXT2 dst,src */ - { DRCUML_OP_ZEXT4, op_zext4 }, /* ZEXT4 dst,src */ - { DRCUML_OP_SEXT1, op_sext1 }, /* SEXT1 dst,src */ - { DRCUML_OP_SEXT2, op_sext2 }, /* SEXT2 dst,src */ - { DRCUML_OP_SEXT4, op_sext4 }, /* SEXT4 dst,src */ - { DRCUML_OP_XTRACT, op_xtract }, /* XTRACT dst,src1,src2,src3 */ - { DRCUML_OP_INSERT, op_insert }, /* INSERT dst,src1,src2,src3 */ + { DRCUML_OP_SEXT, op_sext }, /* SEXT dst,src */ + { DRCUML_OP_ROLAND, op_roland }, /* ROLAND dst,src1,src2,src3 */ + { DRCUML_OP_ROLINS, op_rolins }, /* ROLINS dst,src1,src2,src3 */ { DRCUML_OP_ADD, op_add }, /* ADD dst,src1,src2[,f] */ { DRCUML_OP_ADDC, op_addc }, /* ADDC dst,src1,src2[,f] */ { DRCUML_OP_SUB, op_sub }, /* SUB dst,src1,src2[,f] */ @@ -470,23 +412,13 @@ static const opcode_table_entry opcode_table_source[] = /* Floating Point Operations */ { DRCUML_OP_FLOAD, op_fload }, /* FLOAD dst,base,index */ { DRCUML_OP_FSTORE, op_fstore }, /* FSTORE base,index,src */ - { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,space,src1 */ - { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE space,dst,src1 */ + { DRCUML_OP_FREAD, op_fread }, /* FREAD dst,src1,space */ + { DRCUML_OP_FWRITE, op_fwrite }, /* FWRITE dst,src1,space */ { DRCUML_OP_FMOV, op_fmov }, /* FMOV dst,src1[,c] */ - { DRCUML_OP_FTOI4, op_ftoi4 }, /* FTOI4 dst,src1 */ - { DRCUML_OP_FTOI4T, op_ftoi4t }, /* FTOI4T dst,src1 */ - { DRCUML_OP_FTOI4R, op_ftoi4r }, /* FTOI4R dst,src1 */ - { DRCUML_OP_FTOI4F, op_ftoi4f }, /* FTOI4F dst,src1 */ - { DRCUML_OP_FTOI4C, op_ftoi4c }, /* FTOI4C dst,src1 */ - { DRCUML_OP_FTOI8, op_ftoi8 }, /* FTOI8 dst,src1 */ - { DRCUML_OP_FTOI8T, op_ftoi8t }, /* FTOI8T dst,src1 */ - { DRCUML_OP_FTOI8R, op_ftoi8r }, /* FTOI8R dst,src1 */ - { DRCUML_OP_FTOI8F, op_ftoi8f }, /* FTOI8F dst,src1 */ - { DRCUML_OP_FTOI8C, op_ftoi8c }, /* FTOI8C dst,src1 */ - { DRCUML_OP_FFRFS, op_ffrfs }, /* FFRFS dst,src1 */ - { DRCUML_OP_FFRFD, op_ffrfd }, /* FFRFD dst,src1 */ - { DRCUML_OP_FFRI4, op_ffri4 }, /* FFRI4 dst,src1 */ - { DRCUML_OP_FFRI8, op_ffri8 }, /* FFRI8 dst,src1 */ + { DRCUML_OP_FTOINT, op_ftoint }, /* FTOINT dst,src1,size,round */ + { DRCUML_OP_FFRINT, op_ffrint }, /* FFRINT dst,src1,size */ + { DRCUML_OP_FFRFLT, op_ffrflt }, /* FFRFLT dst,src1,size */ + { DRCUML_OP_FRNDS, op_frnds }, /* FRNDS dst,src1 */ { DRCUML_OP_FADD, op_fadd }, /* FADD dst,src1,src2 */ { DRCUML_OP_FSUB, op_fsub }, /* FSUB dst,src1,src2 */ { DRCUML_OP_FCMP, op_fcmp }, /* FCMP src1,src2 */ @@ -3603,6 +3535,136 @@ static x86code *op_getexp(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- + op_getflgs - process a GETFLGS opcode +-------------------------------------------------*/ + +static x86code *op_getflgs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +{ + drcuml_parameter dstp; + int dstreg; + + /* validate instruction */ + assert(inst->size == 4); + assert(inst->condflags != DRCUML_COND_ALWAYS); + + /* normalize parameters */ + param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); + + /* pick a target register for the general case */ + dstreg = param_select_register(REG_EAX, &dstp, NULL); + + switch (inst->condflags) + { + /* single flags only */ + case DRCUML_FLAG_C: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + break; + + case DRCUML_FLAG_V: + emit_setcc_r8(&dst, COND_O, REG_AL); // seto al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 + break; + + case DRCUML_FLAG_Z: + emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 + break; + + case DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_S, REG_AL); // sets al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 3); // shl dstreg,3 + break; + + case DRCUML_FLAG_U: + emit_setcc_r8(&dst, COND_P, REG_AL); // setp al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + emit_shl_r32_imm(&dst, dstreg, 4); // shl dstreg,4 + break; + + /* carry plus another flag */ + case DRCUML_FLAG_C | DRCUML_FLAG_V: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_setcc_r8(&dst, COND_O, REG_CL); // seto cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + break; + + case DRCUML_FLAG_C | DRCUML_FLAG_Z: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + break; + + case DRCUML_FLAG_C | DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_C, REG_AL); // setc al + emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 8, 0)); // lea dstreg,[eax+ecx*8] + break; + + /* overflow plus another flag */ + case DRCUML_FLAG_V | DRCUML_FLAG_Z: + emit_setcc_r8(&dst, COND_O, REG_AL); // seto al + emit_setcc_r8(&dst, COND_Z, REG_CL); // setz cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 + break; + + case DRCUML_FLAG_V | DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_O, REG_AL); // seto al + emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 4, 0)); // lea dstreg,[eax+ecx*4] + emit_shl_r32_imm(&dst, dstreg, 1); // shl dstreg,1 + break; + + /* zero plus another flag */ + case DRCUML_FLAG_Z | DRCUML_FLAG_S: + emit_setcc_r8(&dst, COND_Z, REG_AL); // setz al + emit_setcc_r8(&dst, COND_S, REG_CL); // sets cl + emit_movzx_r32_r8(&dst, REG_EAX, REG_AL); // movzx eax,al + emit_movzx_r32_r8(&dst, REG_ECX, REG_CL); // movzx ecx,al + emit_lea_r32_m32(&dst, dstreg, MBISD(REG_EAX, REG_ECX, 2, 0)); // lea dstreg,[eax+ecx*2] + emit_shl_r32_imm(&dst, dstreg, 2); // shl dstreg,2 + break; + + /* default cases */ + default: + emit_pushf(&dst); // pushf + emit_pop_r32(&dst, REG_EAX); // pop eax + emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 + emit_movzx_r32_m8(&dst, dstreg, MBD(REG_EAX, flags_map)); // movzx dstreg,[flags_map] + break; + } + + /* store low 32 bits */ + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + + /* 64-bit form stores upper 32 bits */ + if (inst->size == 8) + { + /* general case */ + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + } + return dst; +} + + +/*------------------------------------------------- op_save - process a SAVE opcode -------------------------------------------------*/ @@ -3726,12 +3788,12 @@ static x86code *op_restore(drcbe_state *drcbe, x86code *dst, const drcuml_instru ***************************************************************************/ /*------------------------------------------------- - op_load1u - process a LOAD1U opcode + op_load - process a LOAD opcode -------------------------------------------------*/ -static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_load(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, basep, indp; + drcuml_parameter dstp, basep, indp, sizep; int dstreg; /* validate instruction */ @@ -3739,117 +3801,43 @@ static x86code *op_load1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); /* immediate index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movzx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movzx dstreg,[basep + 1*indp] - - /* other index */ - else { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movzx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movzx dstreg,[basep + 1*indp] - } - - /* store low 32 bits */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - /* 64-bit form stores upper 32 bits */ - if (inst->size == 8) - { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 - } - return dst; -} - - -/*------------------------------------------------- - op_load1s - process a LOAD1S opcode --------------------------------------------------*/ - -static x86code *op_load1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movsx eax,[basep + 1*indp] - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movsx eax,[basep + 1*indp] - } - - /* 32-bit form */ - if (inst->size == 4) - { - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ - else - { - /* general case */ - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movzx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movzx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movzx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movzx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4] + emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp] + } } - return dst; -} - - -/*------------------------------------------------- - op_load2u - process a LOAD2U opcode --------------------------------------------------*/ - -static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movzx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movzx dstreg,[basep + 2*indp] /* other index */ else { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movzx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movzx dstreg,[basep + 2*indp] + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movzx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movzx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movzx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movzx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4] + emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp] + } } /* store low 32 bits */ @@ -3858,23 +3846,35 @@ static x86code *op_load2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /* 64-bit form stores upper 32 bits */ if (inst->size == 8) { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + /* 1, 2, or 4-byte case */ + if (sizep.value != DRCUML_SIZE_QWORD) + { + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + } + + /* 8-byte case */ + else + { + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx + } } return dst; } /*------------------------------------------------- - op_load2s - process a LOAD2S opcode + op_loads - process a LOADS opcode -------------------------------------------------*/ -static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_loads(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, basep, indp; + drcuml_parameter dstp, basep, indp, sizep; int dstreg; /* validate instruction */ @@ -3882,70 +3882,43 @@ static x86code *op_load2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI, &sizep, PTYPE_I); /* pick a target register for the general case */ - dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL); + dstreg = param_select_register(REG_EAX, &dstp, NULL); /* immediate index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_movsx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movsx eax,[basep + 2*indp] - - /* other index */ - else { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_movsx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movsx eax,[basep + 2*indp] - } - - /* 32-bit form */ - if (inst->size == 4) - { - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ - else - { - /* general case */ - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_m8(&dst, dstreg, MABS(basep.value + 1*indp.value)); // movsx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_m16(&dst, dstreg, MABS(basep.value + 2*indp.value)); // movsx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4] + emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp] + } } - return dst; -} - - -/*------------------------------------------------- - op_load4u - process a LOAD4U opcode --------------------------------------------------*/ - -static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 4*indp.value)); // mov dstreg,[basep + 4*indp] /* other index */ else { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp] + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_m8(&dst, dstreg, MISD(indreg, 1, basep.value)); // movsx dstreg,[basep + 1*indp] + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_m16(&dst, dstreg, MISD(indreg, 2, basep.value)); // movsx dstreg,[basep + 2*indp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 4, basep.value)); // mov dstreg,[basep + 4*indp] + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4] + emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp] + } } /* store low 32 bits */ @@ -3954,100 +3927,23 @@ static x86code *op_load4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /* 64-bit form stores upper 32 bits */ if (inst->size == 8) { - /* general case */ + emit_cdq(&dst); // cdq if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 + emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 - } - return dst; -} - - -/*------------------------------------------------- - op_load4s - process a LOAD4S opcode --------------------------------------------------*/ - -static x86code *op_load4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, basep, indp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_r32_m32(&dst, REG_EAX, MABS(basep.value + 4*indp.value)); // mov eax,[basep + 4*indp] - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_mov_r32_m32(&dst, REG_EAX, MISD(indreg, 4, basep.value)); // movsx eax,[basep + 4*indp] + emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx } - - /* general case */ - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax - return dst; } /*------------------------------------------------- - op_load8u - process a LOAD8U opcode + op_store - process a STORE opcode -------------------------------------------------*/ -static x86code *op_load8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_store(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, basep, indp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &basep, PTYPE_M, &indp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* immediate index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - { - emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 8*indp.value + 4)); // mov edx,[basep + 8*indp + 4] - emit_mov_r32_m32(&dst, dstreg, MABS(basep.value + 8*indp.value)); // mov dstreg,[basep + 8*indp] - } - - /* other index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 8, basep.value + 4)); // mov edx,[basep + 8*indp + 4] - emit_mov_r32_m32(&dst, dstreg, MISD(indreg, 8, basep.value)); // mov dstreg,[basep + 8*indp] - } - - /* general case */ - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dstp,edx:dstreg - - return dst; -} - - -/*------------------------------------------------- - op_store1 - process a STORE1 opcode --------------------------------------------------*/ - -static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; + drcuml_parameter srcp, basep, indp, sizep; int srcreg; /* validate instruction */ @@ -4055,118 +3951,51 @@ static x86code *op_store1(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); + param_normalize_4(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI, &sizep, PTYPE_I); /* pick a source register for the general case */ srcreg = param_select_register(REG_EAX, &srcp, NULL); - if (srcreg & 4) + if (sizep.value == DRCUML_SIZE_BYTE && (srcreg & 4)) srcreg = REG_EAX; /* degenerate case: constant index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) { + /* immediate source */ if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m8_imm(&dst, MABS(basep.value + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m8_r8(&dst, MABS(basep.value + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg - } - } - - /* normal case: variable index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m8_imm(&dst, MISD(indreg, 1, basep.value), srcp.value); // mov [basep + 1*ecx],srcp - else { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m8_r8(&dst, MISD(indreg, 1, basep.value), srcreg); // mov [basep + 1*ecx],srcreg - } - } - return dst; -} - - -/*------------------------------------------------- - op_store2 - process a STORE2 opcode --------------------------------------------------*/ - -static x86code *op_store2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; - int srcreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* pick a source register for the general case */ - srcreg = param_select_register(REG_EAX, &srcp, NULL); - - /* degenerate case: constant index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - { - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m16_imm(&dst, MABS(basep.value + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m16_r16(&dst, MABS(basep.value + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg - } - } - - /* normal case: variable index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m16_imm(&dst, MISD(indreg, 2, basep.value), srcp.value); // mov [basep + 2*ecx],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m16_r16(&dst, MISD(indreg, 2, basep.value), srcreg); // mov [basep + 2*ecx],srcreg + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_imm(&dst, MABS(basep.value + 1*indp.value), srcp.value); // mov [basep + 1*indp],srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_imm(&dst, MABS(basep.value + 2*indp.value), srcp.value); // mov [basep + 2*indp],srcp + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_imm(&dst, MABS(basep.value + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp + emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value + 4), srcp.value >> 32); + // mov [basep + 8*indp + 4],srcp >> 32 + } } - } - return dst; -} - - -/*------------------------------------------------- - op_store4 - process a STORE4 opcode --------------------------------------------------*/ - -static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; - int srcreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* pick a source register for the general case */ - srcreg = param_select_register(REG_EAX, &srcp, NULL); - - /* degenerate case: constant index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - { - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m32_imm(&dst, MABS(basep.value + 4*indp.value), srcp.value); // mov [basep + 4*indp],srcp + + /* variable source */ else { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m32_r32(&dst, MABS(basep.value + indp.value), srcreg); // mov [basep + 4*indp],srcreg + if (sizep.value != DRCUML_SIZE_QWORD) + emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_r8(&dst, MABS(basep.value + 1*indp.value), srcreg); // mov [basep + 1*indp],srcreg + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_r16(&dst, MABS(basep.value + 2*indp.value), srcreg); // mov [basep + 2*indp],srcreg + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_r32(&dst, MABS(basep.value + 4*indp.value), srcreg); // mov [basep + 4*indp],srcreg + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg + emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value + 4), REG_EDX); // mov [basep + 8*indp + 4],edx + } } } @@ -4175,69 +4004,42 @@ static x86code *op_store4(drcbe_state *drcbe, x86code *dst, const drcuml_instruc { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - emit_mov_m32_imm(&dst, MISD(indreg, 4, basep.value), srcp.value); // mov [basep + 4*ecx],srcp - else - { - emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp - emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), srcreg); // mov [basep + 4*ecx],srcreg - } - } - return dst; -} - - -/*------------------------------------------------- - op_store8 - process a STORE8 opcode --------------------------------------------------*/ -static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter srcp, basep, indp; - int srcreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* pick a source register for the general case */ - srcreg = param_select_register(REG_EAX, &srcp, NULL); - - /* degenerate case: constant index */ - if (indp.type == DRCUML_PTYPE_IMMEDIATE) - { + /* immediate source */ if (srcp.type == DRCUML_PTYPE_IMMEDIATE) { - emit_mov_m32_imm(&dst, MABS(basep.value + 8*indp.value), srcp.value); // mov [basep + 8*indp],srcp - emit_mov_m32_imm(&dst, MABS(basep.value + 4 + 8*indp.value), srcp.value >> 32); - // mov [basep + 4 + 8*indp],srcp >> 32 - } - else - { - emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp - emit_mov_m32_r32(&dst, MABS(basep.value + 8*indp.value), srcreg); // mov [basep + 8*indp],srcreg - emit_mov_m32_r32(&dst, MABS(basep.value + 4 + 8*indp.value), REG_EDX); // mov [basep + 8*indp + 4],edx + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_imm(&dst, MISD(indreg, 1, basep.value), srcp.value); // mov [basep + 1*ecx],srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_imm(&dst, MISD(indreg, 2, basep.value), srcp.value); // mov [basep + 2*ecx],srcp + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_imm(&dst, MISD(indreg, 4, basep.value), srcp.value); // mov [basep + 4*ecx],srcp + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value), srcp.value); // mov [basep + 8*ecx],srcp + emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value + 4), srcp.value >> 32); + // mov [basep + 8*ecx + 4],srcp >> 32 + } } - } - /* normal case: variable index */ - else - { - int indreg = param_select_register(REG_ECX, &indp, NULL); - emit_mov_r32_p32(drcbe, &dst, indreg, &indp); // mov indreg,indp - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - { - emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value), srcp.value); // mov [basep + 8*ecx],srcp - emit_mov_m32_imm(&dst, MISD(indreg, 8, basep.value + 4), srcp.value >> 32); // mov [basep + 8*ecx + 4],srcp >> 32 - } + /* variable source */ else { - emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp - emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value), srcreg); // mov [basep + 8*ecx],srcreg - emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value + 4), REG_EDX); // mov [basep + 4 + 8*ecx],edx + if (sizep.value != DRCUML_SIZE_QWORD) + emit_mov_r32_p32(drcbe, &dst, srcreg, &srcp); // mov srcreg,srcp + else + emit_mov_r64_p64(drcbe, &dst, srcreg, REG_EDX, &srcp); // mov edx:srcreg,srcp + if (sizep.value == DRCUML_SIZE_BYTE) + emit_mov_m8_r8(&dst, MISD(indreg, 1, basep.value), srcreg); // mov [basep + 1*ecx],srcreg + else if (sizep.value == DRCUML_SIZE_WORD) + emit_mov_m16_r16(&dst, MISD(indreg, 2, basep.value), srcreg); // mov [basep + 2*ecx],srcreg + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), srcreg); // mov [basep + 4*ecx],srcreg + else if (sizep.value == DRCUML_SIZE_QWORD) + { + emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value), srcreg); // mov [basep + 8*ecx],srcreg + emit_mov_m32_r32(&dst, MISD(indreg, 8, basep.value + 4), REG_EDX); // mov [basep + 8*ecx],edx + } } } return dst; @@ -4245,12 +4047,12 @@ static x86code *op_store8(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_read1u - process a READ1U opcode + op_read - process a READ opcode -------------------------------------------------*/ -static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_read(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, spacep, addrp; + drcuml_parameter dstp, addrp, spacesizep; int dstreg; /* validate instruction */ @@ -4258,124 +4060,74 @@ static x86code *op_read1u(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &spacesizep, PTYPE_I); /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); /* set up a call to the read byte handler */ emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_byte);// call read_byte - emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al - - /* store low 32 bits */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - /* 64-bit form stores upper 32 bits */ - if (inst->size == 8) + if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_byte); + // call read_byte + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al } - return dst; -} - - -/*------------------------------------------------- - op_read1s - process a READ1S opcode --------------------------------------------------*/ - -static x86code *op_read1s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read byte handler */ - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_byte);// call read_byte - emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - emit_movsx_r32_r8(&dst, dstreg, REG_AL); // movsx dstreg,al - - /* 32-bit form */ - if (inst->size == 4) + else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) { - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_word); + // call read_word + emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax } - - /* 64-bit form */ - else + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) { - /* general case */ - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_dword); + // call read_dword + emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax + } + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) + { + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_qword); + // call read_qword + emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax } - return dst; -} - - -/*------------------------------------------------- - op_read2u - process a READ2U opcode --------------------------------------------------*/ - -static x86code *op_read2u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read word handler */ - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word);// call read_word emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax /* store low 32 bits */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg /* 64-bit form stores upper 32 bits */ if (inst->size == 8) { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + /* 1, 2, or 4-byte case */ + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) + { + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + } + + /* 8-byte case */ + else + { + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx + } } return dst; } /*------------------------------------------------- - op_read2s - process a READ2S opcode + op_readm - process a READM opcode -------------------------------------------------*/ -static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_readm(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, spacep, addrp; + drcuml_parameter dstp, addrp, maskp, spacesizep; int dstreg; /* validate instruction */ @@ -4383,510 +4135,151 @@ static x86code *op_read2s(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); /* pick a target register for the general case */ dstreg = param_select_register(REG_EAX, &dstp, NULL); - /* set up a call to the read word handler */ - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word);// call read_word - emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - emit_movsx_r32_r16(&dst, dstreg, REG_AX); // movsx dstreg,ax - - /* 32-bit form */ - if (inst->size == 4) - { - /* general case */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ + /* set up a call to the read byte handler */ + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) + emit_push_p32(drcbe, &dst, &maskp); // push maskp else - { - /* general case */ - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax - } - return dst; -} - - -/*------------------------------------------------- - op_read2m - process a READ2M opcode --------------------------------------------------*/ - -static x86code *op_read2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp, maskp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* set up a call to the read dword masked handler */ - emit_push_p32(drcbe, &dst, &maskp); // push maskp + emit_push_p64(drcbe, &dst, &maskp); // push maskp emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_word_masked); + if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) + { + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_word_masked); // call read_word_masked - emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 - emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax - - /* store low 32 bits */ - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - - /* 64-bit form stores upper 32 bits */ - if (inst->size == 8) + emit_movzx_r32_r16(&dst, dstreg, REG_AX); // movzx dstreg,ax + } + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_dword_masked); + // call read_dword_masked + emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax } - return dst; -} - - -/*------------------------------------------------- - op_read4u - process a READ4U opcode --------------------------------------------------*/ - -static x86code *op_read4u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* set up a call to the read dword handler */ - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword - emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - - /* store low 32 bits */ - emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax - - /* 64-bit form stores upper 32 bits */ - if (inst->size == 8) + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->read_qword_masked); + // call read_qword_masked + emit_mov_r32_r32(&dst, dstreg, REG_EAX); // mov dstreg,eax } - return dst; -} - - -/*------------------------------------------------- - op_read4s - process a READ4S opcode --------------------------------------------------*/ - -static x86code *op_read4s(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* set up a call to the read dword handler */ - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword);// call read_dword - emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - - /* 64-bit form */ - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax - - return dst; -} - - -/*------------------------------------------------- - op_read4m - process a READ4M opcode --------------------------------------------------*/ - -static x86code *op_read4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp, maskp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); - - /* set up a call to the read dword masked handler */ - emit_push_p32(drcbe, &dst, &maskp); // push maskp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_dword_masked); - // call read_dword_masked - emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 - + emit_add_r32_imm(&dst, REG_ESP, ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) ? 8 : 12); + // add esp,8/12 /* store low 32 bits */ - emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg /* 64-bit form stores upper 32 bits */ if (inst->size == 8) { - /* general case */ - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + /* 1, 2, or 4-byte case */ + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) + { + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + } + + /* 8-byte case */ + else + { + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp+4],edx + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_EDX); // mov [reghi],edx + } } return dst; } /*------------------------------------------------- - op_read8u - process a READ8U opcode + op_write - process a WRITE opcode -------------------------------------------------*/ -static x86code *op_read8u(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_write(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, spacep, addrp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI); - - /* set up a call to the read qword handler */ - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword);// call read_qword - emit_add_r32_imm(&dst, REG_ESP, 4); // add esp,4 - - /* 64-bit form */ - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax - - return dst; -} - - -/*------------------------------------------------- - op_read8m - process a READ8M opcode --------------------------------------------------*/ - -static x86code *op_read8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, spacep, addrp, maskp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI); - - /* set up a call to the read qword masked handler */ - emit_push_p64(drcbe, &dst, &maskp); // push maskp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->read_qword_masked); - // call read_qword_masked - emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 - - /* 64-bit form */ - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dst,edx:eax - - return dst; -} - - -/*------------------------------------------------- - op_write1 - process a WRITE1 opcode --------------------------------------------------*/ - -static x86code *op_write1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; + drcuml_parameter addrp, srcp, spacesizep; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &spacesizep, PTYPE_I); /* set up a call to the write byte handler */ - emit_push_p32(drcbe, &dst, &srcp); // push srcp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_byte);// call write_byte - emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 - - return dst; -} - - -/*------------------------------------------------- - op_write2 - process a WRITE2 opcode --------------------------------------------------*/ - -static x86code *op_write2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_push_p32(drcbe, &dst, &srcp); // push srcp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_word);// call write_word - emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 - - return dst; -} - - -/*------------------------------------------------- - op_writ2m - process a WRIT2M opcode --------------------------------------------------*/ - -static x86code *op_writ2m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, maskp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_push_p32(drcbe, &dst, &maskp); // push maskp - emit_push_p32(drcbe, &dst, &srcp); // push srcp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_word_masked); - // call write_word_masked - emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 - return dst; -} - - -/*------------------------------------------------- - op_write4 - process a WRITE4 opcode --------------------------------------------------*/ - -static x86code *op_write4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write dword handler */ - emit_push_p32(drcbe, &dst, &srcp); // push srcp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword);// call write_dword - emit_add_r32_imm(&dst, REG_ESP, 8); // add esp,8 - - return dst; -} - - -/*------------------------------------------------- - op_writ4m - process a WRIT4M opcode --------------------------------------------------*/ - -static x86code *op_writ4m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, maskp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_push_p32(drcbe, &dst, &maskp); // push maskp - emit_push_p32(drcbe, &dst, &srcp); // push srcp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_dword_masked); - // call write_dword_masked - emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 - return dst; -} - - -/*------------------------------------------------- - op_write8 - process a WRITE8 opcode --------------------------------------------------*/ - -static x86code *op_write8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, srcp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write qword handler */ - emit_push_p64(drcbe, &dst, &srcp); // push srcp - emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword);// call write_qword - - emit_add_r32_imm(&dst, REG_ESP, 12); // add esp,12 - return dst; -} - - -/*------------------------------------------------- - op_writ8m - process a WRIT8M opcode --------------------------------------------------*/ - -static x86code *op_writ8m(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter spacep, addrp, maskp, srcp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_4(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &maskp, PTYPE_MRI, &srcp, PTYPE_MRI); - - /* set up a call to the write word handler */ - emit_push_p64(drcbe, &dst, &maskp); // push maskp - emit_push_p64(drcbe, &dst, &srcp); // push srcp + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) + emit_push_p32(drcbe, &dst, &srcp); // push srcp + else + emit_push_p64(drcbe, &dst, &srcp); // push srcp emit_push_p32(drcbe, &dst, &addrp); // push addrp - emit_call(&dst, (x86code *)active_address_space[spacep.value].accessors->write_qword_masked); - // call write_qword_masked - emit_add_r32_imm(&dst, REG_ESP, 20); // add esp,20 + if ((spacesizep.value & 3) == DRCUML_SIZE_BYTE) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_byte); + // call write_byte + else if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_word); + // call write_word + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_dword); + // call write_dword + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_qword); + // call write_qword + emit_add_r32_imm(&dst, REG_ESP, ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) ? 8 : 12); + // add esp,8/12 return dst; } /*------------------------------------------------- - op_flags - process a FLAGS opcode + op_writem - process a WRITEM opcode -------------------------------------------------*/ -static x86code *op_flags(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_writem(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, maskp, tablep; - int dstreg; + drcuml_parameter addrp, srcp, maskp, spacesizep; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &maskp, PTYPE_I, &tablep, PTYPE_M); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_ECX, &dstp, NULL); + param_normalize_4(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MRI, &maskp, PTYPE_MRI, &spacesizep, PTYPE_I); - /* translate live flags into UML flags */ - emit_pushf(&dst); // pushf - emit_pop_r32(&dst, REG_EAX); // pop eax - emit_and_r32_imm(&dst, REG_EAX, 0x8c5); // and eax,0x8c5 - emit_movzx_r32_m8(&dst, REG_EAX, MBD(REG_EAX, flags_map)); // movzx eax,[flags_map] - - /* 32-bit form */ - if (inst->size == 4) + /* set up a call to the write byte handler */ + if ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) { - /* no masking */ - if (maskp.value == 0xffffffff) - { - emit_mov_r32_m32(&dst, dstreg, MISD(REG_EAX, 4, tablep.value)); // mov dstreg,[eax*4+table] - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* general case */ - else - { - emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp - emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 4, tablep.value)); // mov edx,[eax*4+table] - emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask - emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask - emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } + emit_push_p32(drcbe, &dst, &maskp); // push maskp + emit_push_p32(drcbe, &dst, &srcp); // push srcp } - - /* 64-bit form */ else { - /* no masking */ - if (maskp.value == U64(0xffffffffffffffff)) - { - emit_mov_r32_m32(&dst, dstreg, MISD(REG_EAX, 8, tablep.value)); // mov dstreg,[eax*4+table] - emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 8, tablep.value + 4)); // mov edx,[eax*4+table+4] - emit_mov_p64_r64(drcbe, &dst, &dstp, dstreg, REG_EDX); // mov dst,edx:dstreg - } - - /* general case */ - else - { - if ((UINT32)maskp.value != 0) - { - emit_mov_r32_p32(drcbe, &dst, dstreg, &dstp); // mov dstreg,dstp - emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EAX, 8, tablep.value)); // mov edx,[eax*8+table] - emit_and_r32_imm(&dst, dstreg, ~maskp.value); // and dstreg,~mask - emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask - emit_or_r32_r32(&dst, dstreg, REG_EDX); // or dstreg,edx - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg.lo - } - if ((UINT32)(maskp.value >> 32) != 0) - { - if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_r32_m32(&dst, REG_ECX, MABS(drcbe->reghi[dstp.value])); // mov ecx,dstp.hi - else - emit_mov_r32_m32(&dst, REG_ECX, MABS(dstp.value + 4)); // mov ecx,dstp.hi - emit_mov_r32_m32(&dst, REG_EDX, MISD(REG_EDX, 8, tablep.value+4)); // mov edx,[eax*8+table+4] - emit_and_r32_imm(&dst, REG_ECX, ~maskp.value); // and ecx,~mask - emit_and_r32_imm(&dst, REG_EDX, maskp.value); // and edx,mask - emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or ecx,edx - if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_r32(&dst, MABS(drcbe->reghi[dstp.value]), REG_ECX); // mov dstp.hi,ecx - else - emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_ECX); // mov dstp.hi,ecx - } - } + emit_push_p64(drcbe, &dst, &maskp); // push maskp + emit_push_p64(drcbe, &dst, &srcp); // push srcp } + emit_push_p32(drcbe, &dst, &addrp); // push addrp + if ((spacesizep.value & 3) == DRCUML_SIZE_WORD) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_word_masked); + // call write_word_masked + else if ((spacesizep.value & 3) == DRCUML_SIZE_DWORD) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_dword_masked); + // call write_dword_masked + else if ((spacesizep.value & 3) == DRCUML_SIZE_QWORD) + emit_call(&dst, (x86code *)active_address_space[spacesizep.value / 16].accessors->write_qword_masked); + // call write_qword_masked + emit_add_r32_imm(&dst, REG_ESP, ((spacesizep.value & 3) != DRCUML_SIZE_QWORD) ? 12 : 20); + // add esp,12/20 return dst; } /*------------------------------------------------- - op_setc - process a SETC opcode + op_carry - process a CARRY opcode -------------------------------------------------*/ -static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_carry(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter srcp, bitp; @@ -4961,6 +4354,45 @@ static x86code *op_setc(drcbe_state *drcbe, x86code *dst, const drcuml_instructi /*------------------------------------------------- + op_set - process a SET opcode +-------------------------------------------------*/ + +static x86code *op_set(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +{ + drcuml_parameter dstp; + int dstreg; + + /* validate instruction */ + assert(inst->size == 4 || inst->size == 8); + assert(inst->condflags >= DRCUML_COND_Z && inst->condflags < DRCUML_COND_MAX); + + /* normalize parameters */ + param_normalize_1(drcbe, inst, &dstp, PTYPE_MR); + + /* pick a target register for the general case */ + dstreg = param_select_register(REG_EAX, &dstp, NULL); + + /* set to AL */ + emit_setcc_r8(&dst, X86_CONDITION(inst->condflags), REG_AL); // setcc al + emit_movzx_r32_r8(&dst, dstreg, REG_AL); // movzx dstreg,al + + /* store low 32 bits */ + emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + + /* 64-bit form stores upper 32 bits */ + if (inst->size == 8) + { + /* general case */ + if (dstp.type == DRCUML_PTYPE_MEMORY) + emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 + else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov [reghi],0 + } + return dst; +} + + +/*------------------------------------------------- op_mov - process a MOV opcode -------------------------------------------------*/ @@ -5067,71 +4499,12 @@ static x86code *op_mov(drcbe_state *drcbe, x86code *dst, const drcuml_instructio /*------------------------------------------------- - op_zext1 - process a ZEXT1 opcode --------------------------------------------------*/ - -static x86code *op_zext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT8)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* convert 8-bit source registers */ - if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) - { - emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp - srcp.value = REG_EAX; - } - - /* 32-bit form */ - if (inst->size == 4) - { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movzx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - - /* 64-bit form */ - else if (inst->size == 8) - { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movzx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movzx_r32_r8(&dst, dstreg, srcp.value); // movzx dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0 - } - return dst; -} - - -/*------------------------------------------------- - op_zext2 - process a ZEXT2 opcode + op_sext - process a SEXT opcode -------------------------------------------------*/ -static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_sext(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep; int dstreg; /* validate instruction */ @@ -5139,180 +4512,56 @@ static x86code *op_zext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruct assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI, &sizep, PTYPE_I); /* degenerate cases -- convert to a move */ if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT16)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* 32-bit form */ - if (inst->size == 4) { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movzx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + if (sizep.value == DRCUML_SIZE_BYTE) + return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); + else if (sizep.value == DRCUML_SIZE_WORD) + return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); + else if (sizep.value == DRCUML_SIZE_DWORD) + return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); } - /* 64-bit form */ - else if (inst->size == 8) - { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movzx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movzx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movzx_r32_r16(&dst, dstreg, srcp.value); // movzx dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0 - } - return dst; -} - - -/*------------------------------------------------- - op_zext4 - process a ZEXT4 opcode --------------------------------------------------*/ - -static x86code *op_zext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (UINT32)srcp.value); - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* 64-bit form */ - if (inst->size == 8) - { - /* general case */ - emit_mov_r32_p32(drcbe, &dst, dstreg, &srcp); // mov dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_mov_m32_imm(&dst, MABS(dstp.value + 4), 0); // mov [dstp+4],0 - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - emit_mov_m32_imm(&dst, MABS(drcbe->reghi[dstp.value]), 0); // mov reghi[dstp],0 - } - return dst; -} - - -/*------------------------------------------------- - op_sext1 - process a SEXT1 opcode --------------------------------------------------*/ - -static x86code *op_sext1(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT8)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); + dstreg = (inst->size == 8) ? REG_EAX : param_select_register(REG_EAX, &dstp, NULL); - /* convert 8-bit source registers */ - if (srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) + /* convert 8-bit source registers to EAX */ + if (sizep.value == DRCUML_SIZE_BYTE && srcp.type == DRCUML_PTYPE_INT_REGISTER && (srcp.value & 4)) { emit_mov_r32_r32(&dst, REG_EAX, srcp.value); // mov eax,srcp srcp.value = REG_EAX; } - /* 32-bit form */ - if (inst->size == 4) + /* general case */ + if (srcp.type == DRCUML_PTYPE_MEMORY) { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) + if (sizep.value == DRCUML_SIZE_BYTE) emit_movsx_r32_m8(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp - emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp] + else if (sizep.value == DRCUML_SIZE_DWORD) + emit_mov_r32_m32(&dst, dstreg, MABS(srcp.value)); // mov dstreg,[srcp] } - - /* 64-bit form */ - else if (inst->size == 8) + else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r32_m8(&dst, REG_EAX, MABS(srcp.value)); // movsx eax,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r32_r8(&dst, REG_EAX, srcp.value); // movsx eax,srcp - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax + if (sizep.value == DRCUML_SIZE_BYTE) + emit_movsx_r32_r8(&dst, dstreg, srcp.value); // movsx dstreg,srcp + else if (sizep.value == DRCUML_SIZE_WORD) + emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp + else if (sizep.value == DRCUML_SIZE_DWORD && dstreg != srcp.value) + emit_mov_r32_r32(&dst, dstreg, srcp.value); // mov dstreg,srcp } - return dst; -} - - -/*------------------------------------------------- - op_sext2 - process a SEXT2 opcode --------------------------------------------------*/ - -static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - int dstreg; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT16)srcp.value); - - /* pick a target register for the general case */ - dstreg = param_select_register(REG_EAX, &dstp, NULL); - - /* 32-bit form */ + + /* 32-bit form: store the low 32 bits */ if (inst->size == 4) - { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r32_m16(&dst, dstreg, MABS(srcp.value)); // movsx dstreg,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r32_r16(&dst, dstreg, srcp.value); // movsx dstreg,srcp emit_mov_p32_r32(drcbe, &dst, &dstp, dstreg); // mov dstp,dstreg - } - /* 64-bit form */ + /* 64-bit form: sign extend to 64 bits and store edx:eax */ else if (inst->size == 8) { - /* general case */ - if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_movsx_r32_m16(&dst, REG_EAX, MABS(srcp.value)); // movsx eax,[srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - emit_movsx_r32_r16(&dst, REG_EAX, srcp.value); // movsx eax,srcp emit_cdq(&dst); // cdq emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax } @@ -5321,41 +4570,10 @@ static x86code *op_sext2(drcbe_state *drcbe, x86code *dst, const drcuml_instruct /*------------------------------------------------- - op_sext4 - process a SEXT4 opcode + op_roland - process an ROLAND opcode -------------------------------------------------*/ -static x86code *op_sext4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MRI); - - /* degenerate cases -- convert to a move */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - return convert_to_mov_imm(drcbe, dst, inst, &dstp, (INT32)srcp.value); - - /* 64-bit form */ - if (inst->size == 8) - { - /* general case */ - emit_mov_r32_p32(drcbe, &dst, REG_EAX, &srcp); // mov eax,srcp - emit_cdq(&dst); // cdq - emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax - } - return dst; -} - - -/*------------------------------------------------- - op_xtract - process an XTRACT opcode --------------------------------------------------*/ - -static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_roland(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter dstp, srcp, shiftp, maskp; int dstreg; @@ -5417,10 +4635,10 @@ static x86code *op_xtract(drcbe_state *drcbe, x86code *dst, const drcuml_instruc /*------------------------------------------------- - op_insert - process an INSERT opcode + op_rolins - process an ROLINS opcode -------------------------------------------------*/ -static x86code *op_insert(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_rolins(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter dstp, srcp, shiftp, maskp; int dstreg; @@ -5889,6 +5107,27 @@ static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax if (compute_hi) emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx + + /* compute flags */ + if (inst->condflags != 0) + { + if (compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax + } } /* 64-bit form */ @@ -5907,13 +5146,45 @@ static x86code *op_mulu(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax - if (inst->condflags != 0) - emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx + if (inst->condflags != 0 && !compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + } + } if (compute_hi) { + if (inst->condflags & DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo - emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi - emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax + emit_mov_r32_m32(&dst, REG_ECX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov ecx,reshi.hi + emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_ECX); // mov edstp,ecx:eax + if (inst->condflags != 0) + { + if (inst->condflags == DRCUML_FLAG_Z) + { + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + } + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_ECX, REG_ECX); // test ecx,ecx + else + { + emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx + emit_movzx_r32_r16(&dst, REG_EDX, REG_AX); // movzx edx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or edx,ecx + emit_or_r32_r32(&dst, REG_ECX, REG_EAX); // or edx,eax + } + } } } return dst; @@ -6008,6 +5279,27 @@ static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_p32_r32(drcbe, &dst, &dstp, REG_EAX); // mov dstp,eax emit_mov_p32_r32(drcbe, &dst, &edstp, REG_EDX); // mov edstp,edx } + + /* compute flags */ + if (inst->condflags != 0) + { + if (compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + } + } + else + emit_test_r32_r32(&dst, REG_EAX, REG_EAX); // test eax,eax + } } /* 64-bit form */ @@ -6026,13 +5318,43 @@ static x86code *op_muls(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reslo + 0)); // mov eax,reslo.lo emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reslo + 1)); // mov edx,reslo.hi emit_mov_p64_r64(drcbe, &dst, &dstp, REG_EAX, REG_EDX); // mov dstp,edx:eax - if (inst->condflags != 0) - emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx + if (inst->condflags != 0 && !compute_hi) + { + if (inst->condflags == DRCUML_FLAG_Z) + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_EDX, REG_EDX); // test edx,edx + else + { + emit_movzx_r32_r16(&dst, REG_ECX, REG_AX); // movzx ecx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + } + } if (compute_hi) { emit_mov_r32_m32(&dst, REG_EAX, MABS((UINT32 *)&drcbe->reshi + 0)); // mov eax,reshi.lo emit_mov_r32_m32(&dst, REG_EDX, MABS((UINT32 *)&drcbe->reshi + 1)); // mov edx,reshi.hi emit_mov_p64_r64(drcbe, &dst, &edstp, REG_EAX, REG_EDX); // mov edstp,edx:eax + if (inst->condflags != 0) + { + if (inst->condflags == DRCUML_FLAG_Z) + { + emit_or_r32_r32(&dst, REG_EDX, REG_EAX); // or edx,eax + emit_or_r32_r32(&dst, REG_EDX, REG_ECX); // or edx,ecx + } + else if (inst->condflags == DRCUML_FLAG_S) + emit_test_r32_r32(&dst, REG_ECX, REG_ECX); // test ecx,ecx + else + { + emit_or_r32_r32(&dst, REG_EAX, REG_EDX); // or eax,edx + emit_movzx_r32_r16(&dst, REG_EDX, REG_AX); // movzx edx,ax + emit_shr_r32_imm(&dst, REG_EAX, 16); // shr eax,16 + emit_or_r32_r32(&dst, REG_ECX, REG_EDX); // or edx,ecx + emit_or_r32_r32(&dst, REG_ECX, REG_EAX); // or edx,eax + } + } } } return dst; @@ -6963,10 +6285,9 @@ static x86code *op_fload(drcbe_state *drcbe, x86code *dst, const drcuml_instruct /* immediate index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) { - if (inst->size == 4) - emit_fld_m32(&dst, MABS(basep.value + 4*indp.value)); // fld [basep + 4*indp] - else if (inst->size == 8) - emit_fld_m64(&dst, MABS(basep.value + 8*indp.value)); // fld [basep + 8*indp] + emit_mov_r32_m32(&dst, REG_EAX, MABS(basep.value + 4*indp.value)); // mov eax,[basep + 4*indp] + if (inst->size == 8) + emit_mov_r32_m32(&dst, REG_EDX, MABS(basep.value + 4 + 4*indp.value)); // mov edx,[basep + 4*indp + 4] } /* other index */ @@ -6974,15 +6295,15 @@ static x86code *op_fload(drcbe_state *drcbe, x86code *dst, const drcuml_instruct { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - if (inst->size == 4) - emit_fld_m32(&dst, MISD(indreg, 4, basep.value)); // fld [basep + 4*indp] - else if (inst->size == 8) - emit_fld_m64(&dst, MISD(indreg, 8, basep.value)); // fld [basep + 8*indp] + emit_mov_r32_m32(&dst, REG_EAX, MISD(indreg, 4, basep.value)); // mov eax,[basep + 4*indp] + if (inst->size == 8) + emit_mov_r32_m32(&dst, REG_EDX, MISD(indreg, 4, basep.value + 4)); // mov edx,[basep + 4*indp + 4] } /* general case */ - emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp - + emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax + if (inst->size == 8) + emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp + 4],edx return dst; } @@ -7003,15 +6324,16 @@ static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruc param_normalize_3(drcbe, inst, &basep, PTYPE_M, &indp, PTYPE_MRI, &srcp, PTYPE_MF); /* general case */ - emit_fld_p(&dst, inst->size, &srcp); + emit_mov_r32_m32(&dst, REG_EAX, MABS(srcp.value)); // mov eax,[srcp] + if (inst->size == 8) + emit_mov_r32_m32(&dst, REG_EDX, MABS(srcp.value + 4)); // mov edx,[srcp + 4] /* immediate index */ if (indp.type == DRCUML_PTYPE_IMMEDIATE) { - if (inst->size == 4) - emit_fstp_m32(&dst, MABS(basep.value + 4*indp.value)); // fstp [basep + 4*indp] - else if (inst->size == 8) - emit_fstp_m64(&dst, MABS(basep.value + 8*indp.value)); // fstp [basep + 8*indp] + emit_mov_m32_r32(&dst, MABS(basep.value + 4*indp.value), REG_EAX); // mov [basep + 4*indp],eax + if (inst->size == 8) + emit_mov_m32_r32(&dst, MABS(basep.value + 4 + 4*indp.value), REG_EDX); // mov [basep + 4*indp + 4],edx } /* other index */ @@ -7019,10 +6341,9 @@ static x86code *op_fstore(drcbe_state *drcbe, x86code *dst, const drcuml_instruc { int indreg = param_select_register(REG_ECX, &indp, NULL); emit_mov_r32_p32(drcbe, &dst, indreg, &indp); - if (inst->size == 4) - emit_fstp_m32(&dst, MISD(indreg, 4, basep.value)); // fstp [basep + 4*indp] - else if (inst->size == 8) - emit_fstp_m64(&dst, MISD(indreg, 8, basep.value)); // fstp [basep + 8*indp] + emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value), REG_EAX); // mov [basep + 4*indp],eax + if (inst->size == 8) + emit_mov_m32_r32(&dst, MISD(indreg, 4, basep.value + 4), REG_EDX); // mov [basep + 4*indp + 4],edx } return dst; } @@ -7041,7 +6362,7 @@ static x86code *op_fread(drcbe_state *drcbe, x86code *dst, const drcuml_instruct assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &spacep, PTYPE_I, &addrp, PTYPE_MRI); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &addrp, PTYPE_MRI, &spacep, PTYPE_I); /* set up a call to the read dword/qword handler */ emit_push_p32(drcbe, &dst, &addrp); // push addrp @@ -7074,7 +6395,7 @@ static x86code *op_fwrite(drcbe_state *drcbe, x86code *dst, const drcuml_instruc assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_3(drcbe, inst, &spacep, PTYPE_I, &addrp, PTYPE_MRI, &srcp, PTYPE_MF); + param_normalize_3(drcbe, inst, &addrp, PTYPE_MRI, &srcp, PTYPE_MF, &spacep, PTYPE_I); /* set up a call to the write dword/qword handler */ if (inst->size == 4) @@ -7113,8 +6434,12 @@ static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instructi emit_jcc_short_link(&dst, X86_NOT_CONDITION(inst->condflags), &skip); // jcc skip /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp + emit_mov_r32_m32(&dst, REG_EAX, MABS(srcp.value)); // mov eax,[srcp] + if (inst->size == 8) + emit_mov_r32_m32(&dst, REG_EDX, MABS(srcp.value + 4)); // mov edx,[srcp + 4] + emit_mov_m32_r32(&dst, MABS(dstp.value), REG_EAX); // mov [dstp],eax + if (inst->size == 8) + emit_mov_m32_r32(&dst, MABS(dstp.value + 4), REG_EDX); // mov [dstp + 4],edx /* resolve the jump */ if (skip.target != NULL) @@ -7124,394 +6449,154 @@ static x86code *op_fmov(drcbe_state *drcbe, x86code *dst, const drcuml_instructi /*------------------------------------------------- - op_ftoi4 - process a FTOI4 opcode + op_ftoint - process a FTOINT opcode -------------------------------------------------*/ -static x86code *op_ftoi4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_ftoint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep, roundp; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); + param_normalize_4(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF, &sizep, PTYPE_I, &roundp, PTYPE_I); - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + /* set rounding mode if necessary */ + if (roundp.value != DRCUML_FMOD_DEFAULT && (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC)) { - emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] + emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] + emit_fldcw_m16(&dst, MABS(&fp_control[roundp.value])); // fldcw fpcontrol[roundp] } - return dst; -} - - -/*------------------------------------------------- - op_ftoi4t - process a FTOI4T opcode --------------------------------------------------*/ - -static x86code *op_ftoi4t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* non-SSE3 case */ - if (!drcbe->sse3) + + /* general case */ + emit_fld_p(&dst, inst->size, &srcp); // fld srcp + + /* 4-byte integer case */ + if (sizep.value == DRCUML_SIZE_DWORD) { - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_TRUNC])); // fldcw fpcontrol[DRCUML_FMOD_TRUNC] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] + { + if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) + emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] + else + emit_fisttp_m32(&dst, MABS(dstp.value)); // fisttp [dstp] + } else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) { - emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] + if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) + emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] + else + emit_fisttp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] } - - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] } - - /* SSE3 case */ - else + + /* 8-byte integer case */ + else if (sizep.value == DRCUML_SIZE_QWORD) { - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fisttp_m32(&dst, MABS(dstp.value)); // fisttp [dstp] + { + if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) + emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] + else + emit_fisttp_m64(&dst, MABS(dstp.value)); // fisttp [dstp] + } else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) { - emit_fisttp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] + if (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC) + emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] + else + emit_fisttp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] } } - return dst; -} - - -/*------------------------------------------------- - op_ftoi4r - process a FTOI4R opcode --------------------------------------------------*/ - -static x86code *op_ftoi4r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_ROUND])); // fldcw fpcontrol[DRCUML_FMOD_ROUND] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] - } /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] - return dst; -} - - -/*------------------------------------------------- - op_ftoi4f - process a FTOI4F opcode --------------------------------------------------*/ - -static x86code *op_ftoi4f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_FLOOR])); // fldcw fpcontrol[DRCUML_FMOD_FLOOR] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] - } - - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] - return dst; -} - - -/*------------------------------------------------- - op_ftoi4c - process a FTOI4C opcode --------------------------------------------------*/ - -static x86code *op_ftoi4c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_CEIL])); // fldcw fpcontrol[DRCUML_FMOD_CEIL] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m32(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_fistp_m32(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] - } + if (roundp.value != DRCUML_FMOD_DEFAULT && (!drcbe->sse3 || roundp.value != DRCUML_FMOD_TRUNC)) + emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] return dst; } /*------------------------------------------------- - op_ftoi8 - process a FTOI8 opcode + op_ffrint - process a FFRINT opcode -------------------------------------------------*/ -static x86code *op_ftoi8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_ffrint(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); + param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI, &sizep, PTYPE_I); - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + /* 4-byte integer case */ + if (sizep.value == DRCUML_SIZE_DWORD) { - emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] - } - return dst; -} - - -/*------------------------------------------------- - op_ftoi8t - process a FTOI8T opcode --------------------------------------------------*/ - -static x86code *op_ftoi8t(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* non-SSE3 case */ - if (!drcbe->sse3) - { - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_TRUNC])); // fldcw fpcontrol[DRCUML_FMOD_TRUNC] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + if (srcp.type == DRCUML_PTYPE_IMMEDIATE) { - emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] + emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp + emit_fild_m32(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] } - - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] - } - - /* SSE3 case */ - else - { - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fisttp_m64(&dst, MABS(dstp.value)); // fisttp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + else if (srcp.type == DRCUML_PTYPE_MEMORY) + emit_fild_m32(&dst, MABS(srcp.value)); // fild [srcp] + else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) { - emit_fisttp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fisttp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] + emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp + emit_fild_m32(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] } } - return dst; -} - - -/*------------------------------------------------- - op_ftoi8r - process a FTOI8R opcode --------------------------------------------------*/ - -static x86code *op_ftoi8r(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_ROUND])); // fldcw fpcontrol[DRCUML_FMOD_ROUND] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] - } - - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] - return dst; -} - - -/*------------------------------------------------- - op_ftoi8f - process a FTOI8F opcode --------------------------------------------------*/ - -static x86code *op_ftoi8f(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_FLOOR])); // fldcw fpcontrol[DRCUML_FMOD_FLOOR] - - /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) + + /* 8-bit integer case */ + else if (sizep.value == DRCUML_SIZE_QWORD) { - emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] + if (srcp.type == DRCUML_PTYPE_IMMEDIATE) + { + emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp + emit_mov_m32_imm(&dst, MABS((UINT8 *)&drcbe->fptemp + 4), srcp.value); // mov [fptemp+4],srcp + emit_fild_m64(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] + } + else if (srcp.type == DRCUML_PTYPE_MEMORY) + emit_fild_m64(&dst, MABS(srcp.value)); // fild [srcp] + else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) + { + emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp + emit_fild_m64(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] + } } - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] + /* store the result and be done */ + emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp] return dst; } /*------------------------------------------------- - op_ftoi8c - process a FTOI8C opcode + op_ffrflt - process a FFRFLT opcode -------------------------------------------------*/ -static x86code *op_ftoi8c(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_ffrflt(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { - drcuml_parameter dstp, srcp; + drcuml_parameter dstp, srcp, sizep; /* validate instruction */ assert(inst->size == 4 || inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MR, &srcp, PTYPE_MF); - - /* save and set the control word */ - emit_fstcw_m16(&dst, MABS(&drcbe->fmodesave)); // fstcw [fmodesave] - emit_fldcw_m16(&dst, MABS(&fp_control[DRCUML_FMOD_CEIL])); // fldcw fpcontrol[DRCUML_FMOD_CEIL] + param_normalize_3(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF, &sizep, PTYPE_I); /* general case */ - emit_fld_p(&dst, inst->size, &srcp); // fld srcp - if (dstp.type == DRCUML_PTYPE_MEMORY) - emit_fistp_m64(&dst, MABS(dstp.value)); // fistp [dstp] - else if (dstp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_fistp_m64(&dst, MABS(drcbe->reglo[dstp.value])); // fistp reglo[dstp] - emit_mov_r32_m32(&dst, dstp.value, MABS(drcbe->reglo[dstp.value])); // mov dstp,reglo[dstp] - } - - /* restore control word and proceed */ - emit_fldcw_m16(&dst, MABS(&drcbe->fmodesave)); // fldcw [fmodesave] - return dst; -} - - -/*------------------------------------------------- - op_ffrfs - process a FFRFS opcode --------------------------------------------------*/ - -static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); - - /* general case */ - emit_fld_m32(&dst, MABS(srcp.value)); // fld [srcp] + if (sizep.value == DRCUML_SIZE_DWORD) + emit_fld_m32(&dst, MABS(srcp.value)); // fld [srcp] + else if (sizep.value == DRCUML_SIZE_QWORD) + emit_fld_m64(&dst, MABS(srcp.value)); // fld [srcp] emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp return dst; @@ -7519,90 +6604,24 @@ static x86code *op_ffrfs(drcbe_state *drcbe, x86code *dst, const drcuml_instruct /*------------------------------------------------- - op_ffrfd - process a FFRFD opcode + op_frnds - process a FRNDS opcode -------------------------------------------------*/ -static x86code *op_ffrfd(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) +static x86code *op_frnds(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) { drcuml_parameter dstp, srcp; /* validate instruction */ - assert(inst->size == 4); + assert(inst->size == 8); assert(inst->condflags == DRCUML_COND_ALWAYS); /* normalize parameters */ param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MF); /* general case */ - emit_fld_m64(&dst, MABS(srcp.value)); // fld [srcp] - emit_fstp_p(&dst, inst->size, &dstp); // fstp dstp - - return dst; -} - - -/*------------------------------------------------- - op_ffri4 - process a FFRI4 opcode --------------------------------------------------*/ - -static x86code *op_ffri4(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - { - emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp - emit_fild_m32(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] - } - else if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_fild_m32(&dst, MABS(srcp.value)); // fild [srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp - emit_fild_m32(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] - } - emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp] - return dst; -} - - -/*------------------------------------------------- - op_ffri8 - process a FFRI8 opcode --------------------------------------------------*/ - -static x86code *op_ffri8(drcbe_state *drcbe, x86code *dst, const drcuml_instruction *inst) -{ - drcuml_parameter dstp, srcp; - - /* validate instruction */ - assert(inst->size == 4 || inst->size == 8); - assert(inst->condflags == DRCUML_COND_ALWAYS); - - /* normalize parameters */ - param_normalize_2(drcbe, inst, &dstp, PTYPE_MF, &srcp, PTYPE_MRI); - - /* general case */ - if (srcp.type == DRCUML_PTYPE_IMMEDIATE) - { - emit_mov_m32_imm(&dst, MABS(&drcbe->fptemp), srcp.value); // mov [fptemp],srcp - emit_mov_m32_imm(&dst, MABS((UINT8 *)&drcbe->fptemp + 4), srcp.value); // mov [fptemp+4],srcp - emit_fild_m64(&dst, MABS(&drcbe->fptemp)); // fild [fptemp] - } - else if (srcp.type == DRCUML_PTYPE_MEMORY) - emit_fild_m64(&dst, MABS(srcp.value)); // fild [srcp] - else if (srcp.type == DRCUML_PTYPE_INT_REGISTER) - { - emit_mov_m32_r32(&dst, MABS(drcbe->reglo[srcp.value]), srcp.value); // mov reglo[srcp],srcp - emit_fild_m64(&dst, MABS(drcbe->reglo[srcp.value])); // fild reglo[srcp] - } + emit_fld_p(&dst, inst->size, &srcp); // fld srcp + emit_fstp_m32(&dst, MABS(&drcbe->fptemp)); // fstp [fptemp] + emit_fld_m32(&dst, MABS(&drcbe->fptemp)); // fld [fptemp] emit_fstp_p(&dst, inst->size, &dstp); // fstp [dstp] return dst; } diff --git a/src/emu/cpu/drcfe.c b/src/emu/cpu/drcfe.c index f6282e60c04..d84452b506c 100644 --- a/src/emu/cpu/drcfe.c +++ b/src/emu/cpu/drcfe.c @@ -63,6 +63,7 @@ struct _drcfe_state /* CPU parameters */ offs_t pageshift; /* shift to convert address to a page index */ cpu_translate_func translate; /* pointer to translation function */ + offs_t codexor; /* XOR to reach code */ /* opcode descriptor arrays */ opcode_desc * desc_live_list; /* head of list of live descriptions */ @@ -149,6 +150,12 @@ drcfe_state *drcfe_init(const drcfe_config *config, void *param) /* initialize the state */ drcfe->pageshift = activecpu_page_shift(ADDRESS_SPACE_PROGRAM); drcfe->translate = (cpu_translate_func)activecpu_get_info_fct(CPUINFO_PTR_TRANSLATE); +#ifdef LSB_FIRST + if (activecpu_endianness() == CPU_IS_BE) +#else + if (activecpu_endianness() == CPU_IS_LE) +#endif + drcfe->codexor = (activecpu_databus_width(ADDRESS_SPACE_PROGRAM) / 8 / activecpu_min_instruction_bytes() - 1) * activecpu_min_instruction_bytes(); return drcfe; } @@ -225,7 +232,7 @@ const opcode_desc *drcfe_describe_code(drcfe_state *drcfe, offs_t startpc) } /* loop until we exit the block */ - for (curpc = curstack->targetpc; curpc < maxpc && drcfe->desc_array[curpc - minpc] == NULL; curpc += drcfe->desc_array[curpc - minpc]->length) + for (curpc = curstack->targetpc; curpc >= minpc && curpc < maxpc && drcfe->desc_array[curpc - minpc] == NULL; curpc += drcfe->desc_array[curpc - minpc]->length) { /* allocate a new description and describe this instruction */ drcfe->desc_array[curpc - minpc] = curdesc = describe_one(drcfe, curpc); @@ -297,7 +304,7 @@ static opcode_desc *describe_one(drcfe_state *drcfe, offs_t curpc) /* get a pointer to the physical address */ memory_set_opbase(desc->physpc); - desc->opptr.v = cpu_opptr(desc->physpc); + desc->opptr.v = cpu_opptr(desc->physpc ^ drcfe->codexor); assert(desc->opptr.v != NULL); if (desc->opptr.v == NULL) { diff --git a/src/emu/cpu/drcuml.c b/src/emu/cpu/drcuml.c index 988425fb7cc..a6a3c0609af 100644 --- a/src/emu/cpu/drcuml.c +++ b/src/emu/cpu/drcuml.c @@ -12,6 +12,12 @@ Future improvements/changes: + * UML optimizer: + - detects constant operations, converts to MOV + - eliminates no-ops (add i0,i0,0) + - determines flags automatically + - constant folding + * Write a back-end validator: - checks all combinations of memory/register/immediate on all params - checks behavior of all opcodes @@ -21,9 +27,6 @@ * Support for FPU exceptions * New instructions? - - FDRNDS dst,src - round to single-precision - - FCOPYI, ICOPYF copy raw between float and integer registers @@ -201,49 +204,24 @@ static const drcuml_opcode_valid opcode_valid_list[] = OPVALID_ENTRY_1(SETFMOD, 4, NONE, IANY) OPVALID_ENTRY_1(GETFMOD, 4, NONE, IRM) OPVALID_ENTRY_1(GETEXP, 4, NONE, IRM) + OPVALID_ENTRY_1(GETFLGS, 4, NONE, IRM) OPVALID_ENTRY_1(SAVE, 4, NONE, ANYMEM) OPVALID_ENTRY_1(RESTORE, 4, NONE, ANYMEM) /* Integer Operations */ - OPVALID_ENTRY_3(LOAD1U, 4|8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(LOAD1S, 4|8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(LOAD2U, 4|8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(LOAD2S, 4|8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(LOAD4U, 4|8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(LOAD4S, 8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(LOAD8U, 8, NONE, IRM, ANYMEM,IANY4) - OPVALID_ENTRY_3(STORE1, 4|8, NONE, ANYMEM,IANY4, IANY) - OPVALID_ENTRY_3(STORE2, 4|8, NONE, ANYMEM,IANY4, IANY) - OPVALID_ENTRY_3(STORE4, 4|8, NONE, ANYMEM,IANY4, IANY) - OPVALID_ENTRY_3(STORE8, 8, NONE, ANYMEM,IANY4, IANY) - OPVALID_ENTRY_3(READ1U, 4|8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_3(READ1S, 4|8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_3(READ2U, 4|8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_3(READ2S, 4|8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_4(READ2M, 4|8, NONE, IRM, IMV4, IANY4, IANY) - OPVALID_ENTRY_3(READ4U, 4|8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_3(READ4S, 8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_4(READ4M, 4|8, NONE, IRM, IMV4, IANY4, IANY) - OPVALID_ENTRY_3(READ8U, 8, NONE, IRM, IMV4, IANY4) - OPVALID_ENTRY_4(READ8M, 8, NONE, IRM, IMV4, IANY4, IANY) - OPVALID_ENTRY_3(WRITE1, 4|8, NONE, IMV4, IANY4, IANY) - OPVALID_ENTRY_3(WRITE2, 4|8, NONE, IMV4, IANY4, IANY) - OPVALID_ENTRY_4(WRIT2M, 4|8, NONE, IMV4, IANY4, IANY, IANY) - OPVALID_ENTRY_3(WRITE4, 4|8, NONE, IMV4, IANY4, IANY) - OPVALID_ENTRY_4(WRIT4M, 4|8, NONE, IMV4, IANY4, IANY, IANY) - OPVALID_ENTRY_3(WRITE8, 8, NONE, IMV4, IANY4, IANY) - OPVALID_ENTRY_4(WRIT8M, 8, NONE, IMV4, IANY4, IANY, IANY) - OPVALID_ENTRY_3(FLAGS, 4|8, NONE, IRM, IMV, MEM) - OPVALID_ENTRY_2(SETC, 4|8, NONE, IANY, IANY) + OPVALID_ENTRY_4(LOAD, 4|8, NONE, IRM, ANYMEM,IANY4, IMV) + OPVALID_ENTRY_4(LOADS, 4|8, NONE, IRM, ANYMEM,IANY4, IMV) + OPVALID_ENTRY_4(STORE, 4|8, NONE, ANYMEM,IANY4, IANY, IMV) + OPVALID_ENTRY_3(READ, 4|8, NONE, IRM, IANY4, IMV) + OPVALID_ENTRY_4(READM, 4|8, NONE, IRM, IANY4, IANY, IMV) + OPVALID_ENTRY_3(WRITE, 4|8, NONE, IANY4, IANY, IMV) + OPVALID_ENTRY_4(WRITEM, 4|8, NONE, IANY4, IANY, IANY, IMV) + OPVALID_ENTRY_2(CARRY, 4|8, NONE, IANY, IANY) OPVALID_ENTRY_2(MOV, 4|8, COND, IRM, IANY) - OPVALID_ENTRY_2(ZEXT1, 4|8, NONE, IRM, IANY4) - OPVALID_ENTRY_2(ZEXT2, 4|8, NONE, IRM, IANY4) - OPVALID_ENTRY_2(ZEXT4, 8, NONE, IRM, IANY4) - OPVALID_ENTRY_2(SEXT1, 4|8, NONE, IRM, IANY4) - OPVALID_ENTRY_2(SEXT2, 4|8, NONE, IRM, IANY4) - OPVALID_ENTRY_2(SEXT4, 8, NONE, IRM, IANY4) - OPVALID_ENTRY_4(XTRACT, 4|8, NONE, IRM, IANY, IANY, IANY) - OPVALID_ENTRY_4(INSERT, 4|8, NONE, IRM, IANY, IANY, IANY) + OPVALID_ENTRY_1(SET, 4|8, COND, IRM) + OPVALID_ENTRY_3(SEXT, 4|8, NONE, IRM, IANY4, IMV) + OPVALID_ENTRY_4(ROLAND, 4|8, NONE, IRM, IANY, IANY, IANY) + OPVALID_ENTRY_4(ROLINS, 4|8, NONE, IRM, IANY, IANY, IANY) OPVALID_ENTRY_3(ADD, 4|8, SZVC, IRM, IANY, IANY) OPVALID_ENTRY_3(ADDC, 4|8, SZVC, IRM, IANY, IANY) OPVALID_ENTRY_3(SUB, 4|8, SZVC, IRM, IANY, IANY) @@ -270,23 +248,13 @@ static const drcuml_opcode_valid opcode_valid_list[] = /* Floating Point Operations */ OPVALID_ENTRY_3(FLOAD, 4|8, NONE, FRM, ANYMEM,IANY4) OPVALID_ENTRY_3(FSTORE, 4|8, NONE, ANYMEM,IANY4, FANY) - OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IMV4, IANY4) - OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IMV4, IANY4, FANY) + OPVALID_ENTRY_3(FREAD, 4|8, NONE, FRM, IANY4, IMV4) + OPVALID_ENTRY_3(FWRITE, 4|8, NONE, IANY4, FANY, IMV4) OPVALID_ENTRY_2(FMOV, 4|8, COND, FRM, FANY) - OPVALID_ENTRY_2(FTOI4, 4|8, NONE, IRM4, FANY) - OPVALID_ENTRY_2(FTOI4T, 4|8, NONE, IRM4, FANY) - OPVALID_ENTRY_2(FTOI4R, 4|8, NONE, IRM4, FANY) - OPVALID_ENTRY_2(FTOI4F, 4|8, NONE, IRM4, FANY) - OPVALID_ENTRY_2(FTOI4C, 4|8, NONE, IRM4, FANY) - OPVALID_ENTRY_2(FTOI8, 4|8, NONE, IRM8, FANY) - OPVALID_ENTRY_2(FTOI8T, 4|8, NONE, IRM8, FANY) - OPVALID_ENTRY_2(FTOI8R, 4|8, NONE, IRM8, FANY) - OPVALID_ENTRY_2(FTOI8F, 4|8, NONE, IRM8, FANY) - OPVALID_ENTRY_2(FTOI8C, 4|8, NONE, IRM8, FANY) - OPVALID_ENTRY_2(FFRFS, 8, NONE, FRM, FANY4) - OPVALID_ENTRY_2(FFRFD, 4 , NONE, FRM, FANY8) - OPVALID_ENTRY_2(FFRI4, 4|8, NONE, FRM, IANY4) - OPVALID_ENTRY_2(FFRI8, 4|8, NONE, FRM, IANY8) + OPVALID_ENTRY_4(FTOINT, 4|8, NONE, IRM, FANY, IMM, IMM) + OPVALID_ENTRY_3(FFRINT, 4|8, NONE, FRM, IANY, IMM) + OPVALID_ENTRY_3(FFRFLT, 4|8, NONE, FRM, FANY, IMM) + OPVALID_ENTRY_2(FRNDS, 8, NONE, FRM, FANY) OPVALID_ENTRY_3(FADD, 4|8, NONE, FRM, FANY, FANY) OPVALID_ENTRY_3(FSUB, 4|8, NONE, FRM, FANY, FANY) OPVALID_ENTRY_2(FCMP, 4|8, UZC, FANY, FANY) diff --git a/src/emu/cpu/drcuml.h b/src/emu/cpu/drcuml.h index c3200150ff0..a902165b8ba 100644 --- a/src/emu/cpu/drcuml.h +++ b/src/emu/cpu/drcuml.h @@ -142,10 +142,41 @@ enum /* floating point modes */ enum { - DRCUML_FMOD_TRUNC, /* truncate */ + DRCUML_FMOD_TRUNC = 0, /* truncate */ DRCUML_FMOD_ROUND, /* round */ DRCUML_FMOD_CEIL, /* round up */ - DRCUML_FMOD_FLOOR /* round down */ + DRCUML_FMOD_FLOOR, /* round down */ + DRCUML_FMOD_DEFAULT +}; + + +/* sizes */ +enum +{ + DRCUML_SIZE_BYTE = 0, /* 1-byte */ + DRCUML_SIZE_WORD, /* 2-byte */ + DRCUML_SIZE_DWORD, /* 4-byte */ + DRCUML_SIZE_QWORD, /* 8-byte */ + DRCUML_SIZE_SHORT = DRCUML_SIZE_DWORD, + DRCUML_SIZE_DOUBLE = DRCUML_SIZE_QWORD +}; + + +/* size/space combinations */ +enum +{ + DRCUML_SPSIZE_PROGRAM_BYTE = (ADDRESS_SPACE_PROGRAM * 16) + DRCUML_SIZE_BYTE, + DRCUML_SPSIZE_PROGRAM_WORD = (ADDRESS_SPACE_PROGRAM * 16) + DRCUML_SIZE_WORD, + DRCUML_SPSIZE_PROGRAM_DWORD = (ADDRESS_SPACE_PROGRAM * 16) + DRCUML_SIZE_DWORD, + DRCUML_SPSIZE_PROGRAM_QWORD = (ADDRESS_SPACE_PROGRAM * 16) + DRCUML_SIZE_QWORD, + DRCUML_SPSIZE_DATA_BYTE = (ADDRESS_SPACE_DATA * 16) + DRCUML_SIZE_BYTE, + DRCUML_SPSIZE_DATA_WORD = (ADDRESS_SPACE_DATA * 16) + DRCUML_SIZE_WORD, + DRCUML_SPSIZE_DATA_DWORD = (ADDRESS_SPACE_DATA * 16) + DRCUML_SIZE_DWORD, + DRCUML_SPSIZE_DATA_QWORD = (ADDRESS_SPACE_DATA * 16) + DRCUML_SIZE_QWORD, + DRCUML_SPSIZE_IO_BYTE = (ADDRESS_SPACE_IO * 16) + DRCUML_SIZE_BYTE, + DRCUML_SPSIZE_IO_WORD = (ADDRESS_SPACE_IO * 16) + DRCUML_SIZE_WORD, + DRCUML_SPSIZE_IO_DWORD = (ADDRESS_SPACE_IO * 16) + DRCUML_SIZE_DWORD, + DRCUML_SPSIZE_IO_QWORD = (ADDRESS_SPACE_IO * 16) + DRCUML_SIZE_QWORD }; @@ -175,50 +206,25 @@ enum _drcuml_opcode /* Internal Register Operations */ DRCUML_OP_SETFMOD, /* SETFMOD src */ DRCUML_OP_GETFMOD, /* GETFMOD dst */ - DRCUML_OP_GETEXP, /* GETEXP dst,index */ + DRCUML_OP_GETEXP, /* GETEXP dst */ + DRCUML_OP_GETFLGS, /* GETFLGS dst[,f] */ DRCUML_OP_SAVE, /* SAVE mem */ DRCUML_OP_RESTORE, /* RESTORE mem */ /* Integer Operations */ - DRCUML_OP_LOAD1U, /* LOAD1U dst,base,index */ - DRCUML_OP_LOAD1S, /* LOAD1S dst,base,index */ - DRCUML_OP_LOAD2U, /* LOAD2U dst,base,index */ - DRCUML_OP_LOAD2S, /* LOAD2S dst,base,index */ - DRCUML_OP_LOAD4U, /* LOAD4U dst,base,index */ - DRCUML_OP_LOAD4S, /* LOAD4S dst,base,index */ - DRCUML_OP_LOAD8U, /* LOAD8U dst,base,index */ - DRCUML_OP_STORE1, /* STORE1 base,index,src */ - DRCUML_OP_STORE2, /* STORE2 base,index,src */ - DRCUML_OP_STORE4, /* STORE4 base,index,src */ - DRCUML_OP_STORE8, /* STORE8 base,index,src */ - DRCUML_OP_READ1U, /* READ1U dst,space,src1 */ - DRCUML_OP_READ1S, /* READ1S dst,space,src1 */ - DRCUML_OP_READ2U, /* READ2U dst,space,src1 */ - DRCUML_OP_READ2S, /* READ2S dst,space,src1 */ - DRCUML_OP_READ2M, /* READ2M dst,space,src1,mask */ - DRCUML_OP_READ4U, /* READ4U dst,space,src1 */ - DRCUML_OP_READ4S, /* READ4S dst,space,src1 */ - DRCUML_OP_READ4M, /* READ4M dst,space,src1,mask */ - DRCUML_OP_READ8U, /* READ8U dst,space,src1 */ - DRCUML_OP_READ8M, /* READ8M dst,space,src1,mask */ - DRCUML_OP_WRITE1, /* WRITE1 space,dst,src1 */ - DRCUML_OP_WRITE2, /* WRITE2 space,dst,src1 */ - DRCUML_OP_WRIT2M, /* WRIT2M space,dst,mask,src1 */ - DRCUML_OP_WRITE4, /* WRITE4 space,dst,src1 */ - DRCUML_OP_WRIT4M, /* WRIT4M space,dst,mask,src1 */ - DRCUML_OP_WRITE8, /* WRITE8 space,dst,src1 */ - DRCUML_OP_WRIT8M, /* WRIT8M space,dst,mask,src1 */ - DRCUML_OP_SETC, /* SETC src,bitnum */ - DRCUML_OP_FLAGS, /* FLAGS dst,mask,table */ + DRCUML_OP_LOAD, /* LOAD dst,base,index,size */ + DRCUML_OP_LOADS, /* LOADS dst,base,index,size */ + DRCUML_OP_STORE, /* STORE base,index,src,size */ + DRCUML_OP_READ, /* READ dst,src1,space/size */ + DRCUML_OP_READM, /* READM dst,src1,mask,space/size */ + DRCUML_OP_WRITE, /* WRITE dst,src1,space/size */ + DRCUML_OP_WRITEM, /* WRITEM dst,mask,src1,space/size */ + DRCUML_OP_CARRY, /* CARRY src,bitnum */ + DRCUML_OP_SET, /* SET dst,c */ DRCUML_OP_MOV, /* MOV dst,src[,c] */ - DRCUML_OP_ZEXT1, /* ZEXT1 dst,src */ - DRCUML_OP_ZEXT2, /* ZEXT2 dst,src */ - DRCUML_OP_ZEXT4, /* ZEXT4 dst,src */ - DRCUML_OP_SEXT1, /* SEXT1 dst,src */ - DRCUML_OP_SEXT2, /* SEXT2 dst,src */ - DRCUML_OP_SEXT4, /* SEXT4 dst,src */ - DRCUML_OP_XTRACT, /* XTRACT dst,src,shift,mask */ - DRCUML_OP_INSERT, /* INSERT dst,src,shift,mask */ + DRCUML_OP_SEXT, /* SEXT dst,src,size */ + DRCUML_OP_ROLAND, /* ROLAND dst,src,shift,mask */ + DRCUML_OP_ROLINS, /* ROLINS dst,src,shift,mask */ DRCUML_OP_ADD, /* ADD dst,src1,src2[,f] */ DRCUML_OP_ADDC, /* ADDC dst,src1,src2[,f] */ DRCUML_OP_SUB, /* SUB dst,src1,src2[,f] */ @@ -247,21 +253,11 @@ enum _drcuml_opcode DRCUML_OP_FSTORE, /* FSTORE base,index,src */ DRCUML_OP_FREAD, /* FREAD dst,space,src1 */ DRCUML_OP_FWRITE, /* FWRITE space,dst,src1 */ - DRCUML_OP_FMOV, /* FSMOV dst,src1[,c] */ - DRCUML_OP_FTOI4, /* FTOI4 dst,src1 */ - DRCUML_OP_FTOI4T, /* FTOI4T dst,src1 */ - DRCUML_OP_FTOI4R, /* FTOI4R dst,src1 */ - DRCUML_OP_FTOI4F, /* FTOI4F dst,src1 */ - DRCUML_OP_FTOI4C, /* FTOI4C dst,src1 */ - DRCUML_OP_FTOI8, /* FTOI8 dst,src1 */ - DRCUML_OP_FTOI8T, /* FTOI8T dst,src1 */ - DRCUML_OP_FTOI8R, /* FTOI8R dst,src1 */ - DRCUML_OP_FTOI8F, /* FTOI8F dst,src1 */ - DRCUML_OP_FTOI8C, /* FTOI8C dst,src1 */ - DRCUML_OP_FFRFS, /* FFRFS dst,src1 */ - DRCUML_OP_FFRFD, /* FFRFD dst,src1 */ - DRCUML_OP_FFRI4, /* FFRI4 dst,src1 */ - DRCUML_OP_FFRI8, /* FFRI8 dst,src1 */ + DRCUML_OP_FMOV, /* FMOV dst,src1[,c] */ + DRCUML_OP_FTOINT, /* FTOINT dst,src1,size,round */ + DRCUML_OP_FFRINT, /* FFRINT dst,src1,size */ + DRCUML_OP_FFRFLT, /* FFRFLT dst,src1,size */ + DRCUML_OP_FRNDS, /* FRNDS dst,src1 */ DRCUML_OP_FADD, /* FADD dst,src1,src2 */ DRCUML_OP_FSUB, /* FSUB dst,src1,src2 */ DRCUML_OP_FCMP, /* FCMP src1,src2 */ diff --git a/src/emu/cpu/drcumld.c b/src/emu/cpu/drcumld.c index 127b3d8bcea..d64d50be1e2 100644 --- a/src/emu/cpu/drcumld.c +++ b/src/emu/cpu/drcumld.c @@ -43,7 +43,10 @@ static char *output_flags_cmptest(char *dest, int size, const drcuml_parameter * static char *output_param(char *dest, int size, const drcuml_parameter *param); static char *output_param_string(char *dest, int size, const drcuml_parameter *param); static char *output_param_handle(char *dest, int size, const drcuml_parameter *param); +static char *output_param_size(char *dest, int size, const drcuml_parameter *param); static char *output_param_space(char *dest, int size, const drcuml_parameter *param); +static char *output_param_space_size(char *dest, int size, const drcuml_parameter *param); +static char *output_param_round(char *dest, int size, const drcuml_parameter *param); @@ -89,49 +92,24 @@ static const drcuml_opdesc opcode_source_table[] = { DRCUML_OP_SETFMOD, "setfmod", { output_param } }, { DRCUML_OP_GETFMOD, "getfmod", { output_param } }, { DRCUML_OP_GETEXP, "getexp", { output_param } }, + { DRCUML_OP_GETFLGS, "getflgs", { output_param, output_flags } }, { DRCUML_OP_SAVE, "save", { output_param } }, { DRCUML_OP_RESTORE, "restore", { output_param } }, /* Integer Operations */ - { DRCUML_OP_LOAD1U, "!load1u", { output_param, output_param, output_param } }, - { DRCUML_OP_LOAD1S, "!load1s", { output_param, output_param, output_param } }, - { DRCUML_OP_LOAD2U, "!load2u", { output_param, output_param, output_param } }, - { DRCUML_OP_LOAD2S, "!load2s", { output_param, output_param, output_param } }, - { DRCUML_OP_LOAD4U, "!load4u", { output_param, output_param, output_param } }, - { DRCUML_OP_LOAD4S, "!load4s", { output_param, output_param, output_param } }, - { DRCUML_OP_LOAD8U, "!load8u", { output_param, output_param, output_param } }, - { DRCUML_OP_STORE1, "!store1", { output_param, output_param, output_param } }, - { DRCUML_OP_STORE2, "!store2", { output_param, output_param, output_param } }, - { DRCUML_OP_STORE4, "!store4", { output_param, output_param, output_param } }, - { DRCUML_OP_STORE8, "!store8", { output_param, output_param, output_param } }, - { DRCUML_OP_READ1U, "!read1u", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ1S, "!read1s", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ2U, "!read2u", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ2S, "!read2s", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ2M, "!read2m", { output_param, output_param_space, output_param, output_param } }, - { DRCUML_OP_READ4U, "!read4u", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ4S, "!read4s", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ4M, "!read4m", { output_param, output_param_space, output_param, output_param } }, - { DRCUML_OP_READ8U, "!read8u", { output_param, output_param_space, output_param } }, - { DRCUML_OP_READ8M, "!read8m", { output_param, output_param_space, output_param, output_param } }, - { DRCUML_OP_WRITE1, "!write1", { output_param_space, output_param, output_param } }, - { DRCUML_OP_WRITE2, "!write2", { output_param_space, output_param, output_param } }, - { DRCUML_OP_WRIT2M, "!writ2m", { output_param_space, output_param, output_param, output_param } }, - { DRCUML_OP_WRITE4, "!write4", { output_param_space, output_param, output_param } }, - { DRCUML_OP_WRIT4M, "!writ4m", { output_param_space, output_param, output_param, output_param } }, - { DRCUML_OP_WRITE8, "!write8", { output_param_space, output_param, output_param } }, - { DRCUML_OP_WRIT8M, "!writ8m", { output_param_space, output_param, output_param, output_param } }, - { DRCUML_OP_FLAGS, "!flags", { output_param, output_param, output_param } }, - { DRCUML_OP_SETC, "!setc", { output_param, output_param } }, + { DRCUML_OP_LOAD, "!load", { output_param, output_param, output_param, output_param_size } }, + { DRCUML_OP_LOADS, "!loads", { output_param, output_param, output_param, output_param_size } }, + { DRCUML_OP_STORE, "!store", { output_param, output_param, output_param, output_param_size } }, + { DRCUML_OP_READ, "!read", { output_param, output_param, output_param_space_size } }, + { DRCUML_OP_READM, "!readm", { output_param, output_param, output_param, output_param_space_size } }, + { DRCUML_OP_WRITE, "!write", { output_param, output_param, output_param_space_size } }, + { DRCUML_OP_WRITEM, "!writem", { output_param, output_param, output_param, output_param_space_size } }, + { DRCUML_OP_CARRY, "!carry", { output_param, output_param } }, + { DRCUML_OP_SET, "!set", { output_param, output_cond } }, { DRCUML_OP_MOV, "!mov", { output_param, output_param, output_cond } }, - { DRCUML_OP_ZEXT1, "!zext1", { output_param, output_param } }, - { DRCUML_OP_ZEXT2, "!zext2", { output_param, output_param } }, - { DRCUML_OP_ZEXT4, "!zext4", { output_param, output_param } }, - { DRCUML_OP_SEXT1, "!sext1", { output_param, output_param } }, - { DRCUML_OP_SEXT2, "!sext2", { output_param, output_param } }, - { DRCUML_OP_SEXT4, "!sext4", { output_param, output_param } }, - { DRCUML_OP_XTRACT, "!xtract", { output_param, output_param, output_param, output_param } }, - { DRCUML_OP_INSERT, "!insert", { output_param, output_param, output_param, output_param } }, + { DRCUML_OP_SEXT, "!sext", { output_param, output_param, output_param_size } }, + { DRCUML_OP_ROLAND, "!roland", { output_param, output_param, output_param, output_param } }, + { DRCUML_OP_ROLINS, "!rolins", { output_param, output_param, output_param, output_param } }, { DRCUML_OP_ADD, "!add", { output_param, output_param, output_param, output_flags } }, { DRCUML_OP_ADDC, "!addc", { output_param, output_param, output_param, output_flags } }, { DRCUML_OP_SUB, "!sub", { output_param, output_param, output_param, output_flags } }, @@ -158,23 +136,13 @@ static const drcuml_opdesc opcode_source_table[] = /* Floating-Point Operations */ { DRCUML_OP_FLOAD, "f!load", { output_param, output_param, output_param } }, { DRCUML_OP_FSTORE, "f!store", { output_param, output_param, output_param } }, - { DRCUML_OP_FREAD, "f!read", { output_param, output_param_space, output_param } }, - { DRCUML_OP_FWRITE, "f!write", { output_param_space, output_param, output_param } }, + { DRCUML_OP_FREAD, "f!read", { output_param, output_param, output_param_space } }, + { DRCUML_OP_FWRITE, "f!write", { output_param, output_param, output_param_space } }, { DRCUML_OP_FMOV, "f!mov", { output_param, output_param, output_cond } }, - { DRCUML_OP_FTOI4, "f!toi4", { output_param, output_param } }, - { DRCUML_OP_FTOI4T, "f!toi4t", { output_param, output_param } }, - { DRCUML_OP_FTOI4R, "f!toi4r", { output_param, output_param } }, - { DRCUML_OP_FTOI4F, "f!toi4f", { output_param, output_param } }, - { DRCUML_OP_FTOI4C, "f!toi4c", { output_param, output_param } }, - { DRCUML_OP_FTOI8, "f!toi8", { output_param, output_param } }, - { DRCUML_OP_FTOI8T, "f!toi8t", { output_param, output_param } }, - { DRCUML_OP_FTOI8R, "f!toi8r", { output_param, output_param } }, - { DRCUML_OP_FTOI8F, "f!toi8f", { output_param, output_param } }, - { DRCUML_OP_FTOI8C, "f!toi8c", { output_param, output_param } }, - { DRCUML_OP_FFRFS, "f!frfs", { output_param, output_param } }, - { DRCUML_OP_FFRFD, "f!frfd", { output_param, output_param } }, - { DRCUML_OP_FFRI4, "f!fri4", { output_param, output_param } }, - { DRCUML_OP_FFRI8, "f!fri8", { output_param, output_param } }, + { DRCUML_OP_FTOINT, "f!toint", { output_param, output_param, output_param_size, output_param_round } }, + { DRCUML_OP_FFRINT, "f!frint", { output_param, output_param, output_param_size } }, + { DRCUML_OP_FFRFLT, "f!frflt", { output_param, output_param, output_param_size } }, + { DRCUML_OP_FRNDS, "f!rnds", { output_param, output_param } }, { DRCUML_OP_FADD, "f!add", { output_param, output_param, output_param } }, { DRCUML_OP_FSUB, "f!sub", { output_param, output_param, output_param } }, { DRCUML_OP_FCMP, "f!cmp", { output_param, output_param, output_flags_cmptest } }, @@ -448,6 +416,22 @@ static char *output_param_handle(char *dest, int size, const drcuml_parameter *p /*------------------------------------------------- + output_param_size - output parameter 0, + assuming it is size +-------------------------------------------------*/ + +static char *output_param_size(char *dest, int size, const drcuml_parameter *param) +{ + if (param->type == DRCUML_PTYPE_IMMEDIATE) + { + static const char *strings[] = { "byte", "word", "dword", "qword" }; + return dest + sprintf(dest, "%s", strings[param->value & 3]); + } + return output_param(dest, size, param); +} + + +/*------------------------------------------------- output_param_space - output parameter 0, assuming it is an address space -------------------------------------------------*/ @@ -458,3 +442,36 @@ static char *output_param_space(char *dest, int size, const drcuml_parameter *pa return dest + sprintf(dest, "%s", address_space_names[param->value]); return output_param(dest, size, param); } + + +/*------------------------------------------------- + output_param_space_size - output parameter 0, + assuming it is an address space/size combo +-------------------------------------------------*/ + +static char *output_param_space_size(char *dest, int size, const drcuml_parameter *param) +{ + if (param->type == DRCUML_PTYPE_IMMEDIATE && param->value / 16 >= ADDRESS_SPACE_PROGRAM && param->value / 16 <= ADDRESS_SPACE_IO) + { + dest += sprintf(dest, "%s_", address_space_names[param->value / 16]); + return output_param_size(dest, size, param); + } + + return output_param(dest, size, param); +} + + +/*------------------------------------------------- + output_param_round - output parameter 0, + assuming it is a rounding mode +-------------------------------------------------*/ + +static char *output_param_round(char *dest, int size, const drcuml_parameter *param) +{ + if (param->type == DRCUML_PTYPE_IMMEDIATE && param->value >= DRCUML_FMOD_TRUNC && param->value <= DRCUML_FMOD_DEFAULT) + { + static const char *strings[] = { "trunc", "round", "ceil", "floor", "default" }; + return dest + sprintf(dest, "%s", strings[param->value]); + } + return output_param(dest, size, param); +} diff --git a/src/emu/cpu/drcumlsh.h b/src/emu/cpu/drcumlsh.h index a3543aaee7e..452b55ce319 100644 --- a/src/emu/cpu/drcumlsh.h +++ b/src/emu/cpu/drcumlsh.h @@ -132,49 +132,29 @@ #define UML_SETFMOD(block, mode) do { drcuml_block_append_1(block, DRCUML_OP_SETFMOD, 4, IF_ALWAYS, mode); } while (0) #define UML_GETFMOD(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETFMOD, 4, IF_ALWAYS, dst); } while (0) #define UML_GETEXP(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_GETEXP, 4, IF_ALWAYS, dst); } while (0) +#define UML_GETFLGS(block, dst, flags) do { drcuml_block_append_1(block, DRCUML_OP_GETFLGS, 4, flags, dst); } while (0) #define UML_SAVE(block, dst) do { drcuml_block_append_1(block, DRCUML_OP_SAVE, 4, IF_ALWAYS, MEM(dst)); } while (0) #define UML_RESTORE(block, src) do { drcuml_block_append_1(block, DRCUML_OP_RESTORE, 4, IF_ALWAYS, MEM(src)); } while (0) /* ----- 32-Bit Integer Operations ----- */ -#define UML_LOAD1U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1U, 4, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_LOAD1S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1S, 4, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_LOAD2U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2U, 4, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_LOAD2S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2S, 4, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_LOAD4(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD4U, 4, IF_ALWAYS, dst, MEM(base), index); } while (0) - -#define UML_STORE1(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE1, 4, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_STORE2(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE2, 4, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_STORE4(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE4, 4, IF_ALWAYS, MEM(base), index, src1); } while (0) - -#define UML_READ1U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1U, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_READ1S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1S, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_READ2U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2U, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_READ2S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2S, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_READ2M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ2M, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0) -#define UML_READ4(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ4U, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_READ4M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ4M, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0) - -#define UML_WRITE1(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE1, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_WRITE2(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE2, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_WRIT2M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT2M, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0) -#define UML_WRITE4(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE4, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_WRIT4M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT4M, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0) - -#define UML_FLAGS(block, dst, mask, table) do { drcuml_block_append_3(block, DRCUML_OP_FLAGS, 4, IF_ALWAYS, dst, IMM(mask), MEM(table)); } while (0) -#define UML_SETC(block, src, bitnum) do { drcuml_block_append_2(block, DRCUML_OP_SETC, 4, IF_ALWAYS, src, bitnum); } while (0) +#define UML_LOAD(block, dst, base, index, size) do { drcuml_block_append_4(block, DRCUML_OP_LOAD, 4, IF_ALWAYS, dst, MEM(base), index, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_LOADS(block, dst, base, index, size) do { drcuml_block_append_4(block, DRCUML_OP_LOADS, 4, IF_ALWAYS, dst, MEM(base), index, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_STORE(block, base, index, src1, size) do { drcuml_block_append_4(block, DRCUML_OP_STORE, 4, IF_ALWAYS, MEM(base), index, src1, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_READ(block, dst, src1, spsize) do { drcuml_block_append_3(block, DRCUML_OP_READ, 4, IF_ALWAYS, dst, src1, IMM(DRCUML_SPSIZE_##spsize)); } while (0) +#define UML_READM(block, dst, src1, mask, spsize) do { drcuml_block_append_4(block, DRCUML_OP_READM, 4, IF_ALWAYS, dst, src1, mask, IMM(DRCUML_SPSIZE_##spsize)); } while (0) +#define UML_WRITE(block, dst, src1, spsize) do { drcuml_block_append_3(block, DRCUML_OP_WRITE, 4, IF_ALWAYS, dst, src1, IMM(DRCUML_SPSIZE_##spsize)); } while (0) +#define UML_WRITEM(block, dst, src1, mask, spsize) do { drcuml_block_append_4(block, DRCUML_OP_WRITEM, 4, IF_ALWAYS, dst, src1, mask, IMM(DRCUML_SPSIZE_##spsize)); } while (0) + +#define UML_CARRY(block, src, bitnum) do { drcuml_block_append_2(block, DRCUML_OP_CARRY, 4, IF_ALWAYS, src, bitnum); } while (0) +#define UML_SETc(block, cond, dst) do { drcuml_block_append_1(block, DRCUML_OP_SET, 4, cond, dst); } while (0) #define UML_MOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 4, IF_ALWAYS, dst, src1); } while (0) #define UML_MOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 4, cond, dst, src1); } while (0) +#define UML_SEXT(block, dst, src1, size) do { drcuml_block_append_3(block, DRCUML_OP_SEXT, 4, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size)); } while (0) -#define UML_ZEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT1, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_ZEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT2, 4, IF_ALWAYS, dst, src1); } while (0) - -#define UML_SEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT1, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_SEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT2, 4, IF_ALWAYS, dst, src1); } while (0) - -#define UML_XTRACT(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_XTRACT, 4, IF_ALWAYS, dst, src, shift, mask); } while (0) -#define UML_INSERT(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_INSERT, 4, IF_ALWAYS, dst, src, shift, mask); } while (0) +#define UML_ROLAND(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_ROLAND, 4, IF_ALWAYS, dst, src, shift, mask); } while (0) +#define UML_ROLINS(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_ROLINS, 4, IF_ALWAYS, dst, src, shift, mask); } while (0) #define UML_NEG(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 4, FLAGS_NONE, dst, src1); } while (0) #define UML_NEGf(block, dst, src1, flags) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 4, flags, dst, src1); } while (0) @@ -238,53 +218,23 @@ /* ----- 64-Bit Integer Operations ----- */ -#define UML_DLOAD1U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_DLOAD1S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD1S, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_DLOAD2U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_DLOAD2S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD2S, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_DLOAD4U(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD4U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_DLOAD4S(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD4S, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) -#define UML_DLOAD8(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_LOAD8U, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) - -#define UML_DSTORE1(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE1, 8, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_DSTORE2(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE2, 8, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_DSTORE4(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE4, 8, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_DSTORE8(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_STORE8, 8, IF_ALWAYS, MEM(base), index, src1); } while (0) - -#define UML_DREAD1U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD1S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ1S, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD2U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD2S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ2S, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD2M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ2M, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0) -#define UML_DREAD4U(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ4U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD4S(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ4S, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD4M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ4M, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0) -#define UML_DREAD8(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_READ8U, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_DREAD8M(block, dst, space, src1, mask) do { drcuml_block_append_4(block, DRCUML_OP_READ8M, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1, mask); } while (0) - -#define UML_DWRITE1(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE1, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_DWRITE2(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE2, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_DWRIT2M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT2M, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0) -#define UML_DWRITE4(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE4, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_DWRIT4M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT4M, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0) -#define UML_DWRITE8(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_WRITE8, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) -#define UML_DWRIT8M(block, space, dst, mask, src1) do { drcuml_block_append_4(block, DRCUML_OP_WRIT8M, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, mask, src1); } while (0) - -#define UML_DFLAGS(block, dst, mask, table) do { drcuml_block_append_3(block, DRCUML_OP_FLAGS, 8, IF_ALWAYS, dst, IMM(mask), MEM(table)); } while (0) +#define UML_DLOAD(block, dst, base, index, size) do { drcuml_block_append_4(block, DRCUML_OP_LOAD, 8, IF_ALWAYS, dst, MEM(base), index, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_DLOADS(block, dst, base, index, size) do { drcuml_block_append_4(block, DRCUML_OP_LOADS, 8, IF_ALWAYS, dst, MEM(base), index, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_DSTORE(block, base, index, src1, size) do { drcuml_block_append_4(block, DRCUML_OP_STORE, 8, IF_ALWAYS, MEM(base), index, src1, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_DREAD(block, dst, src1, spsize) do { drcuml_block_append_3(block, DRCUML_OP_READ, 8, IF_ALWAYS, dst, src1, IMM(DRCUML_SPSIZE_##spsize)); } while (0) +#define UML_DREADM(block, dst, src1, mask, spsize) do { drcuml_block_append_4(block, DRCUML_OP_READM, 8, IF_ALWAYS, dst, src1, mask, IMM(DRCUML_SPSIZE_##spsize)); } while (0) +#define UML_DWRITE(block, dst, src1, spsize) do { drcuml_block_append_3(block, DRCUML_OP_WRITE, 8, IF_ALWAYS, dst, src1, IMM(DRCUML_SPSIZE_##spsize)); } while (0) +#define UML_DWRITEM(block, dst, src1, mask, spsize) do { drcuml_block_append_4(block, DRCUML_OP_WRITEM, 8, IF_ALWAYS, dst, src1, mask, IMM(DRCUML_SPSIZE_##spsize)); } while (0) + +#define UML_DCARRY(block, src, bitnum) do { drcuml_block_append_2(block, DRCUML_OP_CARRY, 8, IF_ALWAYS, src, bitnum); } while (0) +#define UML_DSETc(block, cond, dst) do { drcuml_block_append_1(block, DRCUML_OP_SET, 8, cond, dst); } while (0) #define UML_DMOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 8, IF_ALWAYS, dst, src1); } while (0) #define UML_DMOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_MOV, 8, cond, dst, src1); } while (0) +#define UML_DSEXT(block, dst, src1, size) do { drcuml_block_append_3(block, DRCUML_OP_SEXT, 8, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size)); } while (0) -#define UML_DZEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT1, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_DZEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT2, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_DZEXT4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_ZEXT4, 8, IF_ALWAYS, dst, src1); } while (0) - -#define UML_DSEXT1(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT1, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_DSEXT2(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT2, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_DSEXT4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_SEXT4, 8, IF_ALWAYS, dst, src1); } while (0) - -#define UML_DXTRACT(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_XTRACT, 8, IF_ALWAYS, dst, src, shift, mask); } while (0) -#define UML_DINSERT(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_INSERT, 8, IF_ALWAYS, dst, src, shift, mask); } while (0) +#define UML_DROLAND(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_ROLAND, 8, IF_ALWAYS, dst, src, shift, mask); } while (0) +#define UML_DROLINS(block, dst, src, shift, mask) do { drcuml_block_append_4(block, DRCUML_OP_ROLINS, 8, IF_ALWAYS, dst, src, shift, mask); } while (0) #define UML_DNEG(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 8, FLAGS_NONE, dst, src1); } while (0) #define UML_DNEGf(block, dst, src1, flags) do { drcuml_block_append_2(block, DRCUML_OP_NEG, 8, flags, dst, src1); } while (0) @@ -348,26 +298,15 @@ #define UML_FSLOAD(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_FLOAD, 4, IF_ALWAYS, dst, MEM(base), index); } while (0) #define UML_FSSTORE(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_FSTORE, 4, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_FSREAD(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_FREAD, 4, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_FSWRITE(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_FWRITE, 4, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) +#define UML_FSREAD(block, dst, src1, space) do { drcuml_block_append_3(block, DRCUML_OP_FREAD, 4, IF_ALWAYS, dst, src1, IMM(ADDRESS_SPACE_##space)); } while (0) +#define UML_FSWRITE(block, dst, src1, space) do { drcuml_block_append_3(block, DRCUML_OP_FWRITE, 4, IF_ALWAYS, dst, src1, IMM(ADDRESS_SPACE_##space)); } while (0) #define UML_FSMOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 4, IF_ALWAYS, dst, src1); } while (0) #define UML_FSMOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 4, cond, dst, src1); } while (0) -#define UML_FSTOI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI4T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4T, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI4R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4R, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI4C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4C, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI4F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4F, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI8T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8T, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI8R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8R, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI8C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8C, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSTOI8F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8F, 4, IF_ALWAYS, dst, src1); } while (0) - -#define UML_FSFRFD(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRFD, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSFRI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI4, 4, IF_ALWAYS, dst, src1); } while (0) -#define UML_FSFRI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI8, 4, IF_ALWAYS, dst, src1); } while (0) +#define UML_FSTOINT(block, dst, src1, size, round) do { drcuml_block_append_4(block, DRCUML_OP_FTOINT, 4, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size), IMM(DRCUML_FMOD_##round)); } while (0) +#define UML_FSFRINT(block, dst, src1, size) do { drcuml_block_append_3(block, DRCUML_OP_FFRINT, 4, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_FSFRFLT(block, dst, src1, size) do { drcuml_block_append_3(block, DRCUML_OP_FFRFLT, 4, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size)); } while (0) #define UML_FSADD(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FADD, 4, FLAGS_NONE, dst, src1, src2); } while (0) #define UML_FSSUB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FSUB, 4, FLAGS_NONE, dst, src1, src2); } while (0) @@ -385,26 +324,17 @@ #define UML_FDLOAD(block, dst, base, index) do { drcuml_block_append_3(block, DRCUML_OP_FLOAD, 8, IF_ALWAYS, dst, MEM(base), index); } while (0) #define UML_FDSTORE(block, base, index, src1) do { drcuml_block_append_3(block, DRCUML_OP_FSTORE, 8, IF_ALWAYS, MEM(base), index, src1); } while (0) -#define UML_FDREAD(block, dst, space, src1) do { drcuml_block_append_3(block, DRCUML_OP_FREAD, 8, IF_ALWAYS, dst, IMM(ADDRESS_SPACE_##space), src1); } while (0) -#define UML_FDWRITE(block, space, dst, src1) do { drcuml_block_append_3(block, DRCUML_OP_FWRITE, 8, IF_ALWAYS, IMM(ADDRESS_SPACE_##space), dst, src1); } while (0) +#define UML_FDREAD(block, dst, src1, space) do { drcuml_block_append_3(block, DRCUML_OP_FREAD, 8, IF_ALWAYS, dst, src1, IMM(ADDRESS_SPACE_##space)); } while (0) +#define UML_FDWRITE(block, dst, src1, space) do { drcuml_block_append_3(block, DRCUML_OP_FWRITE, 8, IF_ALWAYS, dst, src1, IMM(ADDRESS_SPACE_##space)); } while (0) #define UML_FDMOV(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 8, IF_ALWAYS, dst, src1); } while (0) #define UML_FDMOVc(block, cond, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FMOV, 8, cond, dst, src1); } while (0) -#define UML_FDTOI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI4T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4T, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI4R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4R, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI4C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4C, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI4F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI4F, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI8T(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8T, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI8R(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8R, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI8C(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8C, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDTOI8F(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FTOI8F, 8, IF_ALWAYS, dst, src1); } while (0) - -#define UML_FDFRFS(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRFS, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDFRI4(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI4, 8, IF_ALWAYS, dst, src1); } while (0) -#define UML_FDFRI8(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FFRI8, 8, IF_ALWAYS, dst, src1); } while (0) +#define UML_FDTOINT(block, dst, src1, size, round) do { drcuml_block_append_4(block, DRCUML_OP_FTOINT, 8, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size), IMM(DRCUML_FMOD_##round)); } while (0) +#define UML_FDFRINT(block, dst, src1, size) do { drcuml_block_append_3(block, DRCUML_OP_FFRINT, 8, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size)); } while (0) +#define UML_FDFRFLT(block, dst, src1, size) do { drcuml_block_append_3(block, DRCUML_OP_FFRFLT, 8, IF_ALWAYS, dst, src1, IMM(DRCUML_SIZE_##size)); } while (0) + +#define UML_FDRNDS(block, dst, src1) do { drcuml_block_append_2(block, DRCUML_OP_FRNDS, 8, FLAGS_NONE, dst, src1); } while (0) #define UML_FDADD(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FADD, 8, FLAGS_NONE, dst, src1, src2); } while (0) #define UML_FDSUB(block, dst, src1, src2) do { drcuml_block_append_3(block, DRCUML_OP_FSUB, 8, FLAGS_NONE, dst, src1, src2); } while (0) diff --git a/src/emu/cpu/i386/i386dasm.c b/src/emu/cpu/i386/i386dasm.c index 6de76c8f64f..a418e3233a5 100644 --- a/src/emu/cpu/i386/i386dasm.c +++ b/src/emu/cpu/i386/i386dasm.c @@ -1764,7 +1764,7 @@ static void handle_fpu(char *s, UINT8 op1, UINT8 op2) switch ((op2 >> 3) & 0x7) { case 0: sprintf(s, "fild dword ptr %s", modrm_string); break; - case 1: sprintf(s, "??? (FPU)"); break; + case 1: sprintf(s, "fisttp dword ptr %s", modrm_string); break; case 2: sprintf(s, "fist dword ptr %s", modrm_string); break; case 3: sprintf(s, "fistp dword ptr %s", modrm_string); break; case 4: sprintf(s, "??? (FPU)"); break; @@ -1861,7 +1861,7 @@ static void handle_fpu(char *s, UINT8 op1, UINT8 op2) switch ((op2 >> 3) & 0x7) { case 0: sprintf(s, "fld qword ptr %s", modrm_string); break; - case 1: sprintf(s, "??? (FPU)"); break; + case 1: sprintf(s, "fisttp qword ptr %s", modrm_string); break; case 2: sprintf(s, "fst qword ptr %s", modrm_string); break; case 3: sprintf(s, "fstp qword ptr %s", modrm_string); break; case 4: sprintf(s, "frstor %s", modrm_string); break; @@ -1954,7 +1954,7 @@ static void handle_fpu(char *s, UINT8 op1, UINT8 op2) switch ((op2 >> 3) & 0x7) { case 0: sprintf(s, "fild word ptr %s", modrm_string); break; - case 1: sprintf(s, "??? (FPU)"); break; + case 1: sprintf(s, "fisttp word ptr %s", modrm_string); break; case 2: sprintf(s, "fist word ptr %s", modrm_string); break; case 3: sprintf(s, "fistp word ptr %s", modrm_string); break; case 4: sprintf(s, "fbld %s", modrm_string); break; diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c index e56276e5b3a..e6f677929ab 100644 --- a/src/emu/cpu/mips/mips3drc.c +++ b/src/emu/cpu/mips/mips3drc.c @@ -117,7 +117,8 @@ extern unsigned dasmmips3(char *buffer, unsigned pc, UINT32 op); #define CPR264(reg) MEM(&mips3->cpr[2][reg]) #define CCR264(reg) MEM(&mips3->ccr[2][reg]) -#define FCCMASK(which) fcc_mask[(mips3->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)] +#define FCCMASK(which) ((UINT32)(1 << fcc_shift[(mips3->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)])) +#define FCCSHIFT(which) fcc_shift[(mips3->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : ((which) & 7)] @@ -177,15 +178,6 @@ struct _mips3imp_state /* 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 */ /* register mappings */ drcuml_parameter regmap[34]; /* parameter to register mappings for all 32 integer registers */ @@ -270,7 +262,7 @@ static mips3_state *mips3; /* 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 }; +static const UINT8 fcc_shift[8] = { 23, 25, 26, 27, 28, 29, 30, 31 }; /* lookup table for FP modes */ static const UINT8 fpmode_source[4] = @@ -281,339 +273,6 @@ static const UINT8 fpmode_source[4] = 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 -}; - /*************************************************************************** @@ -738,15 +397,6 @@ static void mips3_init(mips3_flavor flavor, int bigendian, int index, int clock, /* allocate memory for cache-local state and initialize it */ memcpy(mips3->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); - memcpy(mips3->impstate->slt_table, slt_table_source, sizeof(slt_table_source)); - memcpy(mips3->impstate->sltu_table, sltu_table_source, sizeof(sltu_table_source)); - memcpy(mips3->impstate->c_un_table, c_un_table_source, sizeof(c_un_table_source)); - memcpy(mips3->impstate->c_eq_table, c_eq_table_source, sizeof(c_eq_table_source)); - memcpy(mips3->impstate->c_ueq_table, c_ueq_table_source, sizeof(c_ueq_table_source)); - memcpy(mips3->impstate->c_olt_table, c_olt_table_source, sizeof(c_olt_table_source)); - memcpy(mips3->impstate->c_ult_table, c_ult_table_source, sizeof(c_ult_table_source)); - memcpy(mips3->impstate->c_ole_table, c_ole_table_source, sizeof(c_ole_table_source)); - memcpy(mips3->impstate->c_ule_table, c_ule_table_source, sizeof(c_ule_table_source)); /* compute the register parameters */ for (regnum = 0; regnum < 34; regnum++) @@ -1259,7 +909,7 @@ static void static_generate_entry_point(drcuml_state *drcuml) /* reset the FPU mode */ UML_AND(block, IREG(0), CCR132(31), IMM(3)); // and i0,ccr1[31],3 - UML_LOAD1U(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0)); // load1u i0,fpmode,i0 + UML_LOAD(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0), BYTE); // load i0,fpmode,i0,byte UML_SETFMOD(block, IREG(0)); // setfmod i0 /* load fast integer registers */ @@ -1370,7 +1020,7 @@ static void static_generate_tlb_mismatch(drcuml_state *drcuml) UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC UML_MOV(block, MEM(&mips3->pc), IREG(0)); // mov <pc>,i0 UML_SHR(block, IREG(1), IREG(0), IMM(12)); // shr i1,i0,12 - UML_LOAD4(block, IREG(1), mips3->tlb_table, IREG(1)); // load4 i1,[tlb_table],i1 + UML_LOAD(block, IREG(1), mips3->tlb_table, IREG(1), DWORD); // load i1,[tlb_table],i1,dword if (PRINTF_MMU) { UML_MOV(block, MEM(&mips3->impstate->arg0), IREG(0)); // mov [arg0],i0 @@ -1433,8 +1083,8 @@ static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) { /* set the upper bits of EntryHi and the lower bits of Context to the fault page */ - UML_INSERT(block, CPR032(COP0_EntryHi), IREG(0), IMM(0), IMM(0xffffe000)); // insert [EntryHi],i0,0,0xffffe000 - UML_INSERT(block, CPR032(COP0_Context), IREG(0), IMM(32-9), IMM(0x7fffff)); // insert [Context],i0,32-9,0x7fffff + UML_ROLINS(block, CPR032(COP0_EntryHi), IREG(0), IMM(0), IMM(0xffffe000)); // rolins [EntryHi],i0,0,0xffffe000 + UML_ROLINS(block, CPR032(COP0_Context), IREG(0), IMM(32-9), IMM(0x7fffff)); // rolins [Context],i0,32-9,0x7fffff } /* set the EPC and Cause registers */ @@ -1458,7 +1108,7 @@ static void static_generate_exception(drcuml_state *drcuml, UINT8 exception, int if (exception == EXCEPTION_BADCOP) { UML_GETEXP(block, IREG(0)); // getexp i0 - UML_INSERT(block, CPR032(COP0_Cause), IREG(0), IMM(28), IMM(0x30000000)); // insert [Cause],i0,28,0x30000000 + UML_ROLINS(block, CPR032(COP0_Cause), IREG(0), IMM(28), IMM(0x30000000)); // rolins [Cause],i0,28,0x30000000 } /* set EXL in the SR */ @@ -1536,10 +1186,10 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int /* 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->tlb_table, IREG(3)); // load4 i3,[tlb_table],i3 + UML_LOAD(block, IREG(3), mips3->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword UML_TEST(block, IREG(3), IMM(iswrite ? TLB_DIRTY : TLB_VALID)); // test i3,iswrite ? TLB_DIRTY : TLB_VALID UML_JMPc(block, IF_Z, tlbmiss = label++); // jmp tlbmiss,z - UML_INSERT(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // insert i0,i3,0,0xfffff000 + UML_ROLINS(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // rolins i0,i3,0,0xfffff000 for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) if (!Machine->debug_mode && mips3->impstate->fastram[ramnum].base != NULL && (!iswrite || !mips3->impstate->fastram[ramnum].readonly)) @@ -1563,24 +1213,24 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int { UML_XOR(block, IREG(0), IREG(0), IMM(mips3->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 + UML_LOAD(block, IREG(0), fastbase, IREG(0), BYTE); // load i0,fastbase,i0,byte } 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->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 + UML_LOAD(block, IREG(0), fastbase, IREG(0), WORD); // load i0,fastbase,i0,word } 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 + UML_LOAD(block, IREG(0), fastbase, IREG(0), DWORD); // load i0,fastbase,i0,dword } 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_DLOAD(block, IREG(0), fastbase, IREG(0), QWORD); // dload i0,fastbase,i0,qword UML_DROR(block, IREG(0), IREG(0), IMM(32 * (mips3->bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)))); // dror i0,i0,32*bytexor } @@ -1592,26 +1242,26 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int { UML_XOR(block, IREG(0), IREG(0), IMM(mips3->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 + UML_STORE(block, fastbase, IREG(0), IREG(1), BYTE); // store fastbase,i0,i1,byte } 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->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 + UML_STORE(block, fastbase, IREG(0), IREG(1), WORD); // store fastbase,i0,i1,word } 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_INSERT(block, IREG(3), IREG(1), IMM(0), IREG(2)); // insert i3,i1,0,i2 - UML_STORE4(block, fastbase, IREG(0), IREG(3)); // store4 fastbase,i0,i3 + UML_LOAD(block, IREG(3), fastbase, IREG(0), DWORD); // load i3,fastbase,i0,dword + UML_ROLINS(block, IREG(3), IREG(1), IMM(0), IREG(2)); // rolins i3,i1,0,i2 + UML_STORE(block, fastbase, IREG(0), IREG(3), DWORD); // store fastbase,i0,i3,dword } else - UML_STORE4(block, fastbase, IREG(0), IREG(1)); // store4 fastbase,i0,i1 + UML_STORE(block, fastbase, IREG(0), IREG(1), DWORD); // store fastbase,i0,i1,dword } else if (size == 8) { @@ -1622,12 +1272,12 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int { UML_DROR(block, IREG(2), IREG(2), IMM(32 * (mips3->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_DINSERT(block, IREG(3), IREG(1), IMM(0), IREG(2)); // dinsert i3,i1,0,i2 - UML_DSTORE8(block, fastbase, IREG(0), IREG(3)); // dstore8 fastbase,i0,i3 + UML_DLOAD(block, IREG(3), fastbase, IREG(0), QWORD); // dload i3,fastbase,i0,qword + UML_DROLINS(block, IREG(3), IREG(1), IMM(0), IREG(2)); // drolins i3,i1,0,i2 + UML_DSTORE(block, fastbase, IREG(0), IREG(3), QWORD); // dstore fastbase,i0,i3,qword } else - UML_DSTORE8(block, fastbase, IREG(0), IREG(1)); // dstore8 fastbase,i0,i1 + UML_DSTORE(block, fastbase, IREG(0), IREG(1), QWORD); // dstore fastbase,i0,i1,qword } UML_RET(block); // ret } @@ -1639,32 +1289,32 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int { case 1: if (iswrite) - UML_WRITE1(block, PROGRAM, IREG(0), IREG(1)); // write1 i0,i1 + UML_WRITE(block, IREG(0), IREG(1), PROGRAM_BYTE); // write i0,i1,program_byte else - UML_READ1U(block, IREG(0), PROGRAM, IREG(0)); // read1u i0,i0 + UML_READ(block, IREG(0), IREG(0), PROGRAM_BYTE); // read i0,i0,program_byte break; case 2: if (iswrite) - UML_WRITE2(block, PROGRAM, IREG(0), IREG(1)); // write2 i0,i1 + UML_WRITE(block, IREG(0), IREG(1), PROGRAM_WORD); // write i0,i1,program_word else - UML_READ2U(block, IREG(0), PROGRAM, IREG(0)); // read2u i0,i0 + UML_READ(block, IREG(0), IREG(0), PROGRAM_WORD); // read i0,i0,program_word break; case 4: if (iswrite) { if (!ismasked) - UML_WRITE4(block, PROGRAM, IREG(0), IREG(1)); // write4 PROGRAM,i0,i1 + UML_WRITE(block, IREG(0), IREG(1), PROGRAM_DWORD); // write i0,i1,program_dword else - UML_WRIT4M(block, PROGRAM, IREG(0), IREG(2), IREG(1)); // writ4m PROGRAM,i0,i2,i1 + UML_WRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_DWORD); // writem i0,i2,i1,program_dword } else { if (!ismasked) - UML_READ4(block, IREG(0), PROGRAM, IREG(0)); // read4 i0,PROGRAM,i0 + UML_READ(block, IREG(0), IREG(0), PROGRAM_DWORD); // read i0,i0,program_dword else - UML_READ4M(block, IREG(0), PROGRAM, IREG(0), IREG(2)); // read4m i0,PROGRAM,i0,i2 + UML_READM(block, IREG(0), IREG(0), IREG(2), PROGRAM_DWORD); // readm i0,i0,i2,program_dword } break; @@ -1672,16 +1322,16 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int if (iswrite) { if (!ismasked) - UML_DWRITE8(block, PROGRAM, IREG(0), IREG(1)); // dwrite8 PROGRAM,i0,i1 + UML_DWRITE(block, IREG(0), IREG(1), PROGRAM_QWORD); // dwrite i0,i1,program_qword else - UML_DWRIT8M(block, PROGRAM, IREG(0), IREG(2), IREG(1)); // dwrit8m PROGRAM,i0,i2,i1 + UML_DWRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_QWORD); // dwritem i0,i2,i1,program_qword } else { if (!ismasked) - UML_DREAD8(block, IREG(0), PROGRAM, IREG(0)); // dread8 i0,PROGRAM,i0 + UML_DREAD(block, IREG(0), IREG(0), PROGRAM_QWORD); // dread i0,i0,program_qword else - UML_DREAD8M(block, IREG(0), PROGRAM, IREG(0), IREG(2)); // dread8m i0,PROGRAM,i0,i2 + UML_DREADM(block, IREG(0), IREG(0), IREG(2), PROGRAM_QWORD); // dreadm i0,i0,i2,program_qword } break; } @@ -1717,10 +1367,10 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int static void generate_update_mode(drcuml_block *block) { - UML_XTRACT(block, IREG(2), IREG(0), IMM(32-2), IMM(0x06)); // xtract i2,i0,32-2,0x06 + UML_ROLAND(block, IREG(2), IREG(0), IMM(32-2), IMM(0x06)); // roland i2,i0,32-2,0x06 UML_TEST(block, IREG(0), IMM(SR_EXL | SR_ERL)); // test i0,SR_EXL | SR_ERL UML_MOVc(block, IF_NZ, IREG(2), IMM(0)); // mov i2,0,nz - UML_INSERT(block, IREG(2), IREG(0), IMM(32-26), IMM(0x01)); // insert i2,i0,32-26,0x01 + UML_ROLINS(block, IREG(2), IREG(0), IMM(32-26), IMM(0x01)); // rolins i2,i0,32-26,0x01 UML_MOV(block, MEM(&mips3->impstate->mode), IREG(2)); // mov [mode],i2 } @@ -1797,7 +1447,7 @@ static void generate_checksum_block(drcuml_block *block, compiler_state *compile { if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) { - UML_LOAD4(block, IREG(0), seqhead->opptr.l, IMM(0)); // load4 i0,*opptr + UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,0,dword UML_CMP(block, IREG(0), IMM(*seqhead->opptr.l)); // cmp i0,*opptr UML_EXHc(block, IF_NE, mips3->impstate->nocode, IMM(epc(seqhead))); // exne nocode,seqhead->pc } @@ -1810,18 +1460,18 @@ static void generate_checksum_block(drcuml_block *block, compiler_state *compile for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { - UML_LOAD4(block, IREG(0), curdesc->opptr.l, IMM(0)); // load4 i0,*opptr + UML_LOAD(block, IREG(0), curdesc->opptr.l, IMM(0), DWORD); // load i0,*opptr,0,dword UML_CMP(block, IREG(0), IMM(*curdesc->opptr.l)); // cmp i0,*opptr UML_EXHc(block, IF_NE, mips3->impstate->nocode, IMM(epc(seqhead))); // exne nocode,seqhead->pc } #else UINT32 sum = 0; - UML_LOAD4(block, IREG(0), seqhead->opptr.l, IMM(0)); // load4 i0,*opptr + UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,0,dword sum += *seqhead->opptr.l; for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) { - UML_LOAD4(block, IREG(1), curdesc->opptr.l, IMM(0)); // load4 i1,*opptr + UML_LOAD(block, IREG(1), curdesc->opptr.l, IMM(0), DWORD); // load i1,*opptr,dword UML_ADD(block, IREG(0), IREG(0), IREG(1)); // add i0,i0,i1 sum += *curdesc->opptr.l; } @@ -1906,7 +1556,7 @@ static void generate_sequence_instruction(drcuml_block *block, compiler_state *c UML_MOV(block, MEM(&mips3->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc UML_CALLC(block, cfunc_printf_debug, "Checking TLB at @ %08X\n"); // callc printf_debug } - UML_LOAD4(block, IREG(0), &mips3->tlb_table[desc->pc >> 12], IMM(0)); // load4 i0,tlb_table[desc->pc >> 12] + UML_LOAD(block, IREG(0), &mips3->tlb_table[desc->pc >> 12], IMM(0), DWORD);// load i0,tlb_table[desc->pc >> 12],0,dword UML_CMP(block, IREG(0), IMM(mips3->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry UML_EXHc(block, IF_NE, mips3->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE } @@ -1951,7 +1601,7 @@ static void generate_delay_slot_and_branch(drcuml_block *block, compiler_state * /* set the link if needed */ if (linkreg != 0) - UML_DSEXT4(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dsext4 <linkreg>,desc->pc + 8 + UML_DMOV(block, R64(linkreg), IMM((INT32)(desc->pc + 8))); // dmov <linkreg>,desc->pc + 8 /* compile the delay slot using temporary compiler state */ assert(desc->delay != NULL); @@ -2061,7 +1711,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const case 0x0f: /* LUI - MIPS I */ if (RTREG != 0) - UML_DSEXT4(block, R64(RTREG), IMM(SIMMVAL << 16)); // dsext4 <rtreg>,SIMMVAL << 16 + UML_DMOV(block, R64(RTREG), IMM(SIMMVAL << 16)); // dmov <rtreg>,SIMMVAL << 16 return TRUE; case 0x08: /* ADDI - MIPS I */ @@ -2074,14 +1724,14 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0,dword 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 + UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0,dword } return TRUE; @@ -2122,8 +1772,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const if (RTREG != 0) { UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL - UML_DFLAGS(block, R64(RTREG), (UINT64)~0, mips3->impstate->slt_table); - // dflags <rtreg>,~0,slt_table + UML_DSETc(block, IF_L, R64(RTREG)); // dset <rtreg>,l } return TRUE; @@ -2131,8 +1780,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const if (RTREG != 0) { UML_DCMP(block, R64(RSREG), IMM(SIMMVAL)); // dcmp <rsreg>,SIMMVAL - UML_DFLAGS(block, R64(RTREG), (UINT64)~0, mips3->impstate->sltu_table); - // dflags <rtreg>,~0,sltu_table + UML_DSETc(block, IF_B, R64(RTREG)); // dset <rtreg>,b } return TRUE; @@ -2143,7 +1791,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read8[mips3->impstate->mode >> 1]); // callh read8 if (RTREG != 0) - UML_DSEXT1(block, R64(RTREG), IREG(0)); // dsext1 <rtreg>,i0 + UML_DSEXT(block, R64(RTREG), IREG(0), BYTE); // dsext <rtreg>,i0,byte if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2152,7 +1800,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read16[mips3->impstate->mode >> 1]); // callh read16 if (RTREG != 0) - UML_DSEXT2(block, R64(RTREG), IREG(0)); // dsext2 <rtreg>,i0 + UML_DSEXT(block, R64(RTREG), IREG(0), WORD); // dsext <rtreg>,i0,word if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2161,7 +1809,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read32[mips3->impstate->mode >> 1]); // callh read32 if (RTREG != 0) - UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0 + UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0 if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2170,7 +1818,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read8[mips3->impstate->mode >> 1]); // callh read8 if (RTREG != 0) - UML_DZEXT1(block, R64(RTREG), IREG(0)); // dzext1 <rtreg>,i0 + UML_DAND(block, R64(RTREG), IREG(0), IMM(0xff)); // dand <rtreg>,i0,0xff if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2179,7 +1827,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read16[mips3->impstate->mode >> 1]); // callh read16 if (RTREG != 0) - UML_DZEXT2(block, R64(RTREG), IREG(0)); // dzext2 <rtreg>,i0 + UML_DAND(block, R64(RTREG), IREG(0), IMM(0xffff)); // dand <rtreg>,i0,0xffff if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2188,7 +1836,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read32[mips3->impstate->mode >> 1]); // callh read32 if (RTREG != 0) - UML_DZEXT4(block, R64(RTREG), IREG(0)); // dzext4 <rtreg>,i0 + UML_DAND(block, R64(RTREG), IREG(0), IMM(0xffffffff)); // dand <rtreg>,i0,0xffffffff if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2214,8 +1862,8 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const { UML_SHL(block, IREG(2), IMM(~0), IREG(1)); // shl i2,~0,i1 UML_MOV(block, IREG(3), R32(RTREG)); // mov i3,<rtreg> - UML_INSERT(block, IREG(3), IREG(0), IREG(1), IREG(2)); // insert i3,i0,i1,i2 - UML_DSEXT4(block, R64(RTREG), IREG(3)); // dsext4 <rtreg>,i3 + UML_ROLINS(block, IREG(3), IREG(0), IREG(1), IREG(2)); // rolins i3,i0,i1,i2 + UML_DSEXT(block, R64(RTREG), IREG(3), DWORD); // dsext <rtreg>,i3,dword } if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); @@ -2234,8 +1882,8 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const UML_SHR(block, IREG(2), IMM(~0), IREG(1)); // shr i2,~0,i1 UML_SUB(block, IREG(1), IMM(32), IREG(1)); // sub i1,32,i1 UML_MOV(block, IREG(3), R32(RTREG)); // mov i3,<rtreg> - UML_INSERT(block, IREG(3), IREG(0), IREG(1), IREG(2)); // insert i3,i0,i1,i2 - UML_DSEXT4(block, R64(RTREG), IREG(3)); // dsext4 <rtreg>,i3 + UML_ROLINS(block, IREG(3), IREG(0), IREG(1), IREG(2)); // rolins i3,i0,i1,i2 + UML_DSEXT(block, R64(RTREG), IREG(3), DWORD); // dsext <rtreg>,i3,dword } if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); @@ -2252,7 +1900,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const if (RTREG != 0) { UML_DSHL(block, IREG(2), IMM((UINT64)~0), IREG(1)); // dshl i2,~0,i1 - UML_DINSERT(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // dinsert <rtreg>,i0,i1,i2 + UML_DROLINS(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // drolins <rtreg>,i0,i1,i2 } if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); @@ -2270,7 +1918,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const { UML_DSHR(block, IREG(2), IMM((UINT64)~0), IREG(1)); // dshr i2,~0,i1 UML_SUB(block, IREG(1), IMM(64), IREG(1)); // sub i1,64,i1 - UML_DINSERT(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // dinsert <rtreg>,i0,i1,i2 + UML_DROLINS(block, R64(RTREG), IREG(0), IREG(1), IREG(2)); // drolins <rtreg>,i0,i1,i2 } if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); @@ -2295,7 +1943,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const case 0x32: /* LWC2 - MIPS I */ UML_ADD(block, IREG(0), R32(RSREG), IMM(SIMMVAL)); // add i0,<rsreg>,SIMMVAL UML_CALLH(block, mips3->impstate->read32[mips3->impstate->mode >> 1]); // callh read32 - UML_DZEXT4(block, CPR264(RTREG), IREG(0)); // dzext4 <cpr2_rt>,i0 + UML_DAND(block, CPR264(RTREG), IREG(0), IMM(0xffffffff)); // dand <cpr2_rt>,i0,0xffffffff if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); return TRUE; @@ -2486,7 +2134,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2494,7 +2142,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2502,7 +2150,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2510,7 +2158,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2518,7 +2166,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2526,7 +2174,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2585,12 +2233,12 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const UML_EXHc(block, IF_V, mips3->impstate->exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0,V if (RDREG != 0) - UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2598,7 +2246,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2627,12 +2275,12 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const UML_EXHc(block, IF_V, mips3->impstate->exception[EXCEPTION_OVERFLOW], IMM(0)); // exh overflow,0,V if (RDREG != 0) - UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 <rdreg>,i0 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2640,7 +2288,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext <rdreg>,i0,dword } return TRUE; @@ -2664,14 +2312,14 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword 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 + UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword return TRUE; case 0x1c: /* DMULT - MIPS III */ @@ -2684,14 +2332,14 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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 + UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword 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 + UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword return TRUE; case 0x1e: /* DDIV - MIPS III */ @@ -2735,7 +2383,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const if (RDREG != 0) { UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg> - UML_DFLAGS(block, R64(RDREG), (UINT64)~0, mips3->impstate->slt_table);// dflags <rdreg>,~0,slt_table + UML_DSETc(block, IF_L, R64(RDREG)); // dset <rdreg>,l } return TRUE; @@ -2743,7 +2391,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const if (RDREG != 0) { UML_DCMP(block, R64(RSREG), R64(RTREG)); // dcmp <rsreg>,<rtreg> - UML_DFLAGS(block, R64(RDREG), (UINT64)~0, mips3->impstate->sltu_table);// dflags <rdreg>,~0,sltu_table + UML_DSETc(block, IF_B, R64(RDREG)); // dset <rdreg>,b } return TRUE; @@ -2802,7 +2450,7 @@ static int generate_special(drcuml_block *block, compiler_state *compiler, const 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_TEST(block, CCR132(31), IMM(FCCMASK(op >> 18))); // test ccr31,fcc_mask[x] UML_DMOVc(block, ((op >> 16) & 1) ? IF_NZ : IF_Z, R64(RDREG), R64(RSREG)); // mov <rdreg>,<rsreg>,NZ/Z } @@ -2961,8 +2609,8 @@ static int generate_idt(drcuml_block *block, compiler_state *compiler, const opc UML_MULS(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // muls i0,i1,rsreg,rtreg UML_ADDf(block, FLAGS_C, IREG(0), IREG(0), LO32); // add i0,i0,lo UML_ADDC(block, IREG(1), IREG(1), HI32); // addc i1,i1,hi - UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 - UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i0 + UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword } return TRUE; @@ -2972,8 +2620,8 @@ static int generate_idt(drcuml_block *block, compiler_state *compiler, const opc UML_MULU(block, IREG(0), IREG(1), R32(RSREG), R32(RTREG)); // mulu i0,i1,rsreg,rtreg UML_ADDf(block, FLAGS_C, IREG(0), IREG(0), LO32); // add i0,i0,lo UML_ADDC(block, IREG(1), IREG(1), HI32); // addc i1,i1,hi - UML_DSEXT4(block, LO64, IREG(0)); // dsext4 lo,i0 - UML_DSEXT4(block, HI64, IREG(1)); // dsext4 hi,i0 + UML_DSEXT(block, LO64, IREG(0), DWORD); // dsext lo,i0,dword + UML_DSEXT(block, HI64, IREG(1), DWORD); // dsext hi,i1,dword } return TRUE; @@ -2981,7 +2629,7 @@ static int generate_idt(drcuml_block *block, compiler_state *compiler, const opc if (RDREG != 0) { UML_MULS(block, IREG(0), IREG(0), R32(RSREG), R32(RTREG)); // muls i0,i0,rsreg,rtreg - UML_DSEXT4(block, R64(RDREG), IREG(0)); // dsext4 rdreg,i0 + UML_DSEXT(block, R64(RDREG), IREG(0), DWORD); // dsext rdreg,i0,dword } return TRUE; } @@ -3002,7 +2650,7 @@ static int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, switch (reg) { case COP0_Cause: - UML_INSERT(block, CPR032(COP0_Cause), IREG(0), IMM(0), IMM(~0xfc00)); // insert [Cause],i0,0,~0xfc00 + UML_ROLINS(block, CPR032(COP0_Cause), IREG(0), IMM(0), IMM(~0xfc00)); // rolins [Cause],i0,0,~0xfc00 compiler->checksoftints = TRUE; if (!in_delay_slot) generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); @@ -3025,7 +2673,7 @@ static int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, generate_update_cycles(block, compiler, IMM(desc->pc), !in_delay_slot); // <subtract cycles> UML_MOV(block, CPR032(COP0_Count), IREG(0)); // mov [Count],i0 UML_CALLC(block, cfunc_get_cycles, &mips3->impstate->numcycles); // callc cfunc_get_cycles,&mips3->impstate->numcycles - UML_DZEXT4(block, IREG(0), IREG(0)); // dzext4 i0,i0 + UML_DAND(block, IREG(0), IREG(0), IMM(0xffffffff)); // and i0,i0,0xffffffff UML_DADD(block, IREG(0), IREG(0), IREG(0)); // dadd i0,i0,i0 UML_DSUB(block, MEM(&mips3->count_zero_time), MEM(&mips3->impstate->numcycles), IREG(0)); // dsub [count_zero_time],[mips3->impstate->numcycles],i0 @@ -3043,7 +2691,7 @@ static int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler, return TRUE; case COP0_Config: - UML_INSERT(block, CPR032(COP0_Config), IREG(0), IMM(0), IMM(0x0007)); // insert [Config],i0,0,0x0007 + UML_ROLINS(block, CPR032(COP0_Config), IREG(0), IMM(0), IMM(0x0007)); // rolins [Config],i0,0,0x0007 return TRUE; case COP0_EntryHi: @@ -3080,7 +2728,7 @@ static int generate_get_cop0_reg(drcuml_block *block, compiler_state *compiler, UML_DSUB(block, IREG(0), MEM(&mips3->impstate->numcycles), MEM(&mips3->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 + UML_DSEXT(block, IREG(0), IREG(0), DWORD); // dsext i0,i0,dword return TRUE; case COP0_Random: @@ -3091,18 +2739,18 @@ static int generate_get_cop0_reg(drcuml_block *block, compiler_state *compiler, 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_DAND(block, IREG(2), IREG(2), IMM(0xffffffff)); // dand i2,i2,0xffffffff 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_DMOV(block, IREG(0), IMM(47)); // dmov i0,47 UML_LABEL(block, link2); // link2: return TRUE; default: - UML_DSEXT4(block, IREG(0), CPR032(reg)); // dsext4 i0,cpr0[reg] + UML_DSEXT(block, IREG(0), CPR032(reg), DWORD); // dsext i0,cpr0[reg],dword return TRUE; } } @@ -3131,7 +2779,7 @@ static int generate_cop0(drcuml_block *block, compiler_state *compiler, const op if (RTREG != 0) { generate_get_cop0_reg(block, compiler, desc, RDREG); // <get cop0 reg> - UML_DSEXT4(block, R64(RTREG), IREG(0)); // dsext4 <rtreg>,i0 + UML_DSEXT(block, R64(RTREG), IREG(0), DWORD); // dsext <rtreg>,i0,dword } return TRUE; @@ -3145,11 +2793,11 @@ static int generate_cop0(drcuml_block *block, compiler_state *compiler, const op case 0x02: /* CFCz */ if (RTREG != 0) - UML_DSEXT4(block, R64(RTREG), CCR032(RDREG)); // dsext4 <rtreg>,ccr0[rdreg] + UML_DSEXT(block, R64(RTREG), CCR032(RDREG), DWORD); // dsext <rtreg>,ccr0[rdreg],dword return TRUE; case 0x04: /* MTCz */ - UML_DSEXT4(block, IREG(0), R32(RTREG)); // dsext4 i0,<rtreg> + UML_DSEXT(block, IREG(0), R32(RTREG), DWORD); // dsext i0,<rtreg>,dword generate_set_cop0_reg(block, compiler, desc, RDREG); // <set cop0 reg> return TRUE; @@ -3159,7 +2807,7 @@ static int generate_cop0(drcuml_block *block, compiler_state *compiler, const op return TRUE; case 0x06: /* CTCz */ - UML_DSEXT4(block, CCR064(RDREG), R32(RTREG)); // dsext4 ccr0[rdreg],<rtreg> + UML_DSEXT(block, CCR064(RDREG), R32(RTREG), DWORD); // dsext ccr0[rdreg],<rtreg>,dword return TRUE; case 0x10: @@ -3254,7 +2902,7 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op { case 0x00: /* MFCz - MIPS I */ if (RTREG != 0) - UML_DSEXT4(block, R64(RTREG), FPR32(RDREG)); // dsext4 <rtreg>,fpr[rdreg] + UML_DSEXT(block, R64(RTREG), FPR32(RDREG), DWORD); // dsext <rtreg>,fpr[rdreg],dword return TRUE; case 0x01: /* DMFCz - MIPS III */ @@ -3264,7 +2912,7 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op case 0x02: /* CFCz - MIPS I */ if (RTREG != 0) - UML_DSEXT4(block, R64(RTREG), CCR132(RDREG)); // dsext4 <rtreg>,ccr132[rdreg] + UML_DSEXT(block, R64(RTREG), CCR132(RDREG), DWORD); // dsext <rtreg>,ccr132[rdreg],dword return TRUE; case 0x04: /* MTCz - MIPS I */ @@ -3277,15 +2925,15 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op case 0x06: /* CTCz - MIPS I */ if (RDREG != 31) - UML_DSEXT4(block, CCR164(RDREG), R32(RTREG)); // dsext4 ccr1[rdreg],<rtreg> + UML_DSEXT(block, CCR164(RDREG), R32(RTREG), DWORD); // dsext ccr1[rdreg],<rtreg>,dword 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_DSEXT(block, CCR164(31), R32(RTREG), DWORD); // dsext ccr1[31],<rtreg>,dword 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->impstate->fpmode[0], IREG(0)); // load1u i0,fpmode,i0 + UML_LOAD(block, IREG(0), &mips3->impstate->fpmode[0], IREG(0), BYTE);// load i0,fpmode,i0,byte UML_SETFMOD(block, IREG(0)); // setfmod i0 UML_LABEL(block, skip); // skip: } @@ -3373,58 +3021,58 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op case 0x08: if (IS_SINGLE(op)) /* ROUND.L.S - MIPS III */ - UML_FSTOI8R(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8r <fdreg>,<fsreg> + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, ROUND);// fstoint <fdreg>,<fsreg>,qword,round else /* ROUND.L.D - MIPS III */ - UML_FDTOI8R(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8r <fdreg>,<fsreg> + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, ROUND);// fdtoint <fdreg>,<fsreg>,qword,round return TRUE; case 0x09: if (IS_SINGLE(op)) /* TRUNC.L.S - MIPS III */ - UML_FSTOI8T(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8t <fdreg>,<fsreg> + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, TRUNC);// fstoint <fdreg>,<fsreg>,qword,trunc else /* TRUNC.L.D - MIPS III */ - UML_FDTOI8T(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8t <fdreg>,<fsreg> + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, TRUNC);// fdtoint <fdreg>,<fsreg>,qword,trunc return TRUE; case 0x0a: if (IS_SINGLE(op)) /* CEIL.L.S - MIPS III */ - UML_FSTOI8C(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8c <fdreg>,<fsreg> + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, CEIL);// fstoint <fdreg>,<fsreg>,qword,ceil else /* CEIL.L.D - MIPS III */ - UML_FDTOI8C(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8c <fdreg>,<fsreg> + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, CEIL);// fdtoint <fdreg>,<fsreg>,qword,ceil return TRUE; case 0x0b: if (IS_SINGLE(op)) /* FLOOR.L.S - MIPS III */ - UML_FSTOI8F(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8f <fdreg>,<fsreg> + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, FLOOR);// fstoint <fdreg>,<fsreg>,qword,floor else /* FLOOR.L.D - MIPS III */ - UML_FDTOI8F(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8f <fdreg>,<fsreg> + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, FLOOR);// fdtoint <fdreg>,<fsreg>,qword,floor return TRUE; case 0x0c: if (IS_SINGLE(op)) /* ROUND.W.S - MIPS II */ - UML_FSTOI4R(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4r <fdreg>,<fsreg> + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, ROUND);// fstoint <fdreg>,<fsreg>,dword,round else /* ROUND.W.D - MIPS II */ - UML_FDTOI4R(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4r <fdreg>,<fsreg> + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, ROUND);// fdtoint <fdreg>,<fsreg>,dword,round return TRUE; case 0x0d: if (IS_SINGLE(op)) /* TRUNC.W.S - MIPS II */ - UML_FSTOI4T(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4t <fdreg>,<fsreg> + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, TRUNC);// fstoint <fdreg>,<fsreg>,dword,trunc else /* TRUNC.W.D - MIPS II */ - UML_FDTOI4T(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4t <fdreg>,<fsreg> + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, TRUNC);// fdtoint <fdreg>,<fsreg>,dword,trunc return TRUE; case 0x0e: if (IS_SINGLE(op)) /* CEIL.W.S - MIPS II */ - UML_FSTOI4C(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4c <fdreg>,<fsreg> + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, CEIL);// fstoint <fdreg>,<fsreg>,dword,ceil else /* CEIL.W.D - MIPS II */ - UML_FDTOI4C(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4c <fdreg>,<fsreg> + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, CEIL);// fdtoint <fdreg>,<fsreg>,dword,ceil return TRUE; case 0x0f: if (IS_SINGLE(op)) /* FLOOR.W.S - MIPS II */ - UML_FSTOI4F(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4f <fdreg>,<fsreg> + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, FLOOR);// fstoint <fdreg>,<fsreg>,dword,floor else /* FLOOR.W.D - MIPS II */ - UML_FDTOI4F(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4f <fdreg>,<fsreg> + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, FLOOR);// fdtoint <fdreg>,<fsreg>,dword,floor return TRUE; case 0x11: @@ -3470,38 +3118,38 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op if (IS_INTEGRAL(op)) { if (IS_SINGLE(op)) /* CVT.S.W - MIPS I */ - UML_FSFRI4(block, FPR32(FDREG), FPR32(FSREG)); // fsfri4 <fdreg>,<fsreg> + UML_FSFRINT(block, FPR32(FDREG), FPR32(FSREG), DWORD); // fsfrint <fdreg>,<fsreg>,dword else /* CVT.S.L - MIPS I */ - UML_FSFRI8(block, FPR32(FDREG), FPR64(FSREG)); // fsfri8 <fdreg>,<fsreg> + UML_FSFRINT(block, FPR32(FDREG), FPR64(FSREG), QWORD); // fsfrint <fdreg>,<fsreg>,qword } else /* CVT.S.D - MIPS I */ - UML_FSFRFD(block, FPR32(FDREG), FPR64(FSREG)); // fsfrfd <fdreg>,<fsreg> + UML_FSFRFLT(block, FPR32(FDREG), FPR64(FSREG), QWORD); // fsfrflt <fdreg>,<fsreg>,qword 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> + UML_FDFRINT(block, FPR64(FDREG), FPR32(FSREG), DWORD); // fdfrint <fdreg>,<fsreg>,dword else /* CVT.D.L - MIPS I */ - UML_FDFRI8(block, FPR64(FDREG), FPR64(FSREG)); // fdfri8 <fdreg>,<fsreg> + UML_FDFRINT(block, FPR64(FDREG), FPR64(FSREG), QWORD); // fdfrint <fdreg>,<fsreg>,qword } else /* CVT.D.S - MIPS I */ - UML_FDFRFS(block, FPR64(FDREG), FPR32(FSREG)); // fdfrfs <fdreg>,<fsreg> + UML_FDFRFLT(block, FPR64(FDREG), FPR32(FSREG), DWORD); // fdfrflt <fdreg>,<fsreg>,dword return TRUE; case 0x24: if (IS_SINGLE(op)) /* CVT.W.S - MIPS I */ - UML_FSTOI4(block, FPR32(FDREG), FPR32(FSREG)); // fstoi4 <fdreg>,<fsreg> + UML_FSTOINT(block, FPR32(FDREG), FPR32(FSREG), DWORD, DEFAULT);// fstoint <fdreg>,<fsreg>,dword,default else /* CVT.W.D - MIPS I */ - UML_FDTOI4(block, FPR32(FDREG), FPR64(FSREG)); // fdtoi4 <fdreg>,<fsreg> + UML_FDTOINT(block, FPR32(FDREG), FPR64(FSREG), DWORD, DEFAULT);// fdtoint <fdreg>,<fsreg>,dword,default return TRUE; case 0x25: if (IS_SINGLE(op)) /* CVT.L.S - MIPS I */ - UML_FSTOI8(block, FPR64(FDREG), FPR32(FSREG)); // fstoi8 <fdreg>,<fsreg> + UML_FSTOINT(block, FPR64(FDREG), FPR32(FSREG), QWORD, DEFAULT);// fstoint <fdreg>,<fsreg>,qword,default else /* CVT.L.D - MIPS I */ - UML_FDTOI8(block, FPR64(FDREG), FPR64(FSREG)); // fdtoi8 <fdreg>,<fsreg> + UML_FDTOINT(block, FPR64(FDREG), FPR64(FSREG), QWORD, DEFAULT);// fdtoint <fdreg>,<fsreg>,qword,default return TRUE; case 0x30: @@ -3515,8 +3163,9 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_un_table); - // flags ccr31,fccmask[op],c_eq_table + UML_SETc(block, IF_U, IREG(0)); // set i0,u + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; case 0x32: @@ -3525,8 +3174,9 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_eq_table); - // flags ccr31,fccmask[op],c_eq_table + UML_SETc(block, IF_E, IREG(0)); // set i0,e + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; case 0x33: @@ -3535,8 +3185,11 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_ueq_table); - // flags ccr31,fccmask[op],c_eq_table + UML_SETc(block, IF_U, IREG(0)); // set i0,u + UML_SETc(block, IF_E, IREG(1)); // set i1,e + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; case 0x34: @@ -3545,8 +3198,9 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_olt_table); - // flags ccr31,fccmask[op],c_lt_table + UML_SETc(block, IF_B, IREG(0)); // set i0,b + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; case 0x35: @@ -3555,8 +3209,11 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_ult_table); - // flags ccr31,fccmask[op],c_lt_table + UML_SETc(block, IF_U, IREG(0)); // set i0,u + UML_SETc(block, IF_B, IREG(1)); // set i1,b + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; case 0x36: @@ -3565,8 +3222,9 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_ole_table); - // flags ccr31,fccmask[op],c_le_table + UML_SETc(block, IF_BE, IREG(0)); // set i0,be + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; case 0x37: @@ -3575,8 +3233,11 @@ static int generate_cop1(drcuml_block *block, compiler_state *compiler, const op 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->impstate->c_ule_table); - // flags ccr31,fccmask[op],c_le_table + UML_SETc(block, IF_U, IREG(0)); // set i0,u + UML_SETc(block, IF_BE, IREG(1)); // set i1,be + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 + UML_ROLINS(block, CCR132(31), IREG(0), IMM(FCCSHIFT(op >> 8)), IMM(FCCMASK(op >> 8))); + // rolins ccr31,i0,fccshift,fcc return TRUE; } break; diff --git a/src/emu/cpu/powerpc/ppc.c b/src/emu/cpu/powerpc/ppc.c index b70785941ca..80b4a3087a4 100644 --- a/src/emu/cpu/powerpc/ppc.c +++ b/src/emu/cpu/powerpc/ppc.c @@ -4,6 +4,79 @@ #include "ppc.h" #include "debugger.h" +// PLL Configuration based on the table in MPC603EUM page 7-31 +static const int mpc603e_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, -1, 0x0, -1 }, + { -1, -1, -1, -1, -1, 0xc, -1, 0xc, -1 }, + { 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, -1, -1, -1 }, + { -1, -1, -1, 0x6, 0x6, -1, -1, -1, -1 }, + { -1, -1, 0x8, 0x8, -1, -1, -1, -1, -1 }, + { -1, 0xe, 0xe, -1, -1, -1, -1, -1, -1 }, + { 0xa, 0xa, 0xa, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, +}; + +// PLL Configuration based on the table in MPC603E7VEC page 29 +static const int mpc603ev_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + // 2:1 + { -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4 }, + // 2.5:1 + { -1, -1, -1, -1, -1, 0x6, 0x6, 0x6, 0x6 }, + // 3:1 + { -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8, 0x8 }, + // 3.5:1 + { -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe, -1 }, + // 4:1 + { -1, -1, -1, 0xa, 0xa, 0xa, 0xa, -1, -1 }, + // 4.5:1 + { -1, -1, -1, 0x7, 0x7, 0x7, -1, -1, -1 }, + // 5:1 + { -1, -1, 0xb, 0xb, 0xb, -1, -1, -1, -1 }, + // 5.5:1 + { -1, -1, 0x9, 0x9, 0x9, -1, -1, -1, -1 }, + // 6:1 + { -1, -1, 0xd, 0xd, 0xd, -1, -1, -1, -1 } +}; + +// PLL Configuration based on the table in MPC603E7TEC page 23 +static const int mpc603r_pll_config[12][9] = +{ + // 16, 20, 25, 33, 40, 50, 60, 66, 75 + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, + // 2:1 + { -1, -1, -1, -1, 0x5, 0x5, 0x5, 0x5, 0x5 }, + // 2.5:1 + { -1, -1, -1, -1, -1, -1, 0x6, 0x6, 0x6 }, + // 3:1 + { -1, -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8 }, + // 3.5:1 + { -1, -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe }, + // 4:1 + { -1, -1, -1, -1, 0xa, 0xa, 0xa, 0xa, 0xa }, + // 4.5:1 + { -1, -1, -1, 0x7, 0x7, 0x7, 0x7, 0x7, -1 }, + // 5:1 + { -1, -1, -1, 0xb, 0xb, 0xb, 0xb, -1, -1 }, + // 5.5:1 + { -1, -1, -1, 0x9, 0x9, 0x9, -1, -1, -1 }, + // 6:1 + { -1, -1, 0xd, 0xd, 0xd, 0xd, -1, -1, -1 }, +}; + + #if (HAS_PPC603 || HAS_PPC601 || HAS_PPC604) static void ppc603_exception(int exception); #endif diff --git a/src/emu/cpu/powerpc/ppc.h b/src/emu/cpu/powerpc/ppc.h index ac00204fd2f..161ac2dbd92 100644 --- a/src/emu/cpu/powerpc/ppc.h +++ b/src/emu/cpu/powerpc/ppc.h @@ -1,164 +1,24 @@ -#ifndef _PPC_H -#define _PPC_H +/*************************************************************************** + + ppc.h + Interface file for the portable MIPS III/IV emulator. + Written by Aaron Giles + +***************************************************************************/ + +#ifndef __PPC_H__ +#define __PPC_H__ #include "cpuintrf.h" -#define SPR_XER 1 /* Fixed Point Exception Register Read / Write */ -#define SPR_LR 8 /* Link Register Read / Write */ -#define SPR_CTR 9 /* Count Register Read / Write */ -#define SPR_SRR0 26 /* Save/Restore Register 0 Read / Write */ -#define SPR_SRR1 27 /* Save/Restore Register 1 Read / Write */ -#define SPR_SPRG0 272 /* SPR General 0 Read / Write */ -#define SPR_SPRG1 273 /* SPR General 1 Read / Write */ -#define SPR_SPRG2 274 /* SPR General 2 Read / Write */ -#define SPR_SPRG3 275 /* SPR General 3 Read / Write */ -#define SPR_PVR 287 /* Processor Version Number Read Only */ - -#define SPR403_ICDBDR 0x3D3 /* 406GA Instruction Cache Debug Data Register Rad Only */ -#define SPR403_ESR 0x3D4 /* 406GA Exception Syndrome Register Read / Write */ -#define SPR403_DEAR 0x3D5 /* 406GA Data Exception Address Register Read Only */ -#define SPR403_EVPR 0x3D6 /* 406GA Exception Vector Prefix Register Read / Write */ -#define SPR403_CDBCR 0x3D7 /* 406GA Cache Debug Control Register Read/Write */ -#define SPR403_TSR 0x3D8 /* 406GA Timer Status Register Read / Clear */ -#define SPR403_TCR 0x3DA /* 406GA Timer Control Register Read / Write */ -#define SPR403_PIT 0x3DB /* 406GA Programmable Interval Timer Read / Write */ -#define SPR403_TBHI 988 /* 406GA Time Base High Read / Write */ -#define SPR403_TBLO 989 /* 406GA Time Base Low Read / Write */ -#define SPR403_SRR2 0x3DE /* 406GA Save/Restore Register 2 Read / Write */ -#define SPR403_SRR3 0x3DF /* 406GA Save/Restore Register 3 Read / Write */ -#define SPR403_DBSR 0x3F0 /* 406GA Debug Status Register Read / Clear */ -#define SPR403_DBCR 0x3F2 /* 406GA Debug Control Register Read / Write */ -#define SPR403_IAC1 0x3F4 /* 406GA Instruction Address Compare 1 Read / Write */ -#define SPR403_IAC2 0x3F5 /* 406GA Instruction Address Compare 2 Read / Write */ -#define SPR403_DAC1 0x3F6 /* 406GA Data Address Compare 1 Read / Write */ -#define SPR403_DAC2 0x3F7 /* 406GA Data Address Compare 2 Read / Write */ -#define SPR403_DCCR 0x3FA /* 406GA Data Cache Cacheability Register Read / Write */ -#define SPR403_ICCR 0x3FB /* 406GA I Cache Cacheability Registe Read / Write */ -#define SPR403_PBL1 0x3FC /* 406GA Protection Bound Lower 1 Read / Write */ -#define SPR403_PBU1 0x3FD /* 406GA Protection Bound Upper 1 Read / Write */ -#define SPR403_PBL2 0x3FE /* 406GA Protection Bound Lower 2 Read / Write */ -#define SPR403_PBU2 0x3FF /* 406GA Protection Bound Upper 2 Read / Write */ - -#define SPR403_SGR 0x3b9 /* 403GCX Storage Guarded Register */ -#define SPR403_DCWR 0x3ba /* 403GCX Data Cache Write Through */ -#define SPR403_PID 0x3b1 /* 403GCX Process ID */ -#define SPR403_TBHU 0x3cc /* 403GCX Time Base High User-mode */ -#define SPR403_TBLU 0x3cd /* 403GCX Time Base Low User-mode */ - -#define SPR603E_DSISR 18 /* 603E */ -#define SPR603E_DAR 19 /* 603E */ -#define SPR603E_DEC 22 /* 603E */ -#define SPR603E_SDR1 25 /* 603E */ -#define SPR603E_TBL_R 268 /* 603E Time Base Low (Read-only) */ -#define SPR603E_TBU_R 269 /* 603E Time Base High (Read-only) */ -#define SPR603E_TBL_W 284 /* 603E Time Base Low (Write-only) */ -#define SPR603E_TBU_W 285 /* 603E Time Base Hight (Write-only) */ -#define SPR603E_EAR 282 /* 603E */ -#define SPR603E_IBAT0U 528 /* 603E */ -#define SPR603E_IBAT0L 529 /* 603E */ -#define SPR603E_IBAT1U 530 /* 603E */ -#define SPR603E_IBAT1L 531 /* 603E */ -#define SPR603E_IBAT2U 532 /* 603E */ -#define SPR603E_IBAT2L 533 /* 603E */ -#define SPR603E_IBAT3U 534 /* 603E */ -#define SPR603E_IBAT3L 535 /* 603E */ -#define SPR603E_DBAT0U 536 /* 603E */ -#define SPR603E_DBAT0L 537 /* 603E */ -#define SPR603E_DBAT1U 538 /* 603E */ -#define SPR603E_DBAT1L 539 /* 603E */ -#define SPR603E_DBAT2U 540 /* 603E */ -#define SPR603E_DBAT2L 541 /* 603E */ -#define SPR603E_DBAT3U 542 /* 603E */ -#define SPR603E_DBAT3L 543 /* 603E */ -#define SPR603E_DABR 1013 /* 603E */ -#define SPR603E_DMISS 0x3d0 /* 603E */ -#define SPR603E_DCMP 0x3d1 /* 603E */ -#define SPR603E_HASH1 0x3d2 /* 603E */ -#define SPR603E_HASH2 0x3d3 /* 603E */ -#define SPR603E_IMISS 0x3d4 /* 603E */ -#define SPR603E_ICMP 0x3d5 /* 603E */ -#define SPR603E_RPA 0x3d6 /* 603E */ -#define SPR603E_HID0 1008 /* 603E */ -#define SPR603E_HID1 1009 /* 603E */ -#define SPR603E_IABR 1010 /* 603E */ -#define SPR603E_HID2 1011 /* 603E */ - -#define SPR602_TCR 984 /* 602 */ -#define SPR602_IBR 986 /* 602 */ -#define SPR602_ESASRR 987 /* 602 */ -#define SPR602_SEBR 990 /* 602 */ -#define SPR602_SER 991 /* 602 */ -#define SPR602_SP 1021 /* 602 */ -#define SPR602_LT 1022 /* 602 */ - - -#define DCR_BEAR 0x90 /* bus error address */ -#define DCR_BESR 0x91 /* bus error syndrome */ -#define DCR_BR0 0x80 /* bank */ -#define DCR_BR1 0x81 /* bank */ -#define DCR_BR2 0x82 /* bank */ -#define DCR_BR3 0x83 /* bank */ -#define DCR_BR4 0x84 /* bank */ -#define DCR_BR5 0x85 /* bank */ -#define DCR_BR6 0x86 /* bank */ -#define DCR_BR7 0x87 /* bank */ -#define DCR_DMACC0 0xc4 /* dma chained count */ -#define DCR_DMACC1 0xcc /* dma chained count */ -#define DCR_DMACC2 0xd4 /* dma chained count */ -#define DCR_DMACC3 0xdc /* dma chained count */ -#define DCR_DMACR0 0xc0 /* dma channel control */ -#define DCR_DMACR1 0xc8 /* dma channel control */ -#define DCR_DMACR2 0xd0 /* dma channel control */ -#define DCR_DMACR3 0xd8 /* dma channel control */ -#define DCR_DMACT0 0xc1 /* dma destination address */ -#define DCR_DMACT1 0xc9 /* dma destination address */ -#define DCR_DMACT2 0xd1 /* dma destination address */ -#define DCR_DMACT3 0xd9 /* dma destination address */ -#define DCR_DMADA0 0xc2 /* dma destination address */ -#define DCR_DMADA1 0xca /* dma destination address */ -#define DCR_DMADA2 0xd2 /* dma source address */ -#define DCR_DMADA3 0xda /* dma source address */ -#define DCR_DMASA0 0xc3 /* dma source address */ -#define DCR_DMASA1 0xcb /* dma source address */ -#define DCR_DMASA2 0xd3 /* dma source address */ -#define DCR_DMASA3 0xdb /* dma source address */ -#define DCR_DMASR 0xe0 /* dma status */ -#define DCR_EXIER 0x42 /* external interrupt enable */ -#define DCR_EXISR 0x40 /* external interrupt status */ -#define DCR_IOCR 0xa0 /* io configuration */ - -enum { - EXCEPTION_IRQ = 1, - EXCEPTION_DECREMENTER = 2, - EXCEPTION_TRAP = 3, - EXCEPTION_SYSTEM_CALL = 4, - EXCEPTION_SMI = 5, - EXCEPTION_DSI = 6, - EXCEPTION_ISI = 7, - EXCEPTION_PROGRAMMABLE_INTERVAL_TIMER = 20, - EXCEPTION_FIXED_INTERVAL_TIMER = 21, - EXCEPTION_WATCHDOG_TIMER = 22, - EXCEPTION_CRITICAL_INTERRUPT = 23, -}; -enum { - PPC_INPUT_LINE_SMI = 10, - PPC_INPUT_LINE_TLBISYNC -}; +/*************************************************************************** + REGISTER ENUMERATION +***************************************************************************/ -enum { - PPC_PC=1, - PPC_MSR, - PPC_CR, - PPC_LR, - PPC_CTR, - PPC_XER, - PPC_DEC, - PPC_SRR0, - PPC_SRR1, - PPC_EXIER, - PPC_EXISR, - PPC_IBR, +enum +{ + PPC_PC = 1, PPC_R0, PPC_R1, PPC_R2, @@ -190,158 +50,95 @@ enum { PPC_R28, PPC_R29, PPC_R30, - PPC_R31 + PPC_R31, + PPC_CR, + PPC_LR, + PPC_CTR, + PPC_XER, + PPC_MSR, + PPC_SRR0, + PPC_SRR1, + PPC_SPRG0, + PPC_SPRG1, + PPC_SPRG2, + PPC_SPRG3, + PPC_SDR1, + PPC_EXIER, + PPC_EXISR, + PPC_EVPR, + PPC_IOCR }; -typedef enum { - PPC_MODEL_403GA = 0x00200000, - PPC_MODEL_403GB = 0x00200100, - PPC_MODEL_403GC = 0x00200200, - PPC_MODEL_403GCX = 0x00201400, - PPC_MODEL_405GP = 0x40110000, - PPC_MODEL_601 = 0x00010000, - PPC_MODEL_603 = 0x00030000, /* "Wart" */ - PPC_MODEL_604 = 0x00040000, /* "Zephyr" */ - PPC_MODEL_602 = 0x00050200, /* "Galahad" */ - PPC_MODEL_603E = 0x00060103, /* "Stretch", version 1.3 */ - PPC_MODEL_603EV = 0x00070000, /* "Valiant" */ - PPC_MODEL_603R = 0x00071202, /* "Goldeneye", version 2.1 */ - PPC_MODEL_740 = 0x00080301, /* "Arthur", version 3.1 */ - PPC_MODEL_750 = PPC_MODEL_740, - PPC_MODEL_740P = 0x00080202, /* "Conan Doyle", version 1.2 */ - PPC_MODEL_750P = PPC_MODEL_740P, - PPC_MODEL_755 = 0x00083203, /* "Goldfinger", version 2.3 */ - PPC_MODEL_7400 = 0x000c0209, /* "Max", version 2.9 */ - PPC_MODEL_7410 = 0x800c1104, /* "Nitro", version 3.4 */ - PPC_MODEL_7450 = 0x80000201, /* "Vger", version 2.1 */ - PPC_MODEL_7451 = 0x80000203, /* "Vger", version 2.3 */ - PPC_MODEL_7441 = PPC_MODEL_7451, - PPC_MODEL_7455 = 0x80010303, /* "Apollo 6", version 3.3 */ - PPC_MODEL_7445 = PPC_MODEL_7455, - PPC_MODEL_7457 = 0x80020101, /* "Apollo 7", version 1.1 */ - PPC_MODEL_MPC8240 = 0x00810101, /* "Kahlua" */ - PPC_MODEL_MPC8241 = 0x80811014, /* "Kahlua Lt" */ - PPC_MODEL_MPC8245 = 0x80811014, /* "Kahlua II" */ -} PPC_MODEL; - -typedef enum { - BUS_FREQUENCY_16MHZ = 0, - BUS_FREQUENCY_20MHZ, - BUS_FREQUENCY_25MHZ, - BUS_FREQUENCY_33MHZ, - BUS_FREQUENCY_40MHZ, - BUS_FREQUENCY_50MHZ, - BUS_FREQUENCY_60MHZ, - BUS_FREQUENCY_66MHZ, - BUS_FREQUENCY_75MHZ, -} PPC_BUS_FREQUENCY; - -// PLL Configuration based on the table in MPC603EUM page 7-31 -static const int mpc603e_pll_config[12][9] = -{ - // 16, 20, 25, 33, 40, 50, 60, 66, 75 - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, -1, 0x0, -1 }, - { -1, -1, -1, -1, -1, 0xc, -1, 0xc, -1 }, - { 0x5, 0x5, 0x5, 0x4, 0x4, 0x4, -1, -1, -1 }, - { -1, -1, -1, 0x6, 0x6, -1, -1, -1, -1 }, - { -1, -1, 0x8, 0x8, -1, -1, -1, -1, -1 }, - { -1, 0xe, 0xe, -1, -1, -1, -1, -1, -1 }, - { 0xa, 0xa, 0xa, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, -}; -// PLL Configuration based on the table in MPC603E7VEC page 29 -static const int mpc603ev_pll_config[12][9] = -{ - // 16, 20, 25, 33, 40, 50, 60, 66, 75 - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - // 2:1 - { -1, -1, -1, -1, -1, -1, -1, 0x4, 0x4 }, - // 2.5:1 - { -1, -1, -1, -1, -1, 0x6, 0x6, 0x6, 0x6 }, - // 3:1 - { -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8, 0x8 }, - // 3.5:1 - { -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe, -1 }, - // 4:1 - { -1, -1, -1, 0xa, 0xa, 0xa, 0xa, -1, -1 }, - // 4.5:1 - { -1, -1, -1, 0x7, 0x7, 0x7, -1, -1, -1 }, - // 5:1 - { -1, -1, 0xb, 0xb, 0xb, -1, -1, -1, -1 }, - // 5.5:1 - { -1, -1, 0x9, 0x9, 0x9, -1, -1, -1, -1 }, - // 6:1 - { -1, -1, 0xd, 0xd, 0xd, -1, -1, -1, -1 } -}; +#define PPC_MAX_FASTRAM 4 +#define PPC_MAX_HOTSPOTS 16 + -// PLL Configuration based on the table in MPC603E7TEC page 23 -static const int mpc603r_pll_config[12][9] = +enum { - // 16, 20, 25, 33, 40, 50, 60, 66, 75 - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - // 2:1 - { -1, -1, -1, -1, 0x5, 0x5, 0x5, 0x5, 0x5 }, - // 2.5:1 - { -1, -1, -1, -1, -1, -1, 0x6, 0x6, 0x6 }, - // 3:1 - { -1, -1, -1, -1, -1, 0x8, 0x8, 0x8, 0x8 }, - // 3.5:1 - { -1, -1, -1, -1, -1, 0xe, 0xe, 0xe, 0xe }, - // 4:1 - { -1, -1, -1, -1, 0xa, 0xa, 0xa, 0xa, 0xa }, - // 4.5:1 - { -1, -1, -1, 0x7, 0x7, 0x7, 0x7, 0x7, -1 }, - // 5:1 - { -1, -1, -1, 0xb, 0xb, 0xb, 0xb, -1, -1 }, - // 5.5:1 - { -1, -1, -1, 0x9, 0x9, 0x9, -1, -1, -1 }, - // 6:1 - { -1, -1, 0xd, 0xd, 0xd, 0xd, -1, -1, -1 }, + CPUINFO_INT_PPC_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC, + + CPUINFO_INT_PPC_FASTRAM_SELECT, + CPUINFO_INT_PPC_FASTRAM_START, + CPUINFO_INT_PPC_FASTRAM_END, + CPUINFO_INT_PPC_FASTRAM_READONLY, + + CPUINFO_INT_PPC_HOTSPOT_SELECT, + CPUINFO_INT_PPC_HOTSPOT_PC, + CPUINFO_INT_PPC_HOTSPOT_OPCODE, + CPUINFO_INT_PPC_HOTSPOT_CYCLES, + + CPUINFO_INT_PPC_RX_DATA, + + CPUINFO_PTR_PPC_FASTRAM_BASE = CPUINFO_PTR_CPU_SPECIFIC, + + CPUINFO_PTR_SPU_RX_HANDLER, + CPUINFO_PTR_SPU_TX_HANDLER, + + CPUINFO_PTR_CONTEXT /* temporary */ }; -#define PPCDRC_OPTIONS_CHECK_SELFMOD_CODE 0x1 -enum + +/*************************************************************************** + INTERRUPT CONSTANTS +***************************************************************************/ + +#define PPC_IRQ 0 /* external IRQ */ +#define PPC_IRQ_LINE_0 0 /* (4XX) external IRQ0 */ +#define PPC_IRQ_LINE_1 1 /* (4XX) external IRQ1 */ +#define PPC_IRQ_LINE_2 2 /* (4XX) external IRQ2 */ +#define PPC_IRQ_LINE_3 3 /* (4XX) external IRQ3 */ +#define PPC_IRQ_LINE_4 4 /* (4XX) external IRQ4 */ + + + +/*************************************************************************** + STRUCTURES +***************************************************************************/ + +typedef struct _powerpc_config powerpc_config; +struct _powerpc_config { - CPUINFO_INT_PPC_DRC_OPTIONS = CPUINFO_INT_CPU_SPECIFIC, + UINT32 bus_frequency; }; -typedef struct { - PPC_MODEL pvr; - int bus_frequency_multiplier; - PPC_BUS_FREQUENCY bus_frequency; -} ppc_config; - -#if (HAS_PPC403) -typedef UINT8 (* SPU_RX_HANDLER)(void); -typedef void (* SPU_TX_HANDLER)(UINT8); -typedef void (* PPC_DMA_HANDLER)(int); - -void ppc403_spu_rx(UINT8 data); -void ppc403_install_spu_rx_handler(SPU_RX_HANDLER rx_handler); -void ppc403_install_spu_tx_handler(SPU_TX_HANDLER tx_handler); -void ppc403_install_spu_rx_dma_handler(PPC_DMA_HANDLER rx_dma_handler, UINT8 *buffer); -void ppc403_install_spu_tx_dma_handler(PPC_DMA_HANDLER tx_dma_handler, UINT8 *buffer); -void ppc403_install_dma_read_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer); -void ppc403_install_dma_write_handler(int ch, PPC_DMA_HANDLER dma_handler, UINT8 *buffer); - -#define PPC403_SPU_RX 5 -#define PPC403_SPU_TX 6 -#define PPC403_CRITICAL_IRQ 7 + +/*************************************************************************** + PUBLIC FUNCTIONS +***************************************************************************/ + +#if (HAS_PPC403GA) +void ppc403ga_get_info(UINT32 state, cpuinfo *info); #endif -#if (HAS_PPC403) -void ppc403_get_info(UINT32 state, cpuinfo *info); +#if (HAS_PPC403GCX) +void ppc403gcx_get_info(UINT32 state, cpuinfo *info); +#endif + +#if (HAS_PPC601) +void ppc601_get_info(UINT32 state, cpuinfo *info); #endif #if (HAS_PPC602) @@ -352,20 +149,32 @@ void ppc602_get_info(UINT32 state, cpuinfo *info); void ppc603_get_info(UINT32 state, cpuinfo *info); #endif -#if (HAS_MPC8240) -void mpc8240_get_info(UINT32 state, cpuinfo *info); +#if (HAS_PPC603E) +void ppc603e_get_info(UINT32 state, cpuinfo *info); #endif -#if (HAS_PPC601) -void ppc601_get_info(UINT32 state, cpuinfo *info); +#if (HAS_PPC603R) +void ppc603r_get_info(UINT32 state, cpuinfo *info); #endif #if (HAS_PPC604) void ppc604_get_info(UINT32 state, cpuinfo *info); #endif -#ifdef ENABLE_DEBUGGER -extern offs_t ppc_dasm_one(char *buffer, offs_t pc, UINT32 op); +#if (HAS_MPC8240) +void mpc8240_get_info(UINT32 state, cpuinfo *info); #endif -#endif /* _PPC_H */ + + +/*************************************************************************** + COMPILER-SPECIFIC OPTIONS +***************************************************************************/ + +#define PPCDRC_STRICT_VERIFY 0x0001 /* verify all instructions */ +#define PPCDRC_FLUSH_PC 0x0002 /* flush the PC value before each memory access */ + +#define PPCDRC_COMPATIBLE_OPTIONS (PPCDRC_STRICT_VERIFY | PPCDRC_FLUSH_PC) +#define PPCDRC_FASTEST_OPTIONS (0) + +#endif /* __PPC_H__ */ diff --git a/src/emu/cpu/powerpc/ppc403.c b/src/emu/cpu/powerpc/ppc403.c index 5bfaac3dd90..85183e65b94 100644 --- a/src/emu/cpu/powerpc/ppc403.c +++ b/src/emu/cpu/powerpc/ppc403.c @@ -434,7 +434,7 @@ static void ppc403_set_irq_line(int irqline, int state) ppc.exisr &= ~mask; } } - else if (irqline == PPC403_SPU_RX) + else if (irqline == PPC_IRQ_SPU_RX) { UINT32 mask = 0x08000000; if (state) { @@ -444,7 +444,7 @@ static void ppc403_set_irq_line(int irqline, int state) } } } - else if (irqline == PPC403_SPU_TX) + else if (irqline == PPC_IRQ_SPU_TX) { UINT32 mask = 0x04000000; if (state) { @@ -454,7 +454,7 @@ static void ppc403_set_irq_line(int irqline, int state) } } } - else if (irqline == PPC403_CRITICAL_IRQ) + else if (irqline == PPC_IRQ_CRITICAL) { if (state) { if (EXIER & 0x80000000) { @@ -661,9 +661,9 @@ static void ppc403_spu_w(UINT32 a, UINT8 d) ppc.spu.spls = 0x80; #ifndef PPC_DRC - ppc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); + ppc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); #else - ppcdrc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); + ppcdrc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); #endif } } @@ -698,9 +698,9 @@ void ppc403_spu_rx(UINT8 data) /* generate interrupt if DMA is disabled and RBR interrupt is enabled */ if (((ppc.spu.sprc >> 5) & 0x3) == 0x01) { #ifndef PPC_DRC - ppc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); + ppc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); #else - ppcdrc403_set_irq_line(PPC403_SPU_RX, ASSERT_LINE); + ppcdrc403_set_irq_line(PPC_IRQ_SPU_RX, ASSERT_LINE); #endif } } @@ -722,9 +722,9 @@ static TIMER_CALLBACK( ppc403_spu_tx_callback ) /* generate interrupt if DMA is disabled and TBR interrupt is enabled */ if (((ppc.spu.sptc >> 5) & 0x3) == 0x01) { #ifndef PPC_DRC - ppc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); + ppc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); #else - ppcdrc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); + ppcdrc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); #endif } } @@ -826,9 +826,9 @@ static void ppc403_dma_exec(int ch) } #ifndef PPC_DRC - ppc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); + ppc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); #else - ppcdrc403_set_irq_line(PPC403_SPU_TX, ASSERT_LINE); + ppcdrc403_set_irq_line(PPC_IRQ_SPU_TX, ASSERT_LINE); #endif } else { diff --git a/src/emu/cpu/powerpc/ppc_dasm.c b/src/emu/cpu/powerpc/ppc_dasm.c index 2f24713bab8..ae81392f268 100644 --- a/src/emu/cpu/powerpc/ppc_dasm.c +++ b/src/emu/cpu/powerpc/ppc_dasm.c @@ -15,96 +15,7 @@ #include "cpuintrf.h" #include "debugger.h" - -/* - * Masks - * - * These masks isolate fields in an instruction word. - */ - -#define M_LI 0x03fffffc -#define M_AA 0x00000002 -#define M_LK 0x00000001 -#define M_BO 0x03e00000 -#define M_BI 0x001f0000 -#define M_BD 0x0000fffc -#define M_RT 0x03e00000 -#define M_RA 0x001f0000 -#define M_RB 0x0000f800 -#define M_CRFD 0x03800000 -#define M_L 0x00200000 -#define M_TO 0x03e00000 -#define M_D 0x0000ffff -#define M_SIMM 0x0000ffff -#define M_UIMM 0x0000ffff -#define M_NB 0x0000f800 -#define M_SR 0x000f0000 -#define M_SH 0x0000f800 -#define M_CRFS 0x001c0000 -#define M_IMM 0x0000f000 -#define M_CRBD 0x03e00000 -#define M_RC 0x00000001 -#define M_CRBA 0x001f0000 -#define M_CRBB 0x0000f800 -#define M_SPR 0x001FF800 -#define M_TBR 0x001FF800 -#define M_CRM 0x000FF000 -#define M_DCR 0x001FF800 -#define M_FM 0x01FE0000 -#define M_OE 0x00000400 -#define M_REGC 0x000007c0 -#define M_MB 0x000007c0 -#define M_ME 0x0000003e -#define M_XO 0x000007fe - -/* - * Field Defining Macros - * - * These macros generate instruction words with their associated fields filled - * in with the passed value. - */ - -#define D_OP(op) ((op & 0x3f) << 26) -#define D_XO(xo) ((xo & 0x3ff) << 1) -#define D_RT(r) ((r & 0x1f) << (31 - 10)) -#define D_RA(r) ((r & 0x1f) << (31 - 15)) -#define D_UIMM(u) (u & 0xffff) - -/* - * Macros to Get Field Values - * - * These macros return the values of fields in an opcode. They all return - * unsigned values and do not perform any sign extensions. - */ - -#define G_RT(op) ((op & M_RT) >> (31 - 10)) -#define G_RA(op) ((op & M_RA) >> (31 - 15)) -#define G_RB(op) ((op & M_RB) >> (31 - 20)) -#define G_SIMM(op) (op & M_SIMM) -#define G_UIMM(op) (op & M_UIMM) -#define G_LI(op) ((op & M_LI) >> 2) -#define G_BO(op) ((op & M_BO) >> (31 - 10)) -#define G_BI(op) ((op & M_BI) >> (31 - 15)) -#define G_BD(op) ((op & M_BD) >> 2) -#define G_CRFD(op) ((op & M_CRFD) >> (31 - 8)) -#define G_L(op) ((op & M_L) >> (31 - 10)) -#define G_CRBD(op) ((op & M_CRBD) >> (31 - 10)) -#define G_CRBA(op) ((op & M_CRBA) >> (31 - 15)) -#define G_CRBB(op) ((op & M_CRBB) >> (31 - 20)) -#define G_REGC(op) ((op & M_REGC) >> (31 - 25)) -#define G_D(op) (op & M_D) -#define G_NB(op) ((op & M_NB) >> (31 - 20)) -#define G_CRFS(op) ((op & M_CRFS) >> (31 - 13)) -#define G_SPR(op) ((op & M_SPR) >> (31 - 20)) -#define G_DCR(op) ((op & M_DCR) >> (31 - 20)) -#define G_SR(op) ((op & M_SR) >> (31 - 15)) -#define G_CRM(op) ((op & M_CRM) >> (31 - 19)) -#define G_FM(op) ((op & M_FM) >> (31 - 14)) -#define G_IMM(op) ((op & M_IMM) >> (31 - 19)) -#define G_SH(op) ((op & M_SH) >> (31 - 20)) -#define G_MB(op) ((op & M_MB) >> (31 - 25)) -#define G_ME(op) ((op & M_ME) >> 1) -#define G_TO(op) ((op & M_TO) >> (31 - 10)) +#include "ppccom.h" /* * Operand Formats @@ -227,10 +138,14 @@ static const IDESCR itab[] = { "bc", D_OP(16), M_BO|M_BI|M_BD|M_AA|M_LK, F_BCx, FL_AA|FL_LK }, { "bcctr", D_OP(19)|D_XO(528), M_BO|M_BI|M_LK, F_BO_BI, FL_LK }, { "bclr", D_OP(19)|D_XO(16), M_BO|M_BI|M_LK, F_BO_BI, FL_LK|FL_SO }, - { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_L|M_RA|M_RB, F_CMP, 0 }, - { "cmpi", D_OP(11), M_CRFD|M_L|M_RA|M_SIMM, F_CMP_SIMM, 0 }, - { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_L|M_RA|M_RB, F_CMP, 0 }, - { "cmpli", D_OP(10), M_CRFD|M_L|M_RA|M_UIMM, F_CMP_UIMM, 0 }, + { "cmp", D_OP(31)|D_XO(0), M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpd", D_OP(31)|D_XO(0)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpi", D_OP(11), M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0 }, + { "cmpdi", D_OP(11)|M_L, M_CRFD|M_RA|M_SIMM, F_CMP_SIMM, 0 }, + { "cmpl", D_OP(31)|D_XO(32), M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpld", D_OP(31)|D_XO(32)|M_L,M_CRFD|M_RA|M_RB, F_CMP, 0 }, + { "cmpli", D_OP(10), M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0 }, + { "cmpldi", D_OP(10)|M_L, M_CRFD|M_RA|M_UIMM, F_CMP_UIMM, 0 }, { "cntlzw", D_OP(31)|D_XO(26), M_RT|M_RA|M_RC, F_RA_RT, FL_RC }, { "crand", D_OP(19)|D_XO(257), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, { "crandc", D_OP(19)|D_XO(129), M_CRBD|M_CRBA|M_CRBB, F_CRBD_CRBA_CRBB, 0 }, @@ -424,6 +339,7 @@ static const IDESCR itab[] = */ static const char *const crbit[4] = { "lt", "gt", "eq", "so" }; +static const char *const crnbit[4] = { "ge", "le", "ne", "nso" }; /* @@ -450,61 +366,88 @@ static void SPR(char *dest, int spr_field) switch (spr) { - case 1: strcat(dest, "xer"); break; - case 8: strcat(dest, "lr"); break; - case 9: strcat(dest, "ctr"); break; - case 18: strcat(dest, "dsisr"); break; - case 19: strcat(dest, "dar"); break; - case 22: strcat(dest, "dec"); break; - case 25: strcat(dest, "sdr1"); break; - case 26: strcat(dest, "srr0"); break; - case 27: strcat(dest, "srr1"); break; - case 272: strcat(dest, "sprg0"); break; - case 273: strcat(dest, "sprg1"); break; - case 274: strcat(dest, "sprg2"); break; - case 275: strcat(dest, "sprg3"); break; - case 282: strcat(dest, "ear"); break; - case 287: strcat(dest, "pvr"); break; - case 528: strcat(dest, "ibat0u"); break; - case 529: strcat(dest, "ibat0l"); break; - case 530: strcat(dest, "ibat1u"); break; - case 531: strcat(dest, "ibat1l"); break; - case 532: strcat(dest, "ibat2u"); break; - case 533: strcat(dest, "ibat2l"); break; - case 534: strcat(dest, "ibat3u"); break; - case 535: strcat(dest, "ibat3l"); break; - case 536: strcat(dest, "dbat0u"); break; - case 537: strcat(dest, "dbat0l"); break; - case 538: strcat(dest, "dbat1u"); break; - case 539: strcat(dest, "dbat1l"); break; - case 540: strcat(dest, "dbat2u"); break; - case 541: strcat(dest, "dbat2l"); break; - case 542: strcat(dest, "dbat3u"); break; - case 543: strcat(dest, "dbat3l"); break; - case 1013: strcat(dest, "dabr"); break; // unsupported on 603e/EC603e - - /* - * Some PowerPC implementations may implement MFTB and MFSPR identically, - * therefore TBR registers are also decoded here - */ - - case 268: strcat(dest, "tbl"); break; - case 269: strcat(dest, "tbu"); break; - - /* - * PowerPC 603e/EC603e-specific registers - */ - - case 1008: strcat(dest, "hid0"); break; - case 1009: strcat(dest, "hid1"); break; - case 976: strcat(dest, "dmiss"); break; - case 977: strcat(dest, "dcmp"); break; - case 978: strcat(dest, "hash2"); break; - case 979: strcat(dest, "hash2"); break; - case 980: strcat(dest, "imiss"); break; - case 981: strcat(dest, "icmp"); break; - case 982: strcat(dest, "rpa"); break; - case 1010: strcat(dest, "iabr"); break; + /* UISA SPR register indexes */ + case SPR_XER: strcat(dest, "xer"); break; + case SPR_LR: strcat(dest, "lr"); break; + case SPR_CTR: strcat(dest, "ctr"); break; + + /* VEA SPR register indexes */ + case SPRVEA_TBL_R: strcat(dest, "tbl"); break; + case SPRVEA_TBU_R: strcat(dest, "tbu"); break; + + /* OEA SPR register indexes */ + case SPROEA_DSISR: strcat(dest, "dsisr"); break; + case SPROEA_DAR: strcat(dest, "dar"); break; + case SPROEA_DEC: strcat(dest, "dec"); break; + case SPROEA_SDR1: strcat(dest, "sdr1"); break; + case SPROEA_SRR0: strcat(dest, "srr0"); break; + case SPROEA_SRR1: strcat(dest, "srr1"); break; + case SPROEA_SPRG0: strcat(dest, "sprg0"); break; + case SPROEA_SPRG1: strcat(dest, "sprg1"); break; + case SPROEA_SPRG2: strcat(dest, "sprg2"); break; + case SPROEA_SPRG3: strcat(dest, "sprg3"); break; + case SPROEA_ASR: strcat(dest, "asr"); break; + case SPROEA_EAR: strcat(dest, "ear"); break; + case SPROEA_PVR: strcat(dest, "pvr"); break; + case SPROEA_IBAT0U: strcat(dest, "ibat0u"); break; + case SPROEA_IBAT0L: strcat(dest, "ibat0l"); break; + case SPROEA_IBAT1U: strcat(dest, "ibat1u"); break; + case SPROEA_IBAT1L: strcat(dest, "ibat1l"); break; + case SPROEA_IBAT2U: strcat(dest, "ibat2u"); break; + case SPROEA_IBAT2L: strcat(dest, "ibat2l"); break; + case SPROEA_IBAT3U: strcat(dest, "ibat3u"); break; + case SPROEA_IBAT3L: strcat(dest, "ibat3l"); break; + case SPROEA_DBAT0U: strcat(dest, "dbat0u"); break; + case SPROEA_DBAT0L: strcat(dest, "dbat0l"); break; + case SPROEA_DBAT1U: strcat(dest, "dbat1u"); break; + case SPROEA_DBAT1L: strcat(dest, "dbat1l"); break; + case SPROEA_DBAT2U: strcat(dest, "dbat2u"); break; + case SPROEA_DBAT2L: strcat(dest, "dbat2l"); break; + case SPROEA_DBAT3U: strcat(dest, "dbat3u"); break; + case SPROEA_DBAT3L: strcat(dest, "dbat3l"); break; + case SPROEA_DABR: strcat(dest, "dabr/iac2"); break; // unsupported on 603e/EC603e + + /* PowerPC 603E SPR register indexes */ + case SPR603_HID0: strcat(dest, "hid0/dbsr"); break; + case SPR603_HID1: strcat(dest, "hid1"); break; + case SPR603_DMISS: strcat(dest, "dmiss"); break; + case SPR603_DCMP: strcat(dest, "dcmp"); break; + case SPR603_HASH1: strcat(dest, "hash1"); break; + case SPR603_HASH2: strcat(dest, "hash2/icdbdr"); break; + case SPR603_IMISS: strcat(dest, "imiss"); break; + case SPR603_ICMP: strcat(dest, "icmp/dear"); break; + case SPR603_RPA: strcat(dest, "rpa/evpr"); break; + case SPR603_IABR: strcat(dest, "iabr/dbcr"); break; + + /* PowerPC 4XX SPR register indexes */ + case SPR4XX_SGR: strcat(dest, "sgr"); break; + case SPR4XX_DCWR: strcat(dest, "dcwr"); break; + case SPR4XX_PID: strcat(dest, "pid"); break; + case SPR4XX_TBHU: strcat(dest, "tbhu"); break; + case SPR4XX_TBLU: strcat(dest, "tblu"); break; +// case SPR4XX_ICDBDR: strcat(dest, "icdbdr"); break; // same as SPR603E_HASH2 +// case SPR4XX_DEAR: strcat(dest, "dear"); break; // same as SPR603E_ICMP +// case SPR4XX_EVPR: strcat(dest, "evpr"); break; // same as SPR603E_RPA + case SPR4XX_CDBCR: strcat(dest, "cdbcr"); break; + case SPR4XX_TSR: strcat(dest, "tsr"); break; + case SPR4XX_TCR: strcat(dest, "tcr"); break; + case SPR4XX_PIT: strcat(dest, "pit"); break; + case SPR4XX_TBHI: strcat(dest, "tbhi"); break; + case SPR4XX_TBLO: strcat(dest, "tblo"); break; + case SPR4XX_SRR2: strcat(dest, "srr2"); break; + case SPR4XX_SRR3: strcat(dest, "srr3"); break; +// case SPR4XX_DBSR: strcat(dest, "dbsr"); break; // same as SPR603E_HID0 +// case SPR4XX_DBCR: strcat(dest, "dbcr"); break; // same as SPR603E_IABR + case SPR4XX_IAC1: strcat(dest, "iac1"); break; +// case SPR4XX_IAC2: strcat(dest, "iac2"); break; // same as SPROEA_DABR + case SPR4XX_DAC1: strcat(dest, "dac1"); break; + case SPR4XX_DAC2: strcat(dest, "dac2"); break; + case SPR4XX_DCCR: strcat(dest, "dccr"); break; + case SPR4XX_ICCR: strcat(dest, "iccr"); break; + case SPR4XX_PBL1: strcat(dest, "pbl1"); break; + case SPR4XX_PBU1: strcat(dest, "pbu1"); break; + case SPR4XX_PBL2: strcat(dest, "pbl2"); break; + case SPR4XX_PBU2: strcat(dest, "pbu2"); break; default: sprintf(dest, "%s%d", dest, spr); break; } @@ -805,17 +748,23 @@ static int Simplified(UINT32 op, UINT32 vpc, char *signed16, char *mnem, char *o switch (G_BO(op)) { - case 0x04: // branch if condition is false - case 0x05: - case 0x06: - case 0x07: - strcat(mnem, "bf"); + case 0x04: case 0x05: case 0x06: case 0x07: + strcat(mnem, "b"); + strcat(mnem, crnbit[G_BI(op) & 3]); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + strcat(mnem, "b"); + strcat(mnem, crbit[G_BI(op) & 3]); break; - case 0x0c: - case 0x0d: - case 0x0e: - case 0x0f: - strcat(mnem, "bt"); + case 0x10: case 0x11: case 0x18: case 0x19: + strcat(mnem, "bdnz"); + break; + case 0x12: case 0x13: case 0x1a: case 0x1b: + strcat(mnem, "bdz"); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + strcat(mnem, "b"); break; default: return 0; @@ -824,7 +773,43 @@ static int Simplified(UINT32 op, UINT32 vpc, char *signed16, char *mnem, char *o if (op & M_LK) strcat(mnem, "l"); if (op & M_AA) strcat(mnem, "a"); - sprintf(oprs, "cr%d[%s],0x%08X", G_BI(op) / 4, crbit[G_BI(op) & 3], disp + ((op & M_AA) ? 0 : vpc)); + if (!(G_BO(op) & 0x10) && G_BI(op) / 4 != 0) + sprintf(oprs, "cr%d,0x%08X", G_BI(op) / 4, disp + ((op & M_AA) ? 0 : vpc)); + else + sprintf(oprs, "0x%08X", disp + ((op & M_AA) ? 0 : vpc)); + } + else if ((op & ~(M_BO|M_BI|M_LK)) == (D_OP(19)|D_XO(528)) || (op & ~(M_BO|M_BI|M_LK)) == (D_OP(19)|D_XO(16))) + { + switch (G_BO(op)) + { + case 0x04: case 0x05: case 0x06: case 0x07: + strcat(mnem, "b"); + strcat(mnem, crnbit[G_BI(op) & 3]); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + strcat(mnem, "b"); + strcat(mnem, crbit[G_BI(op) & 3]); + break; + case 0x10: case 0x11: case 0x18: case 0x19: + strcat(mnem, "bdnz"); + break; + case 0x12: case 0x13: case 0x1a: case 0x1b: + strcat(mnem, "bdz"); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + strcat(mnem, "b"); + break; + default: + return 0; + } + + strcat(mnem, (G_XO(op) == 528) ? "ctr" : "lr"); + if (op & M_LK) strcat(mnem, "l"); + if (op & M_AA) strcat(mnem, "a"); + + if (!(G_BO(op) & 0x10) && G_BI(op) / 4 != 0) + sprintf(oprs, "cr%d", G_BI(op) / 4); } else if ((op & ~(M_RT|M_RA|M_RB|M_OE|M_RC)) == (D_OP(31)|D_XO(40))) { @@ -961,15 +946,30 @@ offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op) break; case F_CMP: - sprintf(oprs, "cr%d,%d,r%d,r%d", G_CRFD(op), G_L(op), G_RA(op), G_RB(op)); + if (G_L(op)) + strcat(mnem, "d"); + if (G_CRFD(op) == 0) + sprintf(oprs, "r%d,r%d", G_RA(op), G_RB(op)); + else + sprintf(oprs, "cr%d,r%d,r%d", G_CRFD(op), G_RA(op), G_RB(op)); break; case F_CMP_SIMM: - sprintf(oprs, "cr%d,%d,r%d,%s", G_CRFD(op), G_L(op), G_RA(op), signed16); + if (G_L(op)) + strcat(mnem, "d"); + if (G_CRFD(op) == 0) + sprintf(oprs, "r%d,%s", G_RA(op), signed16); + else + sprintf(oprs, "cr%d,r%d,%s", G_CRFD(op), G_RA(op), signed16); break; case F_CMP_UIMM: - sprintf(oprs, "cr%d,%d,r%d,0x%04X", G_CRFD(op), G_L(op), G_RA(op), G_UIMM(op)); + if (G_L(op)) + strcat(mnem, "d"); + if (G_CRFD(op) == 0) + sprintf(oprs, "r%d,0x%04X", G_RA(op), G_UIMM(op)); + else + sprintf(oprs, "cr%d,r%d,0x%04X", G_CRFD(op), G_RA(op), G_UIMM(op)); break; case F_RA_RT: diff --git a/src/emu/cpu/powerpc/ppc_mem.c b/src/emu/cpu/powerpc/ppc_mem.c index 47f9b2f17f2..c96002751ab 100644 --- a/src/emu/cpu/powerpc/ppc_mem.c +++ b/src/emu/cpu/powerpc/ppc_mem.c @@ -297,7 +297,7 @@ exception: } #if (HAS_PPC602||HAS_PPC603) -static int ppc_translate_address_cb(int space, int intention, offs_t *addr) +static int ppc_translate_address_cb(int space, offs_t *addr) { int success = 1; diff --git a/src/emu/cpu/powerpc/ppccom.c b/src/emu/cpu/powerpc/ppccom.c new file mode 100644 index 00000000000..1eadcd33776 --- /dev/null +++ b/src/emu/cpu/powerpc/ppccom.c @@ -0,0 +1,1792 @@ +/*************************************************************************** + + ppccom.c + + Common PowerPC definitions and functions + +***************************************************************************/ + +#include "ppccom.h" +#include "deprecat.h" + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define PRINTF_TLB_FILL (0) +#define PRINTF_SPU (0) +#define PRINTF_DECREMENTER (0) + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static TIMER_CALLBACK( ppc4xx_fit_callback ); +static TIMER_CALLBACK( ppc4xx_pit_callback ); +static TIMER_CALLBACK( ppc4xx_spu_callback ); +static TIMER_CALLBACK( decrementer_int_callback ); + +static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state); + +static void ppc4xx_dma_update_irq_states(powerpc_state *ppc); +static int ppc4xx_dma_fetch_transmit_byte(powerpc_state *ppc, int dmachan, UINT8 *byte); +static int ppc4xx_dma_handle_receive_byte(powerpc_state *ppc, int dmachan, UINT8 byte); +static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan); + +static void ppc4xx_spu_update_irq_states(powerpc_state *ppc); +static void ppc4xx_spu_timer_reset(powerpc_state *ppc); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + page_access_allowed - return true if we are + allowed to access memory based on the type + of access and the protection bits +-------------------------------------------------*/ + +INLINE int page_access_allowed(int transtype, UINT8 key, UINT8 protbits) +{ + if (key == 0) + return (transtype == TRANSLATE_WRITE) ? (protbits != 3) : TRUE; + else + return (transtype == TRANSLATE_WRITE) ? (protbits == 2) : (protbits != 0); +} + + +/*------------------------------------------------- + tlb_entry_free - free an entry from the TLB, + by index +-------------------------------------------------*/ + +INLINE void tlb_entry_free(powerpc_state *ppc, int entrynum) +{ + int oldentry = ppc->tlb_entries[entrynum]; + + /* if we're mapped to something, free the entry in the table */ + if (oldentry != 0) + { + ppc->tlb_table[oldentry - 1] = 0; + ppc->tlb_entries[entrynum] = 0; + } +} + + +/*------------------------------------------------- + tlb_entry_allocate - allocate a TLB entry + for the given address, if needed, and set its + new value +-------------------------------------------------*/ + +INLINE int tlb_entry_allocate(powerpc_state *ppc, int entrynum, offs_t address, UINT32 value) +{ + UINT32 *entry = &ppc->tlb_table[address >> 12]; + int allocated = FALSE; + + /* only need to allocate if we are empty */ + if (*entry == 0) + { + /* if there's already a TLB entry at the current index, zap it */ + tlb_entry_free(ppc, entrynum); + + /* allocate a new entry and advance to the next one */ + ppc->tlb_entries[entrynum] = (address >> 12) + 1; + allocated = TRUE; + } + *entry = value; + + return allocated; +} + + +/*------------------------------------------------- + get_timebase - return the current timebase + value +-------------------------------------------------*/ + +INLINE UINT64 get_timebase(powerpc_state *ppc) +{ + return (cpunum_gettotalcycles(ppc->cpunum) - ppc->tb_zero_cycles) / ppc->tb_divisor; +} + + +/*------------------------------------------------- + set_timebase - set the timebase +-------------------------------------------------*/ + +INLINE void set_timebase(powerpc_state *ppc, UINT64 newtb) +{ + ppc->tb_zero_cycles = activecpu_gettotalcycles() - newtb * ppc->tb_divisor; +} + + +/*------------------------------------------------- + get_decremeter - return the current + decrementer value +-------------------------------------------------*/ + +INLINE UINT32 get_decrementer(powerpc_state *ppc) +{ + INT64 cycles_until_zero = ppc->dec_zero_cycles - cpunum_gettotalcycles(ppc->cpunum); + cycles_until_zero = MAX(cycles_until_zero, 0); + return cycles_until_zero / ppc->tb_divisor; +} + + +/*------------------------------------------------- + set_decrementer - set the decremeter +-------------------------------------------------*/ + +INLINE void set_decrementer(powerpc_state *ppc, UINT32 newdec) +{ + UINT64 cycles_until_done = ((UINT64)newdec + 1) * ppc->tb_divisor; + UINT32 curdec = get_decrementer(ppc); + + if (PRINTF_DECREMENTER) + { + UINT64 total = cpunum_gettotalcycles(ppc->cpunum); + mame_printf_debug("set_decrementer: olddec=%08X newdec=%08X divisor=%d totalcyc=%08X%08X timer=%08X%08X\n", + curdec, newdec, ppc->tb_divisor, + (UINT32)(total >> 32), (UINT32)total, (UINT32)(cycles_until_done >> 32), (UINT32)cycles_until_done); + } + + ppc->dec_zero_cycles = cpunum_gettotalcycles(ppc->cpunum) + cycles_until_done; + timer_adjust_oneshot(ppc->decrementer_int_timer, ATTOTIME_IN_CYCLES(cycles_until_done, ppc->cpunum), 0); + + if ((INT32)curdec >= 0 && (INT32)newdec < 0) + ppc->irq_pending |= 0x02; +} + + + +/*************************************************************************** + INITIALIZATION AND SHUTDOWN +***************************************************************************/ + +/*------------------------------------------------- + ppccom_init - initialize the powerpc_state + structure based on the configured type +-------------------------------------------------*/ + +size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int), void *memory) +{ + /* if no memory, return the amount needed */ + if (memory == NULL) + return sizeof(ppc->tlb_table[0]) * (POWERPC_TLB_ENTRIES + PPC603_FIXED_TLB_ENTRIES + (1 << (32 - POWERPC_MIN_PAGE_SHIFT))); + + /* initialize based on the config */ + memset(ppc, 0, sizeof(*ppc)); + ppc->cpunum = cpu_getactivecpu(); + ppc->flavor = flavor; + ppc->cap = cap; + ppc->cache_line_size = 32; + ppc->tb_divisor = tb_divisor; + ppc->cpu_clock = clock; + ppc->irq_callback = irqcallback; + ppc->system_clock = (config != NULL) ? config->bus_frequency : clock; + ppc->tb_divisor = (ppc->tb_divisor * clock + ppc->system_clock / 2 - 1) / ppc->system_clock; + + /* initialize the TLB state */ + ppc->tlb_entries = memory; + ppc->tlb_table = ppc->tlb_entries + POWERPC_TLB_ENTRIES + PPC603_FIXED_TLB_ENTRIES; + + /* allocate a timer for the compare interrupt */ + if (cap & PPCCAP_OEA) + ppc->decrementer_int_timer = timer_alloc(decrementer_int_callback, ppc); + + /* and for the 4XX interrupts if needed */ + if (cap & PPCCAP_4XX) + { + ppc->fit_timer = timer_alloc(ppc4xx_fit_callback, ppc); + ppc->pit_timer = timer_alloc(ppc4xx_pit_callback, ppc); + ppc->spu.timer = timer_alloc(ppc4xx_spu_callback, ppc); + } + + /* reset the state */ + ppccom_reset(ppc); + return 0; +} + + +/*------------------------------------------------- + ppccom_reset - reset the state of all the + registers +-------------------------------------------------*/ + +void ppccom_reset(powerpc_state *ppc) +{ + /* initialize the OEA state */ + if (ppc->cap & PPCCAP_OEA) + { + /* PC to the reset vector; MSR has IP set to start */ + ppc->pc = 0xfff00100; + ppc->msr = MSROEA_IP; + + /* reset the decrementer */ + ppc->dec_zero_cycles = cpunum_gettotalcycles(ppc->cpunum); + decrementer_int_callback(Machine, ppc, 0); + } + + /* initialize the 4XX state */ + if (ppc->cap & PPCCAP_4XX) + { + /* PC to the last word; MSR to 0 */ + ppc->pc = 0xfffffffc; + ppc->msr = 0; + + /* reset the SPU status */ + ppc->spr[SPR4XX_TCR] &= ~PPC4XX_TCR_WRC_MASK; + ppc->spu.regs[SPU4XX_LINE_STATUS] = 0x06; + } + + /* time base starts here */ + ppc->tb_zero_cycles = cpunum_gettotalcycles(ppc->cpunum); + + /* clear interrupts */ + ppc->irq_pending = 0; + + /* flush the TLB */ + ppc->tlb_index = 0; + memset(ppc->tlb_entries, 0, sizeof(ppc->tlb_entries[0]) * (POWERPC_TLB_ENTRIES + PPC603_FIXED_TLB_ENTRIES)); + memset(ppc->tlb_table, 0, sizeof(ppc->tlb_table[0]) * (1 << (32 - POWERPC_MIN_PAGE_SHIFT))); +} + + +/*------------------------------------------------- + ppccom_dasm - handle disassembly for a + CPU +-------------------------------------------------*/ + +#ifdef ENABLE_DEBUGGER +offs_t ppccom_dasm(powerpc_state *ppc, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) +{ + extern offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); + UINT32 op = *(UINT32 *)oprom; + op = BIG_ENDIANIZE_INT32(op); + return ppc_dasm_one(buffer, pc, op); +} +#endif /* ENABLE_DEBUGGER */ + + + +/*************************************************************************** + TLB HANDLING +***************************************************************************/ + +/*------------------------------------------------- + ppccom_translate_address_internal - translate + an address from logical to physical; shared + between external requests and internal TLB + filling +-------------------------------------------------*/ + +static UINT32 ppccom_translate_address_internal(powerpc_state *ppc, int intention, offs_t *address) +{ + int transpriv = ((intention & TRANSLATE_USER_MASK) == 0); + int transtype = intention & TRANSLATE_TYPE_MASK; + offs_t hash, hashbase, hashmask; + int batbase, batnum, hashnum; + UINT32 segreg; + + /* only applies if we support the OEA */ + if (!(ppc->cap & PPCCAP_OEA)) + return 0x001; + + /* also no translation necessary if translation is disabled */ + if ((transtype == TRANSLATE_FETCH && (ppc->msr & MSROEA_IR) == 0) || (transtype != TRANSLATE_FETCH && (ppc->msr & MSROEA_DR) == 0)) + return 0x001; + + /* first scan the appropriate BAT */ + batbase = (transtype == TRANSLATE_FETCH) ? SPROEA_IBAT0U : SPROEA_DBAT0U; + for (batnum = 0; batnum < 4; batnum++) + { + UINT32 upper = ppc->spr[batbase + 2*batnum + 0]; + + /* check user/supervisor valid bit */ + if ((upper >> transpriv) & 0x01) + { + UINT32 mask = (~upper << 15) & 0xfffe0000; + + /* check for a hit against this bucket */ + if ((*address & mask) == (upper & mask)) + { + UINT32 lower = ppc->spr[batbase + 2*batnum + 1]; + + /* verify protection; if we fail, return false and indicate a protection violation */ + if (!page_access_allowed(transtype, 1, lower & 3)) + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + + /* otherwise we're good */ + *address = (lower & mask) | (*address & ~mask); + return 0x001; + } + } + } + + /* look up the segment register */ + segreg = ppc->sr[*address >> 28]; + if (transtype == TRANSLATE_FETCH && (segreg & 0x10000000)) + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + + /* get hash table information from SD1 */ + hashbase = ppc->spr[SPROEA_SDR1] & 0xffff0000; + hashmask = ((ppc->spr[SPROEA_SDR1] & 0x1ff) << 16) | 0xffff; + hash = (segreg & 0x7ffff) ^ ((*address >> 12) & 0xffff); + + /* if we're simulating the 603 MMU, fill in the data and stop here */ + if (ppc->cap & PPCCAP_603_MMU) + { + ppc->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((*address >> 22) & 0x3f); + ppc->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask); + ppc->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask); + return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + } + + /* loop twice over hashes */ + for (hashnum = 0; hashnum < 2; hashnum++) + { + offs_t ptegaddr = hashbase | ((hash << 6) & hashmask); + UINT32 *ptegptr = memory_get_read_ptr(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, ptegaddr); + + /* should only have valid memory here, but make sure */ + if (ptegptr != NULL) + { + UINT32 targetupper = 0x80000000 | ((segreg & 0xffffff) << 7) | (hashnum << 6) | ((*address >> 22) & 0x3f); + int ptenum; + + /* scan PTEs */ + for (ptenum = 0; ptenum < 8; ptenum++) + if (ptegptr[BYTE_XOR_BE(ptenum * 2)] == targetupper) + { + UINT32 pteglower = ptegptr[BYTE_XOR_BE(ptenum * 2 + 1)]; + + /* verify protection; if we fail, return false and indicate a protection violation */ + if (!page_access_allowed(transtype, (segreg >> (29 + transpriv)) & 1, pteglower & 3)) + return DSISR_PROTECTED | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); + + /* update page table bits */ + if (!(intention & TRANSLATE_DEBUG_MASK)) + { + pteglower |= 0x100; + if (transtype == TRANSLATE_WRITE) + pteglower |= 0x080; + ptegptr[BYTE_XOR_BE(ptenum * 2 + 1)] = pteglower; + } + + /* otherwise we're good */ + *address = (pteglower & 0xfffff000) | (*address & 0x00000fff); + return (pteglower >> 7) & 1; + } + } + + /* invert the hash after the first round */ + hash = ~hash; + } + + /* we failed to find any match: not found */ + return DSISR_NOT_FOUND | ((transtype == TRANSLATE_WRITE) ? DSISR_STORE : 0); +} + + +/*------------------------------------------------- + ppccom_translate_address - translate an address + from logical to physical +-------------------------------------------------*/ + +int ppccom_translate_address(powerpc_state *ppc, int space, int intention, offs_t *address) +{ + /* only applies to the program address space */ + if (space != ADDRESS_SPACE_PROGRAM) + return TRUE; + + /* translation is successful if the internal routine returns 0 or 1 */ + return (ppccom_translate_address_internal(ppc, intention, address) <= 1); +} + + +/*------------------------------------------------- + ppccom_tlb_fill - handle a missing TLB entry +-------------------------------------------------*/ + +void ppccom_tlb_fill(powerpc_state *ppc) +{ + int transuser = (ppc->msr & MSR_PR) ? TRANSLATE_USER_MASK : 0; + offs_t address = ppc->param0; + int transtype = ppc->param1; + offs_t transaddr = address; + UINT32 entryval; + + /* allow for an implementation-specific override */ + if (ppc->tlb_fill != NULL && (*ppc->tlb_fill)(ppc)) + return; + + /* if we can't translate the address, just return (and fail) */ + ppc->param0 = ppccom_translate_address_internal(ppc, transtype | transuser, &transaddr); + if (PRINTF_TLB_FILL) + printf("tlb_fill: %08X (%s%s) -> ", address, (transtype == TRANSLATE_READ) ? "R" : (transtype == TRANSLATE_WRITE) ? "W" : "F", transuser ? " U" : "S"); + if (ppc->param0 > 1) + { + if (PRINTF_TLB_FILL) + printf("failed(%08X)\n", ppc->param0); + return; + } + + /* if we did translate the address, get a pointer to our entry in the TLB table and fill it in */ + if (PRINTF_TLB_FILL) + printf("succeeded(%d) -> %08X\n", ppc->param0, transaddr); + entryval = (transaddr & 0xfffff000) | TLB_READ | ((ppc->param0 & 1) ? TLB_WRITE : 0); + if (tlb_entry_allocate(ppc, ppc->tlb_index, address, entryval)) + ppc->tlb_index = (ppc->tlb_index + 1) % POWERPC_TLB_ENTRIES; +} + + +/*------------------------------------------------- + ppccom_tlb_flush - flush the entire TLB, + including fixed entries +-------------------------------------------------*/ + +void ppccom_tlb_flush(powerpc_state *ppc) +{ + int entnum; + + /* iterate over entries and invalidate them */ + for (entnum = 0; entnum < POWERPC_TLB_ENTRIES; entnum++) + tlb_entry_free(ppc, entnum); +} + + + +/*************************************************************************** + OPCODE HANDLING +***************************************************************************/ + +/*------------------------------------------------- + ppccom_execute_tlbie - execute a TLBIE + instruction +-------------------------------------------------*/ + +void ppccom_execute_tlbie(powerpc_state *ppc) +{ + offs_t address = ppc->param0; + + /* just nuke it in the table; we may have spare entries referencing it, but no harm */ + ppc->tlb_table[address >> 12] = 0; +} + + +/*------------------------------------------------- + ppccom_execute_tlbia - execute a TLBIA + instruction +-------------------------------------------------*/ + +void ppccom_execute_tlbia(powerpc_state *ppc) +{ + ppccom_tlb_flush(ppc); +} + + +/*------------------------------------------------- + ppccom_execute_tlbl - execute a TLBLD/TLBLI + instruction +-------------------------------------------------*/ + +void ppccom_execute_tlbl(powerpc_state *ppc) +{ + UINT32 address = ppc->param0; + int isitlb = ppc->param1; + UINT32 entrynum, entryval; + + /* determine entry number; we use rand() for associativity */ + entrynum = ((address >> 12) & 0x1f) | (mame_rand(Machine) & 0x20) | (isitlb ? 0x40 : 0); + + /* invalidate any existing TLB entry here */ + ppc->tlb_table[address >> 12] = 0; + + /* allocate this entry */ + entryval = (ppc->spr[SPR603_RPA] & 0xfffff000) | TLB_READ | ((ppc->spr[SPR603_RPA] & 0x80) ? TLB_WRITE : 0); + tlb_entry_allocate(ppc, POWERPC_TLB_ENTRIES + entrynum, address, entryval); + if (PRINTF_TLB_FILL) + printf("tlb_load: %08X (%sS) -> %08X\n", address, isitlb ? "F" : "R", ppc->spr[SPR603_RPA] & 0xfffff000); +} + + +/*------------------------------------------------- + ppccom_execute_mftb - execute an MFTB + instruction +-------------------------------------------------*/ + +void ppccom_execute_mftb(powerpc_state *ppc) +{ + switch (ppc->param0) + { + /* user mode timebase read */ + case SPRVEA_TBL_R: + ppc->param1 = get_timebase(ppc); + break; + case SPRVEA_TBU_R: + ppc->param1 = get_timebase(ppc) >> 32; + break; + } +} + + +/*------------------------------------------------- + ppccom_execute_mfspr - execute an MFSPR + instruction +-------------------------------------------------*/ + +void ppccom_execute_mfspr(powerpc_state *ppc) +{ + /* handle OEA SPRs */ + if (ppc->cap & PPCCAP_OEA) + { + switch (ppc->param0) + { + /* read-through no-ops */ + case SPROEA_DSISR: + case SPROEA_DAR: + case SPROEA_SDR1: + case SPROEA_SRR0: + case SPROEA_SRR1: + case SPROEA_EAR: + case SPROEA_IBAT0L: + case SPROEA_IBAT0U: + case SPROEA_IBAT1L: + case SPROEA_IBAT1U: + case SPROEA_IBAT2L: + case SPROEA_IBAT2U: + case SPROEA_IBAT3L: + case SPROEA_IBAT3U: + case SPROEA_DBAT0L: + case SPROEA_DBAT0U: + case SPROEA_DBAT1L: + case SPROEA_DBAT1U: + case SPROEA_DBAT2L: + case SPROEA_DBAT2U: + case SPROEA_DBAT3L: + case SPROEA_DBAT3U: + case SPROEA_DABR: + ppc->param1 = ppc->spr[ppc->param0]; + return; + + /* decrementer */ + case SPROEA_DEC: + ppc->param1 = get_decrementer(ppc); + return; + } + } + + /* handle 603 SPRs */ + if (ppc->cap & PPCCAP_603_MMU) + { + switch (ppc->param0) + { + /* read-through no-ops */ + case SPR603_DMISS: + case SPR603_DCMP: + case SPR603_HASH1: + case SPR603_HASH2: + case SPR603_IMISS: + case SPR603_ICMP: + case SPR603_RPA: + case SPR603_HID0: + case SPR603_HID1: + case SPR603_IABR: + case SPR603_HID2: + ppc->param1 = ppc->spr[ppc->param0]; + return; + + /* timebase */ + case SPR603_TBL_R: + ppc->param1 = get_timebase(ppc); + return; + case SPR603_TBU_R: + ppc->param1 = (get_timebase(ppc) >> 32) & 0xffffff; + return; + } + } + + /* handle 4XX SPRs */ + if (ppc->cap & PPCCAP_4XX) + { + switch (ppc->param0) + { + /* read-through no-ops */ + case SPR4XX_EVPR: + case SPR4XX_ESR: + case SPR4XX_DCCR: + case SPR4XX_ICCR: + case SPR4XX_SRR0: + case SPR4XX_SRR1: + case SPR4XX_SRR2: + case SPR4XX_SRR3: + case SPR4XX_TCR: + case SPR4XX_TSR: + ppc->param1 = ppc->spr[ppc->param0]; + return; + + /* timebase */ + case SPR4XX_TBLO: + case SPR4XX_TBLU: + ppc->param1 = get_timebase(ppc); + return; + case SPR4XX_TBHI: + case SPR4XX_TBHU: + ppc->param1 = (get_timebase(ppc) >> 32) & 0xffffff; + return; + } + } + + /* default handling */ + mame_printf_debug("SPR %03X read\n", ppc->param0); + ppc->param1 = ppc->spr[ppc->param0]; +} + + +/*------------------------------------------------- + ppccom_execute_mtspr - execute an MTSPR + instruction +-------------------------------------------------*/ + +void ppccom_execute_mtspr(powerpc_state *ppc) +{ + /* handle OEA SPRs */ + if (ppc->cap & PPCCAP_OEA) + { + switch (ppc->param0) + { + /* write-through no-ops */ + case SPROEA_DSISR: + case SPROEA_DAR: + case SPROEA_SRR0: + case SPROEA_SRR1: + case SPROEA_EAR: + case SPROEA_DABR: + ppc->spr[ppc->param0] = ppc->param1; + return; + + /* registers that affect the memory map */ + case SPROEA_SDR1: + case SPROEA_IBAT0L: + case SPROEA_IBAT0U: + case SPROEA_IBAT1L: + case SPROEA_IBAT1U: + case SPROEA_IBAT2L: + case SPROEA_IBAT2U: + case SPROEA_IBAT3L: + case SPROEA_IBAT3U: + case SPROEA_DBAT0L: + case SPROEA_DBAT0U: + case SPROEA_DBAT1L: + case SPROEA_DBAT1U: + case SPROEA_DBAT2L: + case SPROEA_DBAT2U: + case SPROEA_DBAT3L: + case SPROEA_DBAT3U: + ppc->spr[ppc->param0] = ppc->param1; + ppccom_tlb_flush(ppc); + return; + + /* decrementer */ + case SPROEA_DEC: + set_decrementer(ppc, ppc->param1); + return; + } + } + + /* handle 603 SPRs */ + if (ppc->cap & PPCCAP_603_MMU) + { + switch (ppc->param0) + { + /* read-only */ + case SPR603_DMISS: + case SPR603_DCMP: + case SPR603_HASH1: + case SPR603_HASH2: + case SPR603_IMISS: + case SPR603_ICMP: + return; + + /* write-through no-ops */ + case SPR603_RPA: + case SPR603_HID0: + case SPR603_HID1: + case SPR603_IABR: + case SPR603_HID2: + ppc->spr[ppc->param0] = ppc->param1; + return; + + /* timebase */ + case SPR603_TBL_W: + set_timebase(ppc, (get_timebase(ppc) & ~U64(0xffffffff00000000)) | ppc->param1); + return; + case SPR603_TBU_W: + set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00000000ffffffff)) | ((UINT64)ppc->param1 << 32)); + return; + } + } + + /* handle 4XX SPRs */ + if (ppc->cap & PPCCAP_4XX) + { + UINT32 oldval = ppc->spr[ppc->param0]; + switch (ppc->param0) + { + /* write-through no-ops */ + case SPR4XX_EVPR: + case SPR4XX_ESR: + case SPR4XX_DCCR: + case SPR4XX_ICCR: + case SPR4XX_SRR0: + case SPR4XX_SRR1: + case SPR4XX_SRR2: + case SPR4XX_SRR3: + ppc->spr[ppc->param0] = ppc->param1; + return; + + /* timer control register */ + case SPR4XX_TCR: + ppc->spr[SPR4XX_TCR] = ppc->param1 | (oldval & PPC4XX_TCR_WRC_MASK); + if ((oldval ^ ppc->spr[SPR4XX_TCR]) & PPC4XX_TCR_FIE) + ppc4xx_fit_callback(Machine, ppc, FALSE); + if ((oldval ^ ppc->spr[SPR4XX_TCR]) & PPC4XX_TCR_PIE) + ppc4xx_pit_callback(Machine, ppc, FALSE); + return; + + /* timer status register */ + case SPR4XX_TSR: + ppc->spr[SPR4XX_TSR] &= ~ppc->param1; + ppc4xx_set_irq_line(ppc, 0, 0); + return; + + /* PIT */ + case SPR4XX_PIT: + ppc->spr[SPR4XX_PIT] = ppc->param1; + ppc->pit_reload = ppc->param1; + ppc4xx_pit_callback(Machine, ppc, FALSE); + return; + + /* timebase */ + case SPR4XX_TBLO: + set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00ffffff00000000)) | ppc->param1); + return; + case SPR4XX_TBHI: + set_timebase(ppc, (get_timebase(ppc) & ~U64(0x00000000ffffffff)) | ((UINT64)(ppc->param1 & 0x00ffffff) << 32)); + return; + } + } + + /* default handling */ + mame_printf_debug("SPR %03X write = %08X\n", ppc->param0, ppc->param1); + ppc->spr[ppc->param0] = ppc->param1; +} + + +/*------------------------------------------------- + ppccom_execute_mfdcr - execute an MFDCR + instruction +-------------------------------------------------*/ + +void ppccom_execute_mfdcr(powerpc_state *ppc) +{ + /* handle various DCRs */ + switch (ppc->param0) + { + /* read-through no-ops */ + case DCR4XX_BR0: + case DCR4XX_BR1: + case DCR4XX_BR2: + case DCR4XX_BR3: + case DCR4XX_BR4: + case DCR4XX_BR5: + case DCR4XX_BR6: + case DCR4XX_BR7: + case DCR4XX_BESR: + case DCR4XX_DMASR: + case DCR4XX_DMACT0: + case DCR4XX_DMADA0: + case DCR4XX_DMASA0: + case DCR4XX_DMACC0: + case DCR4XX_DMACT1: + case DCR4XX_DMADA1: + case DCR4XX_DMASA1: + case DCR4XX_DMACC1: + case DCR4XX_DMACT2: + case DCR4XX_DMADA2: + case DCR4XX_DMASA2: + case DCR4XX_DMACC2: + case DCR4XX_DMACT3: + case DCR4XX_DMADA3: + case DCR4XX_DMASA3: + case DCR4XX_DMACC3: + case DCR4XX_EXIER: + case DCR4XX_EXISR: + case DCR4XX_IOCR: + ppc->param1 = ppc->dcr[ppc->param0]; + return; + } + + /* default handling */ + mame_printf_debug("DCR %03X read\n", ppc->param0); + if (ppc->param0 < ARRAY_LENGTH(ppc->dcr)) + ppc->param1 = ppc->dcr[ppc->param0]; + else + ppc->param1 = 0; +} + + +/*------------------------------------------------- + ppccom_execute_mtdcr - execute an MTDCR + instruction +-------------------------------------------------*/ + +void ppccom_execute_mtdcr(powerpc_state *ppc) +{ + UINT8 oldval; + + /* handle various DCRs */ + switch (ppc->param0) + { + /* write-through no-ops */ + case DCR4XX_BR0: + case DCR4XX_BR1: + case DCR4XX_BR2: + case DCR4XX_BR3: + case DCR4XX_BR4: + case DCR4XX_BR5: + case DCR4XX_BR6: + case DCR4XX_BR7: + case DCR4XX_BESR: + case DCR4XX_DMACT0: + case DCR4XX_DMADA0: + case DCR4XX_DMASA0: + case DCR4XX_DMACC0: + case DCR4XX_DMACT1: + case DCR4XX_DMADA1: + case DCR4XX_DMASA1: + case DCR4XX_DMACC1: + case DCR4XX_DMACT2: + case DCR4XX_DMADA2: + case DCR4XX_DMASA2: + case DCR4XX_DMACC2: + case DCR4XX_DMACT3: + case DCR4XX_DMADA3: + case DCR4XX_DMASA3: + case DCR4XX_DMACC3: + ppc->dcr[ppc->param0] = ppc->param1; + return; + + /* DMA status */ + case DCR4XX_DMASR: + ppc->dcr[DCR4XX_DMASR] &= ~(ppc->param1 & 0xfff80070); + ppc4xx_dma_update_irq_states(ppc); + return; + + /* interrupt enables */ + case DCR4XX_EXIER: + ppc->dcr[DCR4XX_EXIER] = ppc->param1; + ppc4xx_set_irq_line(ppc, 0, 0); + return; + + /* interrupt clear */ + case DCR4XX_EXISR: + ppc->dcr[ppc->param0] &= ~ppc->param1; + ppc4xx_set_irq_line(ppc, 0, 0); + return; + + /* DMA controls */ + case DCR4XX_DMACR0: + case DCR4XX_DMACR1: + case DCR4XX_DMACR2: + case DCR4XX_DMACR3: + ppc->dcr[ppc->param0] = ppc->param1; + if (ppc->param1 & PPC4XX_DMACR_CE) + ppc4xx_dma_exec(ppc, (ppc->param0 - DCR4XX_DMACR0) / 8); + ppc4xx_dma_update_irq_states(ppc); + return; + + /* I/O control */ + case DCR4XX_IOCR: + oldval = ppc->dcr[ppc->param0]; + ppc->dcr[ppc->param0] = ppc->param1; + if ((oldval ^ ppc->param1) & 0x02) + ppc4xx_spu_timer_reset(ppc); + return; + } + + /* default handling */ + mame_printf_debug("DCR %03X write = %08X\n", ppc->param0, ppc->param1); + if (ppc->param0 < ARRAY_LENGTH(ppc->dcr)) + ppc->dcr[ppc->param0] = ppc->param1; +} + + + +/*************************************************************************** + COMMON GET/SET INFO +***************************************************************************/ + +/*------------------------------------------------- + ppccom_set_info - set information about + a PowerPC CPU +-------------------------------------------------*/ + +void ppccom_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are set as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_STATE + PPC_IRQ: ppc->irq_pending = (ppc->irq_pending & ~1) | (info->i != CLEAR_LINE); break; + + case CPUINFO_INT_PC: + case CPUINFO_INT_REGISTER + PPC_PC: ppc->pc = info->i; break; + case CPUINFO_INT_REGISTER + PPC_MSR: ppc->msr = info->i; break; + case CPUINFO_INT_REGISTER + PPC_CR: ppc->cr = info->i; break; + case CPUINFO_INT_REGISTER + PPC_LR: ppc->spr[SPR_LR] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_CTR: ppc->spr[SPR_CTR] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_XER: ppc->spr[SPR_XER] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SRR0: ppc->spr[SPROEA_SRR0] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SRR1: ppc->spr[SPROEA_SRR1] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SPRG0: ppc->spr[SPROEA_SPRG0] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SPRG1: ppc->spr[SPROEA_SPRG1] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SPRG2: ppc->spr[SPROEA_SPRG2] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SPRG3: ppc->spr[SPROEA_SPRG3] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_SDR1: ppc->spr[SPROEA_SDR1] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_EXIER: ppc->dcr[DCR4XX_EXIER] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_EXISR: ppc->dcr[DCR4XX_EXISR] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_EVPR: ppc->spr[SPR4XX_EVPR] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_IOCR: ppc->dcr[DCR4XX_IOCR] = info->i; break; + + case CPUINFO_INT_REGISTER + PPC_R0: ppc->r[0] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R1: ppc->r[1] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R2: ppc->r[2] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R3: ppc->r[3] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R4: ppc->r[4] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R5: ppc->r[5] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R6: ppc->r[6] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R7: ppc->r[7] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R8: ppc->r[8] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R9: ppc->r[9] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R10: ppc->r[10] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R11: ppc->r[11] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R12: ppc->r[12] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R13: ppc->r[13] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R14: ppc->r[14] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R15: ppc->r[15] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R16: ppc->r[16] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R17: ppc->r[17] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R18: ppc->r[18] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R19: ppc->r[19] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R20: ppc->r[20] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R21: ppc->r[21] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R22: ppc->r[22] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R23: ppc->r[23] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R24: ppc->r[24] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R25: ppc->r[25] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R26: ppc->r[26] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R27: ppc->r[27] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R28: ppc->r[28] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R29: ppc->r[29] = info->i; break; + case CPUINFO_INT_REGISTER + PPC_R30: ppc->r[30] = info->i; break; + case CPUINFO_INT_SP: + case CPUINFO_INT_REGISTER + PPC_R31: ppc->r[31] = info->i; break; + } +} + + +/*------------------------------------------------- + ppccom_get_info - get information about + a PowerPC CPU +-------------------------------------------------*/ + +void ppccom_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: /* provided by core */ break; + case CPUINFO_INT_INPUT_LINES: info->i = 1; break; + case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; + case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; + case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; + case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; + case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; + case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; + case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; + case CPUINFO_INT_MAX_CYCLES: info->i = 40; break; + + case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; + case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; + case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break; + case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; + case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = POWERPC_MIN_PAGE_SHIFT;break; + + case CPUINFO_INT_INPUT_STATE + PPC_IRQ: info->i = ppc->irq_pending ? ASSERT_LINE : CLEAR_LINE; break; + + case CPUINFO_INT_PREVIOUSPC: /* optionally implemented */ break; + + case CPUINFO_INT_PC: + case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc->pc; break; + case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc->msr; break; + case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc->cr; break; + case CPUINFO_INT_REGISTER + PPC_LR: info->i = ppc->spr[SPR_LR]; break; + case CPUINFO_INT_REGISTER + PPC_CTR: info->i = ppc->spr[SPR_CTR]; break; + case CPUINFO_INT_REGISTER + PPC_XER: info->i = ppc->spr[SPR_XER]; break; + case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = ppc->spr[SPROEA_SRR0]; break; + case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = ppc->spr[SPROEA_SRR1]; break; + case CPUINFO_INT_REGISTER + PPC_SPRG0: info->i = ppc->spr[SPROEA_SPRG0]; break; + case CPUINFO_INT_REGISTER + PPC_SPRG1: info->i = ppc->spr[SPROEA_SPRG1]; break; + case CPUINFO_INT_REGISTER + PPC_SPRG2: info->i = ppc->spr[SPROEA_SPRG2]; break; + case CPUINFO_INT_REGISTER + PPC_SPRG3: info->i = ppc->spr[SPROEA_SPRG3]; break; + case CPUINFO_INT_REGISTER + PPC_SDR1: info->i = ppc->spr[SPROEA_SDR1]; break; + case CPUINFO_INT_REGISTER + PPC_EXIER: info->i = ppc->dcr[DCR4XX_EXIER]; break; + case CPUINFO_INT_REGISTER + PPC_EXISR: info->i = ppc->dcr[DCR4XX_EXISR]; break; + case CPUINFO_INT_REGISTER + PPC_EVPR: info->i = ppc->spr[SPR4XX_EVPR]; break; + case CPUINFO_INT_REGISTER + PPC_IOCR: info->i = ppc->dcr[DCR4XX_IOCR]; break; + + case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc->r[0]; break; + case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc->r[1]; break; + case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc->r[2]; break; + case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc->r[3]; break; + case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc->r[4]; break; + case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc->r[5]; break; + case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc->r[6]; break; + case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc->r[7]; break; + case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc->r[8]; break; + case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc->r[9]; break; + case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc->r[10]; break; + case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc->r[11]; break; + case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc->r[12]; break; + case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc->r[13]; break; + case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc->r[14]; break; + case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc->r[15]; break; + case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc->r[16]; break; + case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc->r[17]; break; + case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc->r[18]; break; + case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc->r[19]; break; + case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc->r[20]; break; + case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc->r[21]; break; + case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc->r[22]; break; + case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc->r[23]; break; + case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc->r[24]; break; + case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc->r[25]; break; + case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc->r[26]; break; + case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc->r[27]; break; + case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc->r[28]; break; + case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc->r[29]; break; + case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc->r[30]; break; + case CPUINFO_INT_SP: + case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc->r[31]; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_SET_INFO: /* provided by core */ break; + case CPUINFO_PTR_GET_CONTEXT: /* provided by core */ break; + case CPUINFO_PTR_SET_CONTEXT: /* provided by core */ break; + case CPUINFO_PTR_INIT: /* provided by core */ break; + case CPUINFO_PTR_RESET: /* provided by core */ break; + case CPUINFO_PTR_EXIT: /* provided by core */ break; + case CPUINFO_PTR_EXECUTE: /* provided by core */ break; + case CPUINFO_PTR_TRANSLATE: /* provided by core */ break; + case CPUINFO_PTR_DISASSEMBLE: /* provided by core */ break; + case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc->icount; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC"); break; + case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "PowerPC"); break; + case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "2.0"); break; + case CPUINFO_STR_CORE_FILE: /* provided by core */ break; + case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Aaron Giles"); break; + + case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; + + case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc->pc); break; + case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR:%08X", ppc->msr); break; + case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc->cr); break; + case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", ppc->spr[SPR_LR]); break; + case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR:%08X", ppc->spr[SPR_CTR]); break; + case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER:%08X", ppc->spr[SPR_XER]); break; + case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", ppc->spr[SPROEA_SRR0]); break; + case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", ppc->spr[SPROEA_SRR1]); break; + case CPUINFO_STR_REGISTER + PPC_SPRG0: sprintf(info->s, "SPRG0: %08X", ppc->spr[SPROEA_SPRG0]); break; + case CPUINFO_STR_REGISTER + PPC_SPRG1: sprintf(info->s, "SPRG1: %08X", ppc->spr[SPROEA_SPRG1]); break; + case CPUINFO_STR_REGISTER + PPC_SPRG2: sprintf(info->s, "SPRG2: %08X", ppc->spr[SPROEA_SPRG2]); break; + case CPUINFO_STR_REGISTER + PPC_SPRG3: sprintf(info->s, "SPRG3: %08X", ppc->spr[SPROEA_SPRG3]); break; + case CPUINFO_STR_REGISTER + PPC_SDR1: sprintf(info->s, "SDR1: %08X", ppc->spr[SPROEA_SDR1]); break; + case CPUINFO_STR_REGISTER + PPC_EXIER: sprintf(info->s, "EXIER: %08X", ppc->dcr[DCR4XX_EXIER]); break; + case CPUINFO_STR_REGISTER + PPC_EXISR: sprintf(info->s, "EXISR: %08X", ppc->dcr[DCR4XX_EXISR]); break; + case CPUINFO_STR_REGISTER + PPC_EVPR: sprintf(info->s, "EVPR: %08X", ppc->spr[SPR4XX_EVPR]); break; + case CPUINFO_STR_REGISTER + PPC_IOCR: sprintf(info->s, "IOCR: %08X", ppc->dcr[DCR4XX_EXISR]); break; + + case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc->r[0]); break; + case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc->r[1]); break; + case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc->r[2]); break; + case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc->r[3]); break; + case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc->r[4]); break; + case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc->r[5]); break; + case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc->r[6]); break; + case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc->r[7]); break; + case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc->r[8]); break; + case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc->r[9]); break; + case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10:%08X", ppc->r[10]); break; + case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11:%08X", ppc->r[11]); break; + case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12:%08X", ppc->r[12]); break; + case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13:%08X", ppc->r[13]); break; + case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14:%08X", ppc->r[14]); break; + case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15:%08X", ppc->r[15]); break; + case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16:%08X", ppc->r[16]); break; + case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17:%08X", ppc->r[17]); break; + case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18:%08X", ppc->r[18]); break; + case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19:%08X", ppc->r[19]); break; + case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20:%08X", ppc->r[20]); break; + case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21:%08X", ppc->r[21]); break; + case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22:%08X", ppc->r[22]); break; + case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23:%08X", ppc->r[23]); break; + case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24:%08X", ppc->r[24]); break; + case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25:%08X", ppc->r[25]); break; + case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26:%08X", ppc->r[26]); break; + case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27:%08X", ppc->r[27]); break; + case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28:%08X", ppc->r[28]); break; + case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29:%08X", ppc->r[29]); break; + case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30:%08X", ppc->r[30]); break; + case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31:%08X", ppc->r[31]); break; + } +} + + + +/*************************************************************************** + OEA HELPERS +***************************************************************************/ + +/*------------------------------------------------- + decrementer_int_callback - callback that fires + whenever a decrementer interrupt is generated +-------------------------------------------------*/ + +static TIMER_CALLBACK( decrementer_int_callback ) +{ + powerpc_state *ppc = ptr; + UINT64 cycles_until_next; + + /* set the decrementer IRQ state */ + ppc->irq_pending |= 0x02; + + /* advance by another full rev */ + ppc->dec_zero_cycles += (UINT64)ppc->tb_divisor << 32; + cycles_until_next = ppc->dec_zero_cycles - cpunum_gettotalcycles(ppc->cpunum); + timer_adjust_oneshot(ppc->decrementer_int_timer, ATTOTIME_IN_CYCLES(cycles_until_next, ppc->cpunum), 0); +} + + + +/*************************************************************************** + EMBEDDED 4XX HELPERS +***************************************************************************/ + +#if (HAS_PPC403GA || HAS_PPC403GCX) + +/*------------------------------------------------- + ppc4xx_set_irq_line - PowerPC 4XX-specific + IRQ line management +-------------------------------------------------*/ + +static void ppc4xx_set_irq_line(powerpc_state *ppc, UINT32 bitmask, int state) +{ + UINT32 oldstate = ppc->irqstate; + UINT32 levelmask; + + /* set or clear the appropriate bit */ + if (state != CLEAR_LINE) + ppc->irqstate |= bitmask; + else + ppc->irqstate &= ~bitmask; + + /* if the state changed to on, edge trigger the interrupt */ + if (((ppc->irqstate ^ oldstate) & bitmask) && (ppc->irqstate & bitmask)) + ppc->dcr[DCR4XX_EXISR] |= bitmask; + + /* pass through all level-triggered interrupts */ + levelmask = PPC4XX_IRQ_BIT_CRITICAL | PPC4XX_IRQ_BIT_SPUR | PPC4XX_IRQ_BIT_SPUT; + levelmask |= PPC4XX_IRQ_BIT_JTAGR | PPC4XX_IRQ_BIT_JTAGT; + levelmask |= PPC4XX_IRQ_BIT_DMA0 | PPC4XX_IRQ_BIT_DMA1 | PPC4XX_IRQ_BIT_DMA2 | PPC4XX_IRQ_BIT_DMA3; + if (!(ppc->dcr[DCR4XX_IOCR] & 0x80000000)) levelmask |= PPC4XX_IRQ_BIT_EXT0; + if (!(ppc->dcr[DCR4XX_IOCR] & 0x20000000)) levelmask |= PPC4XX_IRQ_BIT_EXT1; + if (!(ppc->dcr[DCR4XX_IOCR] & 0x08000000)) levelmask |= PPC4XX_IRQ_BIT_EXT2; + if (!(ppc->dcr[DCR4XX_IOCR] & 0x02000000)) levelmask |= PPC4XX_IRQ_BIT_EXT3; + if (!(ppc->dcr[DCR4XX_IOCR] & 0x00800000)) levelmask |= PPC4XX_IRQ_BIT_EXT4; + ppc->dcr[DCR4XX_EXISR] = (ppc->dcr[DCR4XX_EXISR] & ~levelmask) | (ppc->irqstate & levelmask); + + /* update the IRQ status */ + ppc->irq_pending = ((ppc->dcr[DCR4XX_EXISR] & ppc->dcr[DCR4XX_EXIER]) != 0); + if ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) && (ppc->spr[SPR4XX_TSR] & PPC4XX_TSR_FIS)) + ppc->irq_pending = TRUE; + if ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && (ppc->spr[SPR4XX_TSR] & PPC4XX_TSR_PIS)) + ppc->irq_pending = TRUE; +} + + +/*------------------------------------------------- + ppc4xx_get_irq_line - PowerPC 4XX-specific + IRQ line state getter +-------------------------------------------------*/ + +static int ppc4xx_get_irq_line(powerpc_state *ppc, UINT32 bitmask) +{ + return (ppc->irqstate & bitmask) ? ASSERT_LINE : CLEAR_LINE; +} + + +/*------------------------------------------------- + ppc4xx_dma_update_irq_states - update the IRQ + state for each DMA channel +-------------------------------------------------*/ + +static void ppc4xx_dma_update_irq_states(powerpc_state *ppc) +{ + int dmachan; + + /* update the IRQ state for each DMA channel */ + for (dmachan = 0; dmachan < 4; dmachan++) + if ((ppc->dcr[DCR4XX_DMACR0 + 8 * dmachan] & PPC4XX_DMACR_CIE) && (ppc->dcr[DCR4XX_DMASR] & (1 << (27 - dmachan)))) + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), ASSERT_LINE); + else + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_DMA(dmachan), CLEAR_LINE); +} + + +/*------------------------------------------------- + ppc4xx_dma_decrement_count - decrement the + count on a channel and interrupt if configured + to do so +-------------------------------------------------*/ + +static int ppc4xx_dma_decrement_count(powerpc_state *ppc, int dmachan) +{ + UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; + + /* decrement the counter */ + dmaregs[DCR4XX_DMACT0]--; + + /* if non-zero, we keep going */ + if ((dmaregs[DCR4XX_DMACT0] & 0xffff) != 0) + return FALSE; + + /* set the complete bit and handle interrupts */ + ppc->dcr[DCR4XX_DMASR] |= 1 << (27 - dmachan); + ppc4xx_dma_update_irq_states(ppc); + return TRUE; +} + + +/*------------------------------------------------- + ppc4xx_dma_fetch_transmit_byte - fetch a byte + to send to a peripheral +-------------------------------------------------*/ + +static int ppc4xx_dma_fetch_transmit_byte(powerpc_state *ppc, int dmachan, UINT8 *byte) +{ + UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; + + /* if the channel is not enabled, fail */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) + return FALSE; + + /* if no transfers remaining, fail */ + if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0) + return FALSE; + + /* fetch the data */ + cpuintrf_push_context(ppc->cpunum); + *byte = program_read_byte(dmaregs[DCR4XX_DMADA0]++); + ppc4xx_dma_decrement_count(ppc, dmachan); + cpuintrf_pop_context(); + return TRUE; +} + + +/*------------------------------------------------- + ppc4xx_dma_handle_receive_byte - receive a byte + transmitted by a peripheral +-------------------------------------------------*/ + +static int ppc4xx_dma_handle_receive_byte(powerpc_state *ppc, int dmachan, UINT8 byte) +{ + UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; + + /* if the channel is not enabled, fail */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) + return FALSE; + + /* if no transfers remaining, fail */ + if ((dmaregs[DCR4XX_DMACT0] & 0xffff) == 0) + return FALSE; + + /* store the data */ + cpuintrf_push_context(ppc->cpunum); + program_write_byte(dmaregs[DCR4XX_DMADA0]++, byte); + ppc4xx_dma_decrement_count(ppc, dmachan); + cpuintrf_pop_context(); + return TRUE; +} + + +/*------------------------------------------------- + ppc4xx_dma_execute - execute a DMA operation + if one is pending +-------------------------------------------------*/ + +static void ppc4xx_dma_exec(powerpc_state *ppc, int dmachan) +{ + static const UINT8 dma_transfer_width[4] = { 1, 2, 4, 16 }; + UINT32 *dmaregs = &ppc->dcr[8 * dmachan]; + INT32 destinc, srcinc; + UINT8 width; + + /* skip if not enabled */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CE)) + return; + + /* check for unsupported features */ + if (!(dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TCE)) + fatalerror("ppc4xx_dma_exec: DMA_TCE == 0"); + if (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_CH) + fatalerror("ppc4xx_dma_exec: DMA chaining not implemented"); + + /* transfer mode */ + switch ((dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_TM_MASK) >> 21) + { + /* buffered mode DMA */ + case 0: + /* nothing to do; this happens asynchronously and is driven by the SPU */ + break; + + /* fly-by mode DMA */ + case 1: + fatalerror("ppc4xx_dma_exec: fly-by DMA not implemented"); + break; + + /* software initiated memory-to-memory mode DMA */ + case 2: + width = dma_transfer_width[(dmaregs[DCR4XX_DMACR0] >> 26) & 0x3]; + srcinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_SAI) ? width : 0; + destinc = (dmaregs[DCR4XX_DMACR0] & PPC4XX_DMACR_DAI) ? width : 0; + + switch (width) + { + /* byte transfer */ + case 1: + do + { + program_write_byte(dmaregs[DCR4XX_DMADA0], program_read_byte(dmaregs[DCR4XX_DMASA0])); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* word transfer */ + case 2: + do + { + program_write_word(dmaregs[DCR4XX_DMADA0], program_read_word(dmaregs[DCR4XX_DMASA0])); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* dword transfer */ + case 4: + do + { + program_write_dword(dmaregs[DCR4XX_DMADA0], program_read_dword(dmaregs[DCR4XX_DMASA0])); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + + /* 16-byte transfer */ + case 16: + do + { + program_write_qword(dmaregs[DCR4XX_DMADA0], program_read_qword(dmaregs[DCR4XX_DMASA0])); + program_write_qword(dmaregs[DCR4XX_DMADA0] + 8, program_read_qword(dmaregs[DCR4XX_DMASA0] + 8)); + dmaregs[DCR4XX_DMASA0] += srcinc; + dmaregs[DCR4XX_DMADA0] += destinc; + } while (!ppc4xx_dma_decrement_count(ppc, dmachan)); + break; + } + break; + + /* hardware initiated memory-to-memory mode DMA */ + case 3: + fatalerror("ppc4xx_dma_exec: HW mem-to-mem DMA not implemented"); + break; + } +} + + +/*------------------------------------------------- + ppc4xx_fit_callback - FIT timer callback +-------------------------------------------------*/ + +static TIMER_CALLBACK( ppc4xx_fit_callback ) +{ + powerpc_state *ppc = ptr; + + /* if this is a real callback and we are enabled, signal an interrupt */ + if (param) + { + ppc->spr[SPR4XX_TSR] |= PPC4XX_TSR_FIS; + ppc4xx_set_irq_line(ppc, 0, 0); + } + + /* update ourself for the next interval if we are enabled */ + if (ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_FIE) + { + UINT32 timebase = get_timebase(ppc); + UINT32 interval = 0x200 << (4 * ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_FP_MASK) >> 24)); + UINT32 target = (timebase + interval) & ~(interval - 1); + timer_adjust_oneshot(ppc->fit_timer, ATTOTIME_IN_CYCLES((target + 1 - timebase) / ppc->tb_divisor, ppc->cpunum), TRUE); + } + + /* otherwise, turn ourself off */ + else + timer_adjust_oneshot(ppc->fit_timer, attotime_never, FALSE); +} + + +/*------------------------------------------------- + ppc4xx_pit_callback - PIT timer callback +-------------------------------------------------*/ + +static TIMER_CALLBACK( ppc4xx_pit_callback ) +{ + powerpc_state *ppc = ptr; + + /* if this is a real callback and we are enabled, signal an interrupt */ + if (param) + { + ppc->spr[SPR4XX_TSR] |= PPC4XX_TSR_PIS; + ppc4xx_set_irq_line(ppc, 0, 0); + } + + /* update ourself for the next interval if we are enabled and we are either being + forced to update, or we are in auto-reload mode */ + if ((ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_PIE) && ppc->pit_reload != 0 && (!param || (ppc->spr[SPR4XX_TCR] & PPC4XX_TCR_ARE))) + { + UINT32 timebase = get_timebase(ppc); + UINT32 interval = ppc->pit_reload; + UINT32 target = timebase + interval; + timer_adjust_oneshot(ppc->pit_timer, ATTOTIME_IN_CYCLES((target + 1 - timebase) / ppc->tb_divisor, ppc->cpunum), TRUE); + } + + /* otherwise, turn ourself off */ + else + timer_adjust_oneshot(ppc->pit_timer, attotime_never, FALSE); +} + + +/*------------------------------------------------- + ppc4xx_spu_update_irq_states - update the IRQ + state for the SPU +-------------------------------------------------*/ + +static void ppc4xx_spu_update_irq_states(powerpc_state *ppc) +{ + /* check for receive buffer full interrupt */ + if ((ppc->spu.regs[SPU4XX_RX_COMMAND] & 0x60) == 0x20 && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x80)) + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); + + /* check for receive error interrupt */ + else if ((ppc->spu.regs[SPU4XX_RX_COMMAND] & 0x10) && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x78)) + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUR, ASSERT_LINE); + + /* clear otherwise */ + else + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUR, CLEAR_LINE); + + /* check for transmit buffer empty interrupt */ + if ((ppc->spu.regs[SPU4XX_TX_COMMAND] & 0x60) == 0x20 && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x04)) + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); + + /* check for shift register empty interrupt */ + else if ((ppc->spu.regs[SPU4XX_TX_COMMAND] & 0x10) && (ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x02)) + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUT, ASSERT_LINE); + + /* clear otherwise */ + else + ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_SPUT, CLEAR_LINE); +} + + +/*------------------------------------------------- + ppc4xx_spu_rx_data - serial port data receive +-------------------------------------------------*/ + +static void ppc4xx_spu_rx_data(powerpc_state *ppc, UINT8 data) +{ + fatalerror("ppc4xx_spu_rx_data unimplemented\n"); +} + + +/*------------------------------------------------- + ppc4xx_spu_timer_reset - reset and recompute + the transmit/receive timer +-------------------------------------------------*/ + +static void ppc4xx_spu_timer_reset(powerpc_state *ppc) +{ + UINT8 enabled = (ppc->spu.regs[SPU4XX_RX_COMMAND] | ppc->spu.regs[SPU4XX_TX_COMMAND]) & 0x80; + + /* if we're enabled, reset at the current baud rate */ + if (enabled) + { + attotime clockperiod = ATTOTIME_IN_HZ((ppc->dcr[DCR4XX_IOCR] & 0x02) ? 3686400 : 33333333); + int divisor = ((ppc->spu.regs[SPU4XX_BAUD_DIVISOR_H] * 256 + ppc->spu.regs[SPU4XX_BAUD_DIVISOR_L]) & 0xfff) + 1; + int bpc = 7 + ((ppc->spu.regs[SPU4XX_CONTROL] & 8) >> 3) + 1 + (ppc->spu.regs[SPU4XX_CONTROL] & 1); + attotime charperiod = attotime_mul(clockperiod, divisor * 16 * bpc); + timer_adjust_periodic(ppc->spu.timer, charperiod, 0, charperiod); + if (PRINTF_SPU) + mame_printf_debug("ppc4xx_spu_timer_reset: baud rate = %.0f\n", ATTOSECONDS_TO_HZ(charperiod.attoseconds) * bpc); + } + + /* otherwise, disable the timer */ + else + timer_adjust_oneshot(ppc->spu.timer, attotime_never, 0); +} + + +/*------------------------------------------------- + ppc4xx_spu_callback - serial port send/receive + timer +-------------------------------------------------*/ + +static TIMER_CALLBACK( ppc4xx_spu_callback ) +{ + powerpc_state *ppc = ptr; + UINT8 rxbyte; + + /* transmit enabled? */ + if (ppc->spu.regs[SPU4XX_TX_COMMAND] & 0x80) + { + int operation = (ppc->spu.regs[SPU4XX_TX_COMMAND] >> 5) & 3; + + /* if we have data to transmit, do it now */ + if (!(ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x04)) + { + /* if we have a transmit handler, send it that way */ + if (ppc->spu.tx_handler != NULL) + (*ppc->spu.tx_handler)(ppc->spu.txbuf); + + /* indicate that we have moved it to the shift register */ + ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x04; + ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x02; + } + + /* otherwise, clear the shift register */ + else if (!(ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x02)) + ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x02; + + /* handle DMA */ + if (operation >= 2 && ppc4xx_dma_fetch_transmit_byte(ppc, operation, &ppc->spu.txbuf)) + ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; + } + + /* receive enabled? */ + if (ppc->spu.regs[SPU4XX_RX_COMMAND] & 0x80) + if (ppc->spu.rx_handler != NULL && (*ppc->spu.rx_handler)(&rxbyte)) + { + int operation = (ppc->spu.regs[SPU4XX_RX_COMMAND] >> 5) & 3; + + /* if we're not full, copy data to the buffer and update the line status */ + if (!(ppc->spu.regs[SPU4XX_LINE_STATUS] & 0x80)) + { + ppc->spu.rxbuf = rxbyte; + ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x80; + } + + /* otherwise signal an overrun */ + else + { + ppc->spu.regs[SPU4XX_LINE_STATUS] |= 0x20; + goto updateirq; + } + + /* handle DMA */ + if (operation >= 2 && ppc4xx_dma_handle_receive_byte(ppc, operation, ppc->spu.rxbuf)) + ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; + } + + /* update the final IRQ states */ +updateirq: + ppc4xx_spu_update_irq_states(ppc); +} + + +/*------------------------------------------------- + ppc4xx_spu_r - serial port read handler +-------------------------------------------------*/ + +static READ8_HANDLER( ppc4xx_spu_r ) +{ + powerpc_state *ppc = activecpu_get_info_ptr(CPUINFO_PTR_CONTEXT); + UINT8 result = 0xff; + + switch (offset) + { + case SPU4XX_BUFFER: + result = ppc->spu.rxbuf; + ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x80; + break; + + default: + if (offset < ARRAY_LENGTH(ppc->spu.regs)) + result = ppc->spu.regs[offset]; + break; + } + if (PRINTF_SPU) + mame_printf_debug("spu_r(%d) = %02X\n", offset, result); + return result; +} + + +/*------------------------------------------------- + ppc4xx_spu_w - serial port write handler +-------------------------------------------------*/ + +static WRITE8_HANDLER( ppc4xx_spu_w ) +{ + powerpc_state *ppc = activecpu_get_info_ptr(CPUINFO_PTR_CONTEXT); + UINT8 oldstate, newstate; + + if (PRINTF_SPU) + mame_printf_debug("spu_w(%d) = %02X\n", offset, data); + switch (offset) + { + /* clear error bits */ + case SPU4XX_LINE_STATUS: + ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~(data & 0xf8); + ppc4xx_spu_update_irq_states(ppc); + break; + + /* enable/disable the timer if one of these is enabled */ + case SPU4XX_RX_COMMAND: + case SPU4XX_TX_COMMAND: + oldstate = ppc->spu.regs[SPU4XX_RX_COMMAND] | ppc->spu.regs[SPU4XX_TX_COMMAND]; + ppc->spu.regs[offset] = data; + newstate = ppc->spu.regs[SPU4XX_RX_COMMAND] | ppc->spu.regs[SPU4XX_TX_COMMAND]; + if ((oldstate ^ newstate) & 0x80) + ppc4xx_spu_timer_reset(ppc); + ppc4xx_spu_update_irq_states(ppc); + break; + + /* if the divisor changes, we need to update the timer */ + case SPU4XX_BAUD_DIVISOR_H: + case SPU4XX_BAUD_DIVISOR_L: + if (data != ppc->spu.regs[offset]) + { + ppc->spu.regs[offset] = data; + ppc4xx_spu_timer_reset(ppc); + } + break; + + /* if the number of data bits or stop bits changes, we need to update the timer */ + case SPU4XX_CONTROL: + oldstate = ppc->spu.regs[offset]; + ppc->spu.regs[offset] = data; + if ((oldstate ^ data) & 0x09) + ppc4xx_spu_timer_reset(ppc); + break; + + break; + + case SPU4XX_BUFFER: + /* write to the transmit buffer and mark it full */ + ppc->spu.txbuf = data; + ppc->spu.regs[SPU4XX_LINE_STATUS] &= ~0x04; + break; + + default: + if (offset < ARRAY_LENGTH(ppc->spu.regs)) + ppc->spu.regs[offset] = data; + break; + } +} + + + +/*------------------------------------------------- + internal_ppc4xx - internal address map for + the 4XX +-------------------------------------------------*/ + +static ADDRESS_MAP_START( internal_ppc4xx, ADDRESS_SPACE_PROGRAM, 32 ) + AM_RANGE(0x40000000, 0x4000000f) AM_READWRITE8(ppc4xx_spu_r, ppc4xx_spu_w, 0xffffffff) +ADDRESS_MAP_END + + + +/*------------------------------------------------- + ppc4xx_set_info - PowerPC 4XX-specific + information setter +-------------------------------------------------*/ + +void ppc4xx_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_0: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT0, info->i); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_1: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT1, info->i); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_2: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT2, info->i); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_3: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT3, info->i); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_4: ppc4xx_set_irq_line(ppc, PPC4XX_IRQ_BIT_EXT4, info->i); break; + case CPUINFO_INT_PPC_RX_DATA: ppc4xx_spu_rx_data(ppc, info->i); break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_SPU_RX_HANDLER: ppc->spu.rx_handler = (ppc4xx_spu_rx_handler)info->f; break; + case CPUINFO_PTR_SPU_TX_HANDLER: ppc->spu.tx_handler = (ppc4xx_spu_tx_handler)info->f; break; + + /* --- everything else is handled generically --- */ + default: ppccom_set_info(ppc, state, info); break; + } +} + + +/*------------------------------------------------- + ppc4xx_get_info - PowerPC 4XX-specific + information getter +-------------------------------------------------*/ + +void ppc4xx_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_INPUT_LINES: info->i = 5; break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_0: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT0); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_1: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT1); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_2: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT2); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_3: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT3); break; + case CPUINFO_INT_INPUT_STATE + PPC_IRQ_LINE_4: info->i = ppc4xx_get_irq_line(ppc, PPC4XX_IRQ_BIT_EXT4); break; + + case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; + case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 0; break; + case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: /* provided per-CPU */ break; + case CPUINFO_PTR_INTERNAL_MEMORY_MAP + ADDRESS_SPACE_PROGRAM: info->internal_map32 = address_map_internal_ppc4xx; break; + + /* --- everything else is handled generically --- */ + default: ppccom_get_info(ppc, state, info); break; + } +} + +#endif diff --git a/src/emu/cpu/powerpc/ppccom.h b/src/emu/cpu/powerpc/ppccom.h new file mode 100644 index 00000000000..9f78534c559 --- /dev/null +++ b/src/emu/cpu/powerpc/ppccom.h @@ -0,0 +1,611 @@ +/*************************************************************************** + + ppccom.h + + Common PowerPC definitions and functions + +***************************************************************************/ + +#ifndef __PPCCOM_H__ +#define __PPCCOM_H__ + +#include "cpuintrf.h" +#include "ppc.h" + + +/*************************************************************************** + WIDE-SCALE CONTROLS +***************************************************************************/ + +#define SIMULATE_603_TLB (0) + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* core parameters */ +#define POWERPC_MIN_PAGE_SHIFT 12 +#define POWERPC_MIN_PAGE_SIZE (1 << POWERPC_MIN_PAGE_SHIFT) +#define POWERPC_MIN_PAGE_MASK (POWERPC_MIN_PAGE_SIZE - 1) +#define POWERPC_TLB_ENTRIES 128 +#define PPC603_FIXED_TLB_ENTRIES 128 + + +/* internal capabilities flags */ +#define PPCCAP_OEA 0x01 /* TRUE if we conform to the OEA */ +#define PPCCAP_VEA 0x02 /* TRUE if we conform to the VEA */ +#define PPCCAP_FPU 0x04 /* TRUE if we have an FPU */ +#define PPCCAP_MISALIGNED 0x08 /* TRUE if misaligned accesses are supported */ +#define PPCCAP_4XX 0x10 /* TRUE if we are a non-OEA 4XX class chip */ +#define PPCCAP_603_MMU 0x20 /* TRUE if we have 603-class MMU features */ + + +/* bits in our internal TLB */ +#define TLB_READ 0x01 /* reads are allowed */ +#define TLB_WRITE 0x02 /* writes are allowed */ + + +/* PowerPC flavors */ +enum _powerpc_flavor +{ + PPC_MODEL_403GA = 0x00200000, + PPC_MODEL_403GB = 0x00200100, + PPC_MODEL_403GC = 0x00200200, + PPC_MODEL_403GCX = 0x00201400, + PPC_MODEL_405GP = 0x40110000, + PPC_MODEL_601 = 0x00010000, + PPC_MODEL_603 = 0x00030000, /* "Wart" */ + PPC_MODEL_604 = 0x00040000, /* "Zephyr" */ + PPC_MODEL_602 = 0x00050200, /* "Galahad" */ + PPC_MODEL_603E = 0x00060103, /* "Stretch", version 1.3 */ + PPC_MODEL_603EV = 0x00070000, /* "Valiant" */ + PPC_MODEL_603R = 0x00071202, /* "Goldeneye", version 2.1 */ + PPC_MODEL_740 = 0x00080301, /* "Arthur", version 3.1 */ + PPC_MODEL_750 = PPC_MODEL_740, + PPC_MODEL_740P = 0x00080202, /* "Conan Doyle", version 1.2 */ + PPC_MODEL_750P = PPC_MODEL_740P, + PPC_MODEL_755 = 0x00083203, /* "Goldfinger", version 2.3 */ + PPC_MODEL_7400 = 0x000c0209, /* "Max", version 2.9 */ + PPC_MODEL_7410 = 0x800c1104, /* "Nitro", version 3.4 */ + PPC_MODEL_7450 = 0x80000201, /* "Vger", version 2.1 */ + PPC_MODEL_7451 = 0x80000203, /* "Vger", version 2.3 */ + PPC_MODEL_7441 = PPC_MODEL_7451, + PPC_MODEL_7455 = 0x80010303, /* "Apollo 6", version 3.3 */ + PPC_MODEL_7445 = PPC_MODEL_7455, + PPC_MODEL_7457 = 0x80020101, /* "Apollo 7", version 1.1 */ + PPC_MODEL_MPC8240 = 0x00810101, /* "Kahlua" */ + PPC_MODEL_MPC8241 = 0x80811014, /* "Kahlua Lt" */ + PPC_MODEL_MPC8245 = 0x80811014, /* "Kahlua II" */ +}; +typedef enum _powerpc_flavor powerpc_flavor; + + +/* exception types */ +enum +{ + EXCEPTION_RESET = 1, + EXCEPTION_MACHCHECK = 2, + EXCEPTION_DSI = 3, + EXCEPTION_ISI = 4, + EXCEPTION_EI = 5, + EXCEPTION_ALIGN = 6, + EXCEPTION_PROGRAM = 7, + EXCEPTION_NOFPU = 8, + EXCEPTION_DECREMENT = 9, + EXCEPTION_SYSCALL = 12, + EXCEPTION_TRACE = 13, + EXCEPTION_FPASSIST = 14, + EXCEPTION_ITLBMISS = 16, /* PPCCAP_603_MMU */ + EXCEPTION_DTLBMISSL = 17, /* PPCCAP_603_MMU */ + EXCEPTION_DTLBMISSS = 18, /* PPCCAP_603_MMU */ + EXCEPTION_COUNT +}; + + +/* SPRs */ +enum +{ + /* UISA SPR register indexes */ + SPR_XER = 0x001, /* R/W Fixed Point Exception Register */ + SPR_LR = 0x008, /* R/W Link Register */ + SPR_CTR = 0x009, /* R/W Count Register */ + + /* VEA SPR register indexes */ + SPRVEA_TBL_R = 0x10c, /* R Time Base Low */ + SPRVEA_TBU_R = 0x10d, /* R Time Base High */ + + /* OEA SPR register indexes */ + SPROEA_DSISR = 0x012, /* R/W DSI Status Register */ + SPROEA_DAR = 0x013, /* R/W Data Address Register */ + SPROEA_DEC = 0x016, /* R/W Decrementer Register */ + SPROEA_SDR1 = 0x019, /* R/W Page Table Configuration */ + SPROEA_SRR0 = 0x01a, /* R/W Machine Status Save/Restore Register 0 */ + SPROEA_SRR1 = 0x01b, /* R/W Machine Status Save/Restore Register 1 */ + SPROEA_SPRG0 = 0x110, /* R/W SPR General 0 */ + SPROEA_SPRG1 = 0x111, /* R/W SPR General 1 */ + SPROEA_SPRG2 = 0x112, /* R/W SPR General 2 */ + SPROEA_SPRG3 = 0x113, /* R/W SPR General 3 */ + SPROEA_ASR = 0x118, /* R/W Address Space Register (64-bit only) */ + SPROEA_EAR = 0x11a, /* R/W External Access Register */ + SPROEA_PVR = 0x11f, /* R Processor Version Number */ + SPROEA_IBAT0U = 0x210, /* R/W Instruction BAT 0 Upper */ + SPROEA_IBAT0L = 0x211, /* R/W Instruction BAT 0 Lower */ + SPROEA_IBAT1U = 0x212, /* R/W Instruction BAT 1 Upper */ + SPROEA_IBAT1L = 0x213, /* R/W Instruction BAT 1 Lower */ + SPROEA_IBAT2U = 0x214, /* R/W Instruction BAT 2 Upper */ + SPROEA_IBAT2L = 0x215, /* R/W Instruction BAT 2 Lower */ + SPROEA_IBAT3U = 0x216, /* R/W Instruction BAT 3 Upper */ + SPROEA_IBAT3L = 0x217, /* R/W Instruction BAT 3 Lower */ + SPROEA_DBAT0U = 0x218, /* R/W Data BAT 0 Upper */ + SPROEA_DBAT0L = 0x219, /* R/W Data BAT 0 Lower */ + SPROEA_DBAT1U = 0x21a, /* R/W Data BAT 1 Upper */ + SPROEA_DBAT1L = 0x21b, /* R/W Data BAT 1 Lower */ + SPROEA_DBAT2U = 0x21c, /* R/W Data BAT 2 Upper */ + SPROEA_DBAT2L = 0x21d, /* R/W Data BAT 2 Lower */ + SPROEA_DBAT3U = 0x21e, /* R/W Data BAT 3 Upper */ + SPROEA_DBAT3L = 0x21f, /* R/W Data BAT 3 Lower */ + SPROEA_DABR = 0x3f5, /* R/W Data Address Breakpoint Register */ + + /* PowerPC 4XX SPR register indexes */ + SPR4XX_SRR0 = 0x01a, /* R/W 403GA Machine Status Save/Restore Register 0 */ + SPR4XX_SRR1 = 0x01b, /* R/W 403GA Machine Status Save/Restore Register 1 */ + SPR4XX_SPRG0 = 0x110, /* R/W 403GA SPR General 0 */ + SPR4XX_SPRG1 = 0x111, /* R/W 403GA SPR General 1 */ + SPR4XX_SPRG2 = 0x112, /* R/W 403GA SPR General 2 */ + SPR4XX_SPRG3 = 0x113, /* R/W 403GA SPR General 3 */ + SPR4XX_PVR = 0x11f, /* R 403GA Processor Version Number */ + SPR4XX_SGR = 0x3b9, /* R/W 403GCX Storage Guarded Register */ + SPR4XX_DCWR = 0x3ba, /* R/W 403GCX Data Cache Write Through */ + SPR4XX_PID = 0x3b1, /* R/W 403GCX Process ID */ + SPR4XX_TBHU = 0x3cc, /* R/W 403GCX Time Base High User-mode */ + SPR4XX_TBLU = 0x3cd, /* R/W 403GCX Time Base Low User-mode */ + SPR4XX_ICDBDR = 0x3d3, /* R 403GA 406GA Instruction Cache Debug Data Register */ + SPR4XX_ESR = 0x3d4, /* R/W 403GA 406GA Exception Syndrome Register */ + SPR4XX_DEAR = 0x3d5, /* R 403GA 406GA Data Exception Address Register */ + SPR4XX_EVPR = 0x3d6, /* R/W 403GA 406GA Exception Vector Prefix Register */ + SPR4XX_CDBCR = 0x3d7, /* R/W 403GA 406GA Cache Debug Control Register */ + SPR4XX_TSR = 0x3d8, /* R/C 403GA 406GA Timer Status Register */ + SPR4XX_TCR = 0x3da, /* R/W 403GA 406GA Timer Control Register */ + SPR4XX_PIT = 0x3db, /* R/W 403GA 406GA Programmable Interval Timer */ + SPR4XX_TBHI = 0x3dc, /* R/W 403GA 406GA Time Base High */ + SPR4XX_TBLO = 0x3dd, /* R/W 403GA 406GA Time Base Low */ + SPR4XX_SRR2 = 0x3de, /* R/W 403GA 406GA Machine Status Save/Restore Register 2 */ + SPR4XX_SRR3 = 0x3df, /* R/W 403GA 406GA Machine Status Save/Restore Register 3 */ + SPR4XX_DBSR = 0x3f0, /* R/C 403GA 406GA Debug Status Register */ + SPR4XX_DBCR = 0x3f2, /* R/W 403GA 406GA Debug Control Register */ + SPR4XX_IAC1 = 0x3f4, /* R/W 403GA 406GA Instruction Address Compare 1 */ + SPR4XX_IAC2 = 0x3f5, /* R/W 403GA 406GA Instruction Address Compare 2 */ + SPR4XX_DAC1 = 0x3f6, /* R/W 403GA 406GA Data Address Compare 1 */ + SPR4XX_DAC2 = 0x3f7, /* R/W 403GA 406GA Data Address Compare 2 */ + SPR4XX_DCCR = 0x3fa, /* R/W 403GA 406GA Data Cache Cacheability Register */ + SPR4XX_ICCR = 0x3fb, /* R/W 403GA 406GA Instruction Cache Cacheability Registe */ + SPR4XX_PBL1 = 0x3fc, /* R/W 403GA 406GA Protection Bound Lower 1 */ + SPR4XX_PBU1 = 0x3fd, /* R/W 403GA 406GA Protection Bound Upper 1 */ + SPR4XX_PBL2 = 0x3fe, /* R/W 403GA 406GA Protection Bound Lower 2 */ + SPR4XX_PBU2 = 0x3ff, /* R/W 403GA 406GA Protection Bound Upper 2 */ + + /* PowerPC 602 SPR register indexes */ + SPR602_TCR = 0x3d8, /* 602 */ + SPR602_IBR = 0x3da, /* 602 */ + SPR602_ESASRR = 0x3db, /* 602 */ + SPR602_SEBR = 0x3de, /* 602 */ + SPR602_SER = 0x3df, /* 602 */ + SPR602_SP = 0x3fd, /* 602 */ + SPR602_LT = 0x3fe, /* 602 */ + + /* PowerPC 603 SPR register indexes */ + SPR603_TBL_R = 0x10c, /* R 603 Time Base Low (Read-only) */ + SPR603_TBU_R = 0x10d, /* R 603 Time Base High (Read-only) */ + SPR603_TBL_W = 0x11c, /* W 603 Time Base Low (Write-only) */ + SPR603_TBU_W = 0x11d, /* W 603 Time Base Hight (Write-only) */ + SPR603_DMISS = 0x3d0, /* R 603 Data TLB Miss Address Register */ + SPR603_DCMP = 0x3d1, /* R 603 Data TLB Compare Register */ + SPR603_HASH1 = 0x3d2, /* R 603 Primary Hash Address Register */ + SPR603_HASH2 = 0x3d3, /* R 603 Secondary Hash Address Register */ + SPR603_IMISS = 0x3d4, /* R 603 Instruction TLB Miss Address Register */ + SPR603_ICMP = 0x3d5, /* R 603 Instruction TLB Compare Register */ + SPR603_RPA = 0x3d6, /* R/W 603 Required Physical Address Register */ + SPR603_HID0 = 0x3f0, /* R/W 603 Hardware Implementation Register 0 */ + SPR603_HID1 = 0x3f1, /* R/W 603 Hardware Implementation Register 1 */ + SPR603_IABR = 0x3f2, /* R/W 603 Instruction Address Breakpoint Register */ + SPR603_HID2 = 0x3f3 /* R/W 603 */ +}; + + +/* PowerPC 4XX DCR register indexes */ +enum +{ + DCR4XX_EXISR = 0x040, /* external interrupt status */ + DCR4XX_EXIER = 0x042, /* external interrupt enable */ + DCR4XX_BR0 = 0x080, /* bank */ + DCR4XX_BR1 = 0x081, /* bank */ + DCR4XX_BR2 = 0x082, /* bank */ + DCR4XX_BR3 = 0x083, /* bank */ + DCR4XX_BR4 = 0x084, /* bank */ + DCR4XX_BR5 = 0x085, /* bank */ + DCR4XX_BR6 = 0x086, /* bank */ + DCR4XX_BR7 = 0x087, /* bank */ + DCR4XX_BEAR = 0x090, /* bus error address */ + DCR4XX_BESR = 0x091, /* bus error syndrome */ + DCR4XX_IOCR = 0x0a0, /* io configuration */ + DCR4XX_DMACR0 = 0x0c0, /* dma channel control */ + DCR4XX_DMACT0 = 0x0c1, /* dma destination address */ + DCR4XX_DMADA0 = 0x0c2, /* dma destination address */ + DCR4XX_DMASA0 = 0x0c3, /* dma source address */ + DCR4XX_DMACC0 = 0x0c4, /* dma chained count */ + DCR4XX_DMACR1 = 0x0c8, /* dma channel control */ + DCR4XX_DMACT1 = 0x0c9, /* dma destination address */ + DCR4XX_DMADA1 = 0x0ca, /* dma destination address */ + DCR4XX_DMASA1 = 0x0cb, /* dma source address */ + DCR4XX_DMACC1 = 0x0cc, /* dma chained count */ + DCR4XX_DMACR2 = 0x0d0, /* dma channel control */ + DCR4XX_DMACT2 = 0x0d1, /* dma destination address */ + DCR4XX_DMADA2 = 0x0d2, /* dma source address */ + DCR4XX_DMASA2 = 0x0d3, /* dma source address */ + DCR4XX_DMACC2 = 0x0d4, /* dma chained count */ + DCR4XX_DMACR3 = 0x0d8, /* dma channel control */ + DCR4XX_DMACT3 = 0x0d9, /* dma destination address */ + DCR4XX_DMADA3 = 0x0da, /* dma source address */ + DCR4XX_DMASA3 = 0x0db, /* dma source address */ + DCR4XX_DMACC3 = 0x0dc, /* dma chained count */ + DCR4XX_DMASR = 0x0e0 /* dma status */ +}; + + +/* PowerPC 4XX SPU register indexes */ +enum +{ + SPU4XX_LINE_STATUS = 0x00, + SPU4XX_HANDSHAKE_STATUS = 0x02, + SPU4XX_BAUD_DIVISOR_H = 0x04, + SPU4XX_BAUD_DIVISOR_L = 0x05, + SPU4XX_CONTROL = 0x06, + SPU4XX_RX_COMMAND = 0x07, + SPU4XX_TX_COMMAND = 0x08, + SPU4XX_BUFFER = 0x09 +}; + + +/* FPSCR register bits */ +#define FPSCR_FX 0x80000000 +#define FPSCR_FEX 0x40000000 +#define FPSCR_VX 0x20000000 +#define FPSCR_OX 0x10000000 +#define FPSCR_UX 0x08000000 +#define FPSCR_ZX 0x04000000 +#define FPSCR_XX 0x02000000 + + +/* XER register bits */ +#define XER_SO 0x80000000 +#define XER_OV 0x40000000 +#define XER_CA 0x20000000 + + +/* Machine State Register bits - common */ +#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ +#define MSR_EE 0x00008000 /* External Interrupt Enable */ +#define MSR_PR 0x00004000 /* Problem State */ +#define MSR_ME 0x00001000 /* Machine Check Enable */ +#define MSR_LE 0x00000001 /* Little Endian */ + +/* Machine State Register bits - OEA */ +#define MSROEA_POW 0x00040000 /* Power Management Enable */ +#define MSROEA_FP 0x00002000 /* Floating Point Available */ +#define MSROEA_FE0 0x00000800 /* FP Exception Mode 0 */ +#define MSROEA_SE 0x00000400 /* Single Step Trace Enable */ +#define MSROEA_BE 0x00000200 /* Branch Trace Enable */ +#define MSROEA_FE1 0x00000100 /* FP Exception Mode 1 */ +#define MSROEA_IP 0x00000040 /* Interrupt Prefix */ +#define MSROEA_IR 0x00000020 /* Instruction Relocate */ +#define MSROEA_DR 0x00000010 /* Data Relocate */ +#define MSROEA_RI 0x00000002 /* Recoverable Interrupt Enable */ + +/* Machine State Register bits - 4XX */ +#define MSR4XX_WE 0x00040000 /* Wait State Enable */ +#define MSR4XX_CE 0x00020000 /* Critical Interrupt Enable */ +#define MSR4XX_DE 0x00000200 /* Debug Exception Enable */ +#define MSR4XX_PE 0x00000008 /* Protection Enable (reserved for others) */ +#define MSR4XX_PX 0x00000004 /* Protection Exclusive Mode (reserved for others) */ + +/* Machine State Register bits - 602 */ +#define MSR602_AP 0x00800000 /* Access privilege state */ +#define MSR602_SA 0x00400000 /* Supervisor access mode */ + +/* Machine State Register bits - 603 */ +#define MSR603_TGPR 0x00020000 /* Temporary GPR Remapping */ + + +/* DSISR bits for DSI/alignment exceptions */ +#define DSISR_DIRECT 0x00000001 /* DSI: direct-store exception? */ +#define DSISR_NOT_FOUND 0x00000002 /* DSI: not found in HTEG or DBAT */ +#define DSISR_PROTECTED 0x00000010 /* DSI: exception due to protection */ +#define DSISR_CACHE_ERROR 0x00000020 /* DSI: operation on incorrect cache type */ +#define DSISR_STORE 0x00000040 /* DSI: store (1) or load (0) */ +#define DSISR_DABR 0x00000200 /* DSI: DABR match occurred */ +#define DSISR_NO_SEGMENT 0x00000400 /* DSI: no segment match found (64-bit only) */ +#define DSISR_INVALID_ECWX 0x00000800 /* DSI: ECIWX or ECOWX used with EAR[E] = 0 */ +#define DSISR_INSTRUCTION 0xfffff000 /* align: instruction decoding bits */ + + +/* PowerPC 4XX IRQ bits */ +#define PPC4XX_IRQ_BIT_CRITICAL (0x80000000 >> 0) +#define PPC4XX_IRQ_BIT_SPUR (0x80000000 >> 4) +#define PPC4XX_IRQ_BIT_SPUT (0x80000000 >> 5) +#define PPC4XX_IRQ_BIT_JTAGR (0x80000000 >> 6) +#define PPC4XX_IRQ_BIT_JTAGT (0x80000000 >> 7) +#define PPC4XX_IRQ_BIT_DMA0 (0x80000000 >> 8) +#define PPC4XX_IRQ_BIT_DMA1 (0x80000000 >> 9) +#define PPC4XX_IRQ_BIT_DMA2 (0x80000000 >> 10) +#define PPC4XX_IRQ_BIT_DMA3 (0x80000000 >> 11) +#define PPC4XX_IRQ_BIT_EXT0 (0x80000000 >> 27) +#define PPC4XX_IRQ_BIT_EXT1 (0x80000000 >> 28) +#define PPC4XX_IRQ_BIT_EXT2 (0x80000000 >> 29) +#define PPC4XX_IRQ_BIT_EXT3 (0x80000000 >> 30) +#define PPC4XX_IRQ_BIT_EXT4 (0x80000000 >> 31) + +#define PPC4XX_IRQ_BIT_EXT(n) (PPC4XX_IRQ_BIT_EXT0 >> (n)) +#define PPC4XX_IRQ_BIT_DMA(n) (PPC4XX_IRQ_BIT_DMA0 >> (n)) + + +/* PowerPC 4XX DMA control bits */ +#define PPC4XX_DMACR_CE 0x80000000 /* channel enable */ +#define PPC4XX_DMACR_CIE 0x40000000 /* channel interrupt enable */ +#define PPC4XX_DMACR_TD 0x20000000 /* transfer direction */ +#define PPC4XX_DMACR_PL 0x10000000 /* peripheral location */ +#define PPC4XX_DMACR_PW_MASK 0x0c000000 /* peripheral width */ +#define PPC4XX_DMACR_DAI 0x02000000 /* destination address increment */ +#define PPC4XX_DMACR_SAI 0x01000000 /* source address increment */ +#define PPC4XX_DMACR_CP 0x00800000 /* channel priority */ +#define PPC4XX_DMACR_TM_MASK 0x00600000 /* transfer mode */ +#define PPC4XX_DMACR_PSC_MASK 0x00180000 /* peripheral setup cycles */ +#define PPC4XX_DMACR_PWC_MASK 0x0007e000 /* peripheral wait cycles */ +#define PPC4XX_DMACR_PHC_MASK 0x00001c00 /* peripheral hold cycles */ +#define PPC4XX_DMACR_ETD 0x00000200 /* end-of-transfer pin direction */ +#define PPC4XX_DMACR_TCE 0x00000100 /* terminal count enable */ +#define PPC4XX_DMACR_CH 0x00000080 /* chaining enable */ +#define PPC4XX_DMACR_BME 0x00000040 /* burst mode enable */ +#define PPC4XX_DMACR_ECE 0x00000020 /* EOT chain mode enable */ +#define PPC4XX_DMACR_TCD 0x00000010 /* TC chain mode disable */ +#define PPC4XX_DMACR_PCE 0x00000008 + + +/* PowerPC 4XX Timer control register bits */ +#define PPC4XX_TCR_WP_MASK 0xc0000000 /* watchdog period */ +#define PPC4XX_TCR_WRC_MASK 0x30000000 /* watchdog reset control */ +#define PPC4XX_TCR_WIE 0x08000000 /* watchdog interrupt enable */ +#define PPC4XX_TCR_PIE 0x04000000 /* PIT interrupt enable */ +#define PPC4XX_TCR_FP_MASK 0x03000000 /* FIT period */ +#define PPC4XX_TCR_FIE 0x00800000 /* FIT interrupt enable */ +#define PPC4XX_TCR_ARE 0x00400000 /* auto reload enable */ + + +/* PowerPC 4XX Timer status register bits */ +#define PPC4XX_TSR_ENW 0x80000000 /* enable next watchdog */ +#define PPC4XX_TSR_WIS 0x40000000 /* watchdog interrupt status */ +#define PPC4XX_TSR_WRS_MASK 0x30000000 /* watchdog reset status */ +#define PPC4XX_TSR_PIS 0x08000000 /* PIT interrupt status */ +#define PPC4XX_TSR_FIS 0x04000000 /* FIT interrupt status */ + + +/* instruction decoding masks */ +#define M_LI 0x03fffffc +#define M_AA 0x00000002 +#define M_LK 0x00000001 +#define M_BO 0x03e00000 +#define M_BI 0x001f0000 +#define M_BD 0x0000fffc +#define M_RT 0x03e00000 +#define M_RD 0x03e00000 +#define M_RS 0x03e00000 +#define M_RA 0x001f0000 +#define M_RB 0x0000f800 +#define M_CRFD 0x03800000 +#define M_L 0x00200000 +#define M_TO 0x03e00000 +#define M_D 0x0000ffff +#define M_SIMM 0x0000ffff +#define M_UIMM 0x0000ffff +#define M_NB 0x0000f800 +#define M_SR 0x000f0000 +#define M_SH 0x0000f800 +#define M_CRFS 0x001c0000 +#define M_IMM 0x0000f000 +#define M_CRBD 0x03e00000 +#define M_RC 0x00000001 +#define M_CRBA 0x001f0000 +#define M_CRBB 0x0000f800 +#define M_SPR 0x001FF800 +#define M_TBR 0x001FF800 +#define M_CRM 0x000FF000 +#define M_DCR 0x001FF800 +#define M_FM 0x01FE0000 +#define M_OE 0x00000400 +#define M_REGC 0x000007c0 +#define M_MB 0x000007c0 +#define M_ME 0x0000003e +#define M_XO 0x000007fe + + + +/*************************************************************************** + HELPER MACROS +***************************************************************************/ + +/* + * Field Defining Macros + * + * These macros generate instruction words with their associated fields filled + * in with the passed value. + */ + +#define D_OP(op) ((op & 0x3f) << 26) +#define D_XO(xo) ((xo & 0x3ff) << 1) +#define D_RT(r) ((r & 0x1f) << (31 - 10)) +#define D_RA(r) ((r & 0x1f) << (31 - 15)) +#define D_UIMM(u) (u & 0xffff) + +/* + * Macros to Get Field Values + * + * These macros return the values of fields in an opcode. They all return + * unsigned values and do not perform any sign extensions. + */ + +#define G_RT(op) ((op & M_RT) >> (31 - 10)) +#define G_RD(op) ((op & M_RD) >> (31 - 10)) +#define G_RS(op) ((op & M_RS) >> (31 - 10)) +#define G_RA(op) ((op & M_RA) >> (31 - 15)) +#define G_RB(op) ((op & M_RB) >> (31 - 20)) +#define G_SIMM(op) (op & M_SIMM) +#define G_UIMM(op) (op & M_UIMM) +#define G_LI(op) ((op & M_LI) >> 2) +#define G_BO(op) ((op & M_BO) >> (31 - 10)) +#define G_BI(op) ((op & M_BI) >> (31 - 15)) +#define G_BD(op) ((op & M_BD) >> 2) +#define G_CRFD(op) ((op & M_CRFD) >> (31 - 8)) +#define G_L(op) ((op & M_L) >> (31 - 10)) +#define G_CRBD(op) ((op & M_CRBD) >> (31 - 10)) +#define G_CRBA(op) ((op & M_CRBA) >> (31 - 15)) +#define G_CRBB(op) ((op & M_CRBB) >> (31 - 20)) +#define G_REGC(op) ((op & M_REGC) >> (31 - 25)) +#define G_D(op) (op & M_D) +#define G_NB(op) ((op & M_NB) >> (31 - 20)) +#define G_CRFS(op) ((op & M_CRFS) >> (31 - 13)) +#define G_SPR(op) ((op & M_SPR) >> (31 - 20)) +#define G_TBR(op) ((op & M_TBR) >> (31 - 20)) +#define G_DCR(op) ((op & M_DCR) >> (31 - 20)) +#define G_SR(op) ((op & M_SR) >> (31 - 15)) +#define G_CRM(op) ((op & M_CRM) >> (31 - 19)) +#define G_FM(op) ((op & M_FM) >> (31 - 14)) +#define G_IMM(op) ((op & M_IMM) >> (31 - 19)) +#define G_SH(op) ((op & M_SH) >> (31 - 20)) +#define G_MB(op) ((op & M_MB) >> (31 - 25)) +#define G_ME(op) ((op & M_ME) >> 1) +#define G_TO(op) ((op & M_TO) >> (31 - 10)) +#define G_XO(op) ((op & M_XO) >> (31 - 30)) + + + +/*************************************************************************** + STRUCTURES & TYPEDEFS +***************************************************************************/ + +typedef int (*ppc4xx_spu_rx_handler)(UINT8 *data); +typedef void (*ppc4xx_spu_tx_handler)(UINT8 data); + + +/* PowerPC 4XX-specific serial port state */ +typedef struct _ppc4xx_spu_state ppc4xx_spu_state; +struct _ppc4xx_spu_state +{ + UINT8 regs[9]; + UINT8 txbuf; + UINT8 rxbuf; + emu_timer * timer; + ppc4xx_spu_rx_handler rx_handler; + ppc4xx_spu_tx_handler tx_handler; +}; + + +/* forward declaration of implementation-specific state */ +typedef struct _ppcimp_state ppcimp_state; + + +/* PowerPC state */ +typedef struct _powerpc_state powerpc_state; +struct _powerpc_state +{ + /* core registers */ + UINT32 pc; + int icount; + UINT32 r[32]; + double f[32]; + UINT32 cr; + UINT32 fpscr; + UINT32 msr; + UINT32 sr[16]; + UINT32 spr[1024]; + UINT32 dcr[256]; + + /* parameters for calls */ + UINT32 param0; + UINT32 param1; + + /* MMU */ + UINT32 * tlb_table; + UINT32 * tlb_entries; + UINT32 tlb_index; + + /* architectural distinctions */ + powerpc_flavor flavor; + UINT8 cap; + UINT8 cache_line_size; + UINT32 tb_divisor; + int (*spr_read)(powerpc_state *ppc); + int (*spr_write)(powerpc_state *ppc); + int (*tlb_fill)(powerpc_state *ppc); + + /* PowerPC 4xx-specific state */ + ppc4xx_spu_state spu; + emu_timer * fit_timer; + emu_timer * pit_timer; + emu_timer * wdog_timer; + UINT32 pit_reload; + UINT32 irqstate; + + /* PowerPC 603-specific state */ + UINT32 mmu603_cmp; + UINT32 mmu603_hash[2]; + UINT32 mmu603_r[4]; + + /* internal stuff */ + int cpunum; + int (*irq_callback)(int irqline); + UINT32 irq_pending; + UINT32 system_clock; + UINT32 cpu_clock; + UINT64 tb_zero_cycles; + UINT64 dec_zero_cycles; + emu_timer * decrementer_int_timer; + + /* for use by specific implementations */ + ppcimp_state * impstate; +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int), void *memory); +void ppccom_reset(powerpc_state *ppc); +#ifdef ENABLE_DEBUGGER +offs_t ppccom_dasm(powerpc_state *ppc, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram); +#endif +void ppccom_update_cycle_counting(powerpc_state *ppc); + +int ppccom_translate_address(powerpc_state *ppc, int space, int intention, offs_t *address); + +void ppccom_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info); +void ppccom_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info); + +void ppccom_tlb_fill(powerpc_state *ppc); +void ppccom_tlb_flush(powerpc_state *ppc); + +void ppccom_execute_tlbie(powerpc_state *ppc); +void ppccom_execute_tlbia(powerpc_state *ppc); +void ppccom_execute_tlbl(powerpc_state *ppc); +void ppccom_execute_mftb(powerpc_state *ppc); +void ppccom_execute_mfspr(powerpc_state *ppc); +void ppccom_execute_mtspr(powerpc_state *ppc); +void ppccom_execute_mfdcr(powerpc_state *ppc); +void ppccom_execute_mtdcr(powerpc_state *ppc); + +void ppc4xx_set_info(powerpc_state *ppc, UINT32 state, cpuinfo *info); +void ppc4xx_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info); + +#endif diff --git a/src/emu/cpu/powerpc/ppcdrc.c b/src/emu/cpu/powerpc/ppcdrc.c new file mode 100644 index 00000000000..45afbbd3e67 --- /dev/null +++ b/src/emu/cpu/powerpc/ppcdrc.c @@ -0,0 +1,4337 @@ +/*************************************************************************** + + ppcdrc.c + + Universal machine language-based PowerPC 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: + + * Timing for long instructions (stmw/lmw/mul/div/stswi) + + * Eliminate unnecessary flag calculations using information from the + frontend + +***************************************************************************/ + +#include <stddef.h> +#include "cpuintrf.h" +#include "debugger.h" +#include "ppccom.h" +#include "ppcfe.h" +#include "deprecat.h" +#include "cpu/drcfe.h" +#include "cpu/drcuml.h" +#include "cpu/drcumlsh.h" + +extern offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); + + + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define FORCE_C_BACKEND (0) +#define LOG_UML (0) +#define LOG_NATIVE (0) + +#define DISABLE_FAST_REGISTERS (0) +#define SINGLE_INSTRUCTION_MODE (0) + +#define PRINTF_EXCEPTIONS (0) +#define PRINTF_MMU (0) + +#define PROBE_ADDRESS ~0 + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* map variables */ +#define MAPVAR_PC MVAR(0) +#define MAPVAR_CYCLES MVAR(1) +#define MAPVAR_DSISR MVAR(2) + +/* mode bits */ +#define MODE_LITTLE_ENDIAN 0x01 +#define MODE_DATA_TRANSLATION 0x02 +#define MODE_USER 0x04 + +/* size of the execution code cache */ +#define CACHE_SIZE (32 * 1024 * 1024) + +/* compilation boundaries -- how far back/forward does the analysis extend? */ +#define COMPILE_BACKWARDS_BYTES 128 +#define COMPILE_FORWARDS_BYTES 512 +#define COMPILE_MAX_INSTRUCTIONS ((COMPILE_BACKWARDS_BYTES/4) + (COMPILE_FORWARDS_BYTES/4)) +#define COMPILE_MAX_SEQUENCE 64 + +/* exit codes */ +#define EXECUTE_OUT_OF_CYCLES 0 +#define EXECUTE_MISSING_CODE 1 +#define EXECUTE_UNMAPPED_CODE 2 +#define EXECUTE_RESET_CACHE 3 + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define R32(reg) ppc->impstate->regmap[reg].type, ppc->impstate->regmap[reg].value +#define R32Z(reg) (((reg) == 0) ? DRCUML_PTYPE_IMMEDIATE : ppc->impstate->regmap[reg].type), (((reg) == 0) ? 0 : ppc->impstate->regmap[reg].value) +#define F64(reg) ppc->impstate->fdregmap[reg].type, ppc->impstate->fdregmap[reg].value +#define CR32 MEM(&ppc->cr) +#define FPSCR32 MEM(&ppc->fpscr) +#define MSR32 MEM(&ppc->msr) +#define SR32(reg) MEM(&ppc->sr[reg]) +#define SPR32(reg) MEM(&ppc->spr[reg]) + +#define CRMASK(reg) (0xf0000000 >> ((reg) * 4)) + +#define FLAGS_RC(op) ((op & M_RC) ? (DRCUML_FLAG_S | DRCUML_FLAG_Z) : 0) +#define FLAGS_OE(op) ((op & M_OE) ? DRCUML_FLAG_V : 0) +#define FLAGS_RCOE(op) (FLAGS_RC(op) | FLAGS_OE(op)) +#define FLAGS_RCOECA(op) (FLAGS_RCOE(op) | DRCUML_FLAG_C) + +/* DSISR values for various addressing types */ +#define DSISR_IMM(op) ((0) | /* bits 15-16: cleared */ \ + ((((op) >> (31- 5)) & 0x01) << (31-17)) | /* bit 17: opcode bit 5 */ \ + ((((op) >> (31- 4)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 1-4 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + (0)) /* bits 27-31: undefined */ + +#define DSISR_IMMU(op) ((0) | /* bits 15-16: cleared */ \ + ((((op) >> (31- 5)) & 0x01) << (31-17)) | /* bit 17: opcode bit 5 */ \ + ((((op) >> (31- 4)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 1-4 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + ((((op) >> (31-15)) & 0x1f) << (31-31))) /* bits 27-31: opcode bits 11-15 */ + +#define DSISR_IDX(op) (((((op) >> (31-30)) & 0x03) << (31-16)) | /* bits 15-16: opcode bits 29-30 */ \ + ((((op) >> (31-25)) & 0x01) << (31-17)) | /* bit 17: opcode bit 25 */ \ + ((((op) >> (31-24)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 21-24 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + (0)) /* bits 27-31: undefined */ + +#define DSISR_IDXU(op) (((((op) >> (31-30)) & 0x03) << (31-16)) | /* bits 15-16: opcode bits 29-30 */ \ + ((((op) >> (31-25)) & 0x01) << (31-17)) | /* bit 17: opcode bit 25 */ \ + ((((op) >> (31-24)) & 0x0f) << (31-21)) | /* bits 18-21: opcode bits 21-24 */ \ + ((((op) >> (31-10)) & 0x1f) << (31-26)) | /* bits 22-26: opcode bits 6-10 */ \ + ((((op) >> (31-15)) & 0x1f) << (31-31))) /* bits 27-31: opcode bits 11-15 */ + + + +/*************************************************************************** + STRUCTURES & TYPEDEFS +***************************************************************************/ + +/* fast RAM info */ +typedef struct _fast_ram_info fast_ram_info; +struct _fast_ram_info +{ + 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 */ +}; + + +/* hotspot info */ +typedef struct _hotspot_info hotspot_info; +struct _hotspot_info +{ + offs_t pc; /* PC to consider */ + UINT32 opcode; /* required opcode at that PC */ + UINT32 cycles; /* number of cycles to eat when hit */ +}; + + +/* 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 */ +}; + + +/* PowerPC implementation state */ +struct _ppcimp_state +{ + /* core state */ + 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 */ + + /* parameters for subroutines */ + UINT64 numcycles; /* return value from gettotalcycles */ + UINT32 mode; /* current global mode */ + UINT32 arg0; /* print_debug argument 1 */ + UINT32 arg1; /* print_debug argument 2 */ + UINT32 updateaddr; /* update address storage */ + UINT32 swcount; /* counter for sw instructions */ + UINT32 swreg; /* reg index for sw instructions */ + UINT32 tempaddr; /* temporary address storage */ + UINT64 tempdata; /* temporary data storage */ + double fp0; /* floating point 0 */ + + /* tables */ + UINT8 fpmode[4]; /* FPU mode table */ + UINT32 sz_cr_table[32]; /* SZ CR table */ + UINT32 cmp_cr_table[32]; /* CMP CR table */ + UINT32 cmpl_cr_table[32]; /* CMPL CR table */ + UINT32 fcmp_cr_table[32]; /* FCMP CR table */ + + /* internal stuff */ + UINT8 cache_dirty; /* true if we need to flush the cache */ + + /* register mappings */ + drcuml_parameter regmap[32]; /* parameter to register mappings for all 32 integer registers */ + drcuml_parameter fsregmap[32]; /* parameter to register mappings for all 32 floating point registers */ + drcuml_parameter fdregmap[32]; /* parameter to register mappings for all 32 floating point registers */ + + /* 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 handler */ + drcuml_codehandle * swap_tgpr; /* swap TGPR handler */ + drcuml_codehandle * read8[4]; /* read byte */ + drcuml_codehandle * write8[4]; /* write byte */ + drcuml_codehandle * read16[4]; /* read half */ + drcuml_codehandle * read16mask[4]; /* read half */ + drcuml_codehandle * write16[4]; /* write half */ + drcuml_codehandle * write16mask[4]; /* write half */ + drcuml_codehandle * read32[4]; /* read word */ + drcuml_codehandle * read32align[4]; /* read word aligned */ + drcuml_codehandle * read32mask[4]; /* read word */ + drcuml_codehandle * write32[4]; /* write word */ + drcuml_codehandle * write32align[4]; /* write word aligned */ + drcuml_codehandle * write32mask[4]; /* write word */ + drcuml_codehandle * read64[4]; /* read double */ + drcuml_codehandle * read64mask[4]; /* read double */ + drcuml_codehandle * write64[4]; /* write double */ + drcuml_codehandle * write64mask[4]; /* write double */ + drcuml_codehandle * exception[EXCEPTION_COUNT]; /* array of exception handlers */ + drcuml_codehandle * exception_norecover[EXCEPTION_COUNT]; /* array of exception handlers */ + + /* fast RAM */ + UINT32 fastram_select; + fast_ram_info fastram[PPC_MAX_FASTRAM]; + + /* hotspots */ + UINT32 hotspot_select; + hotspot_info hotspot[PPC_MAX_HOTSPOTS]; +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void code_flush_cache(drcuml_state *drcuml); +static void code_compile_block(drcuml_state *drcuml, UINT8 mode, offs_t pc); + +static void cfunc_printf_exception(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_tlb_mismatch(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 mode, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr, drcuml_codehandle *masked); +static void static_generate_swap_tgpr(drcuml_state *drcuml); + +static void generate_update_mode(drcuml_block *block); +static void generate_update_cycles(drcuml_block *block, compiler_state *compiler, drcuml_ptype ptype, UINT64 pvalue, 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 int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); +static int generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); +static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); +static int generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc); +static int generate_instruction_3f(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); + + + +/*************************************************************************** + PRIVATE GLOBAL VARIABLES +***************************************************************************/ + +static powerpc_state *ppc; + + +/* 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 SZ */ +static const UINT32 sz_cr_table_source[32] = +{ + /* ..... */ 0x40000000, + /* ....C */ 0x42000000, + /* ...V. */ 0x4c000000, + /* ...VC */ 0x4e000000, + /* ..Z.. */ 0x20000000, + /* ..Z.C */ 0x22000000, + /* ..ZV. */ 0x2c000000, + /* ..ZVC */ 0x2e000000, + /* .S... */ 0x80000000, + /* .S..C */ 0x82000000, + /* .S.V. */ 0x8c000000, + /* .S.VC */ 0x8e000000, + /* .SZ.. */ 0x20000000, + /* .SZ.C */ 0x22000000, + /* .SZV. */ 0x2c000000, + /* .SZVC */ 0x2e000000, + /* U.... */ 0x40000000, + /* U...C */ 0x42000000, + /* U..V. */ 0x4c000000, + /* U..VC */ 0x4e000000, + /* U.Z.. */ 0x20000000, + /* U.Z.C */ 0x22000000, + /* U.ZV. */ 0x2c000000, + /* U.ZVC */ 0x2e000000, + /* US... */ 0x80000000, + /* US..C */ 0x82000000, + /* US.V. */ 0x8c000000, + /* US.VC */ 0x8e000000, + /* USZ.. */ 0x20000000, + /* USZ.C */ 0x22000000, + /* USZV. */ 0x2c000000, + /* USZVC */ 0x2e000000 +}; + +/* flag lookup table for CMP */ +static const UINT32 cmp_cr_table_source[32] = +{ + /* ..... */ 0x44444444, + /* ....C */ 0x44444444, + /* ...V. */ 0x88888888, + /* ...VC */ 0x88888888, + /* ..Z.. */ 0x22222222, + /* ..Z.C */ 0x22222222, + /* ..ZV. */ 0x22222222, + /* ..ZVC */ 0x22222222, + /* .S... */ 0x88888888, + /* .S..C */ 0x88888888, + /* .S.V. */ 0x44444444, + /* .S.VC */ 0x44444444, + /* .SZ.. */ 0x22222222, + /* .SZ.C */ 0x22222222, + /* .SZV. */ 0x22222222, + /* .SZVC */ 0x22222222, + /* U.... */ 0x44444444, + /* U...C */ 0x44444444, + /* U..V. */ 0x88888888, + /* U..VC */ 0x88888888, + /* U.Z.. */ 0x22222222, + /* U.Z.C */ 0x22222222, + /* U.ZV. */ 0x22222222, + /* U.ZVC */ 0x22222222, + /* US... */ 0x88888888, + /* US..C */ 0x88888888, + /* US.V. */ 0x44444444, + /* US.VC */ 0x44444444, + /* USZ.. */ 0x22222222, + /* USZ.C */ 0x22222222, + /* USZV. */ 0x22222222, + /* USZVC */ 0x22222222 +}; + +/* flag lookup table for CMPL */ +static const UINT32 cmpl_cr_table_source[32] = +{ + /* ..... */ 0x44444444, + /* ....C */ 0x88888888, + /* ...V. */ 0x44444444, + /* ...VC */ 0x88888888, + /* ..Z.. */ 0x22222222, + /* ..Z.C */ 0x22222222, + /* ..ZV. */ 0x22222222, + /* ..ZVC */ 0x22222222, + /* .S... */ 0x44444444, + /* .S..C */ 0x88888888, + /* .S.V. */ 0x44444444, + /* .S.VC */ 0x88888888, + /* .SZ.. */ 0x22222222, + /* .SZ.C */ 0x22222222, + /* .SZV. */ 0x22222222, + /* .SZVC */ 0x22222222, + /* U.... */ 0x44444444, + /* U...C */ 0x88888888, + /* U..V. */ 0x44444444, + /* U..VC */ 0x88888888, + /* U.Z.. */ 0x22222222, + /* U.Z.C */ 0x22222222, + /* U.ZV. */ 0x22222222, + /* U.ZVC */ 0x22222222, + /* US... */ 0x44444444, + /* US..C */ 0x88888888, + /* US.V. */ 0x44444444, + /* US.VC */ 0x88888888, + /* USZ.. */ 0x22222222, + /* USZ.C */ 0x22222222, + /* USZV. */ 0x22222222, + /* USZVC */ 0x22222222 +}; + +/* flag lookup table for FCMP */ +static const UINT32 fcmp_cr_table_source[32] = +{ + /* ..... */ 0x44444444, + /* ....C */ 0x88888888, + /* ...V. */ 0x44444444, + /* ...VC */ 0x88888888, + /* ..Z.. */ 0x22222222, + /* ..Z.C */ 0xaaaaaaaa, + /* ..ZV. */ 0x22222222, + /* ..ZVC */ 0xaaaaaaaa, + /* .S... */ 0x44444444, + /* .S..C */ 0x88888888, + /* .S.V. */ 0x44444444, + /* .S.VC */ 0x88888888, + /* .SZ.. */ 0x22222222, + /* .SZ.C */ 0xaaaaaaaa, + /* .SZV. */ 0x22222222, + /* .SZVC */ 0xaaaaaaaa, + /* U.... */ 0x55555555, + /* U...C */ 0x99999999, + /* U..V. */ 0x55555555, + /* U..VC */ 0x99999999, + /* U.Z.. */ 0x33333333, + /* U.Z.C */ 0xbbbbbbbb, + /* U.ZV. */ 0x33333333, + /* U.ZVC */ 0xbbbbbbbb, + /* US... */ 0x55555555, + /* US..C */ 0x99999999, + /* US.V. */ 0x55555555, + /* US.VC */ 0x99999999, + /* USZ.. */ 0x33333333, + /* USZ.C */ 0xbbbbbbbb, + /* USZV. */ 0x33333333, + /* USZVC */ 0xbbbbbbbb +}; + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + 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); +} + + +/*------------------------------------------------- + load_fast_iregs - load any fast integer + registers +-------------------------------------------------*/ + +INLINE void load_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(ppc->impstate->regmap); regnum++) + if (ppc->impstate->regmap[regnum].type == DRCUML_PTYPE_INT_REGISTER) + UML_MOV(block, IREG(ppc->impstate->regmap[regnum].value - DRCUML_REG_I0), MEM(&ppc->r[regnum])); +} + + +/*------------------------------------------------- + save_fast_iregs - save any fast integer + registers +-------------------------------------------------*/ + +INLINE void save_fast_iregs(drcuml_block *block) +{ + int regnum; + + for (regnum = 0; regnum < ARRAY_LENGTH(ppc->impstate->regmap); regnum++) + if (ppc->impstate->regmap[regnum].type == DRCUML_PTYPE_INT_REGISTER) + UML_MOV(block, MEM(&ppc->r[regnum]), IREG(ppc->impstate->regmap[regnum].value - DRCUML_REG_I0)); +} + + +/*------------------------------------------------- + compute_rlw_mask - compute the 32-bit mask + for an rlw* instruction +-------------------------------------------------*/ + +INLINE UINT32 compute_rlw_mask(UINT8 mb, UINT8 me) +{ + if (mb <= me) + return (0xffffffff >> mb) & (0xffffffff << (31 - me)); + else + return (0xffffffff >> mb) | (0xffffffff << (31 - me)); +} + + +/*------------------------------------------------- + compute_crf_mask - compute the 32-bit mask + for a mtcrf/mfcrf instruction +-------------------------------------------------*/ + +INLINE UINT32 compute_crf_mask(UINT8 crm) +{ + UINT32 mask = 0; + if (crm & 0x80) mask |= 0xf0000000; + if (crm & 0x40) mask |= 0x0f000000; + if (crm & 0x20) mask |= 0x00f00000; + if (crm & 0x10) mask |= 0x000f0000; + if (crm & 0x08) mask |= 0x0000f000; + if (crm & 0x04) mask |= 0x00000f00; + if (crm & 0x02) mask |= 0x000000f0; + if (crm & 0x01) mask |= 0x0000000f; + return mask; +} + + +/*------------------------------------------------- + compute_spr - compute the SPR index from the + SPR field of an opcode +-------------------------------------------------*/ + +INLINE UINT32 compute_spr(UINT32 spr) +{ + return ((spr >> 5) | (spr << 5)) & 0x3ff; +} + + + +/*************************************************************************** + CORE CALLBACKS +***************************************************************************/ + +/*------------------------------------------------- + ppcdrc_init - initialize the processor +-------------------------------------------------*/ + +static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int)) +{ + drcfe_config feconfig = + { + COMPILE_BACKWARDS_BYTES, /* code window start offset = startpc - window_start */ + COMPILE_FORWARDS_BYTES, /* code window end offset = startpc + window_end */ + COMPILE_MAX_SEQUENCE, /* maximum instructions to include in a sequence */ + ppcfe_describe /* callback to describe a single instruction */ + }; + drcbe_info beinfo; + UINT32 flags = 0; + size_t extrasize; + drccache *cache; + void *extramem; + int regnum; + + /* determine how much memory beyond the core size we need */ + extrasize = ppccom_init(NULL, flavor, cap, tb_divisor, clock, config, irqcallback, NULL); + + /* allocate enough space for the cache and the core */ + cache = drccache_alloc(CACHE_SIZE + sizeof(*ppc) + extrasize); + if (cache == NULL) + fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*ppc) + extrasize)); + + /* allocate the core from the near cache, and the extra memory from the full cache */ + ppc = drccache_memory_alloc_near(cache, sizeof(*ppc)); + memset(ppc, 0, sizeof(*ppc)); + extramem = drccache_memory_alloc(cache, extrasize); + memset(extramem, 0, extrasize); + + /* initialize the core */ + ppccom_init(ppc, flavor, cap, tb_divisor, clock, config, irqcallback, extramem); + + /* allocate the implementation-specific state from the full cache */ + ppc->impstate = drccache_memory_alloc_near(cache, sizeof(*ppc->impstate)); + memset(ppc->impstate, 0, sizeof(*ppc->impstate)); + ppc->impstate->cache = cache; + + /* 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; + ppc->impstate->drcuml = drcuml_alloc(cache, flags, 8, 32, 2); + if (ppc->impstate->drcuml == NULL) + fatalerror("Error initializing the UML"); + + /* initialize the front-end helper */ + if (SINGLE_INSTRUCTION_MODE) + feconfig.max_sequence = 1; + ppc->impstate->drcfe = drcfe_init(&feconfig, ppc); + + /* initialize the implementation state tables */ + memcpy(ppc->impstate->fpmode, fpmode_source, sizeof(fpmode_source)); + memcpy(ppc->impstate->sz_cr_table, sz_cr_table_source, sizeof(sz_cr_table_source)); + memcpy(ppc->impstate->cmp_cr_table, cmp_cr_table_source, sizeof(cmp_cr_table_source)); + memcpy(ppc->impstate->cmpl_cr_table, cmpl_cr_table_source, sizeof(cmpl_cr_table_source)); + memcpy(ppc->impstate->fcmp_cr_table, fcmp_cr_table_source, sizeof(fcmp_cr_table_source)); + + /* compute the register parameters */ + for (regnum = 0; regnum < 32; regnum++) + { + ppc->impstate->regmap[regnum].type = DRCUML_PTYPE_MEMORY; + ppc->impstate->regmap[regnum].value = (FPTR)&ppc->r[regnum]; + ppc->impstate->fsregmap[regnum].type = DRCUML_PTYPE_MEMORY; + ppc->impstate->fsregmap[regnum].value = (FPTR)((UINT32 *)&ppc->f[regnum] + BYTE_XOR_LE(0)); + ppc->impstate->fdregmap[regnum].type = DRCUML_PTYPE_MEMORY; + ppc->impstate->fdregmap[regnum].value = (FPTR)&ppc->f[regnum]; + } + + /* if we have registers to spare, assign r0, r1, r2 to leftovers */ + if (!DISABLE_FAST_REGISTERS) + { + drcuml_get_backend_info(ppc->impstate->drcuml, &beinfo); + if (beinfo.direct_iregs > 5) + { + ppc->impstate->regmap[0].type = DRCUML_PTYPE_INT_REGISTER; + ppc->impstate->regmap[0].value = DRCUML_REG_I5; + } + if (beinfo.direct_iregs > 6) + { + ppc->impstate->regmap[1].type = DRCUML_PTYPE_INT_REGISTER; + ppc->impstate->regmap[1].value = DRCUML_REG_I6; + } + if (beinfo.direct_iregs > 7) + { + ppc->impstate->regmap[2].type = DRCUML_PTYPE_INT_REGISTER; + ppc->impstate->regmap[2].value = DRCUML_REG_I7; + } + } + + /* mark the cache dirty so it is updated on next execute */ + ppc->impstate->cache_dirty = TRUE; +} + + +/*------------------------------------------------- + ppcdrc_reset - reset the processor +-------------------------------------------------*/ + +static void ppcdrc_reset(void) +{ + /* reset the common code and mark the cache dirty */ + ppccom_reset(ppc); + ppc->impstate->mode = 0; + ppc->impstate->cache_dirty = TRUE; +} + + +/*------------------------------------------------- + ppcdrc_execute - execute the CPU for the + specified number of cycles +-------------------------------------------------*/ + +static int ppcdrc_execute(int cycles) +{ + drcuml_state *drcuml = ppc->impstate->drcuml; + int execute_result; + + /* reset the cache if dirty */ + if (ppc->impstate->cache_dirty) + code_flush_cache(drcuml); + ppc->impstate->cache_dirty = FALSE; + + /* execute */ + ppc->icount = cycles; + do + { + /* run as much as we can */ + execute_result = drcuml_execute(drcuml, ppc->impstate->entry); + + /* if we need to recompile, do it */ + if (execute_result == EXECUTE_MISSING_CODE) + code_compile_block(drcuml, ppc->impstate->mode, ppc->pc); + else if (execute_result == EXECUTE_UNMAPPED_CODE) + fatalerror("Attempted to execute unmapped code at PC=%08X\n", ppc->pc); + else if (execute_result == EXECUTE_RESET_CACHE) + code_flush_cache(drcuml); + + } while (execute_result != EXECUTE_OUT_OF_CYCLES); + + /* return the number of cycles executed */ + return cycles - ppc->icount; +} + + +/*------------------------------------------------- + ppcdrc_exit - cleanup from execution +-------------------------------------------------*/ + +static void ppcdrc_exit(void) +{ + /* clean up the DRC */ + drcfe_exit(ppc->impstate->drcfe); + drcuml_free(ppc->impstate->drcuml); + drccache_free(ppc->impstate->cache); +} + + +/*------------------------------------------------- + ppcdrc_get_context - return a copy of the + current context +-------------------------------------------------*/ + +static void ppcdrc_get_context(void *dst) +{ + if (dst != NULL) + *(powerpc_state **)dst = ppc; +} + + +/*------------------------------------------------- + ppcdrc_set_context - copy the current context + into the global state +-------------------------------------------------*/ + +static void ppcdrc_set_context(void *src) +{ + if (src != NULL) + ppc = *(powerpc_state **)src; +} + + +/*------------------------------------------------- + ppcdrc_translate - perform virtual-to-physical + address translation +-------------------------------------------------*/ + +static int ppcdrc_translate(int space, int intention, offs_t *address) +{ + return ppccom_translate_address(ppc, space, intention, address); +} + + +/*------------------------------------------------- + ppcdrc_dasm - disassemble an instruction +-------------------------------------------------*/ + +#ifdef ENABLE_DEBUGGER +static offs_t ppcdrc_dasm(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram) +{ + return ppccom_dasm(ppc, buffer, pc, oprom, opram); +} +#endif /* ENABLE_DEBUGGER */ + + +/*------------------------------------------------- + ppcdrc_set_info - set information about a given + CPU instance +-------------------------------------------------*/ + +static void ppcdrc_set_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are set as 64-bit signed integers --- */ + case CPUINFO_INT_PPC_DRC_OPTIONS: ppc->impstate->drcoptions = info->i; break; + + case CPUINFO_INT_PPC_FASTRAM_SELECT: if (info->i >= 0 && info->i < PPC_MAX_FASTRAM) ppc->impstate->fastram_select = info->i; ppc->impstate->cache_dirty = TRUE; break; + case CPUINFO_INT_PPC_FASTRAM_START: ppc->impstate->fastram[ppc->impstate->fastram_select].start = info->i; ppc->impstate->cache_dirty = TRUE; break; + case CPUINFO_INT_PPC_FASTRAM_END: ppc->impstate->fastram[ppc->impstate->fastram_select].end = info->i; ppc->impstate->cache_dirty = TRUE; break; + case CPUINFO_INT_PPC_FASTRAM_READONLY: ppc->impstate->fastram[ppc->impstate->fastram_select].readonly = info->i; ppc->impstate->cache_dirty = TRUE; break; + + case CPUINFO_INT_PPC_HOTSPOT_SELECT: if (info->i >= 0 && info->i < PPC_MAX_HOTSPOTS) ppc->impstate->hotspot_select = info->i; ppc->impstate->cache_dirty = TRUE; break; + case CPUINFO_INT_PPC_HOTSPOT_PC: ppc->impstate->hotspot[ppc->impstate->hotspot_select].pc = info->i; ppc->impstate->cache_dirty = TRUE; break; + case CPUINFO_INT_PPC_HOTSPOT_OPCODE: ppc->impstate->hotspot[ppc->impstate->hotspot_select].opcode = info->i; ppc->impstate->cache_dirty = TRUE; break; + case CPUINFO_INT_PPC_HOTSPOT_CYCLES: ppc->impstate->hotspot[ppc->impstate->hotspot_select].cycles = info->i; ppc->impstate->cache_dirty = TRUE; break; + + /* --- the following bits of info are set as pointers to data or functions --- */ + case CPUINFO_PTR_PPC_FASTRAM_BASE: ppc->impstate->fastram[ppc->impstate->fastram_select].base = info->p; break; + + /* --- everything else is handled generically --- */ + default: ppccom_set_info(ppc, state, info); break; + } +} + + +/*------------------------------------------------- + ppcdrc_get_info - return information about a given + CPU instance +-------------------------------------------------*/ + +static void ppcdrc_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break; + case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_SET_INFO: info->setinfo = ppcdrc_set_info; break; + case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppcdrc_get_context; break; + case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppcdrc_set_context; break; + case CPUINFO_PTR_INIT: /* provided per-CPU */ break; + case CPUINFO_PTR_RESET: info->reset = ppcdrc_reset; break; + case CPUINFO_PTR_EXIT: info->exit = ppcdrc_exit; break; + case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc_execute; break; +#ifdef ENABLE_DEBUGGER + case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppcdrc_dasm; break; +#endif /* ENABLE_DEBUGGER */ + case CPUINFO_PTR_TRANSLATE: info->translate = ppcdrc_translate; break; + case CPUINFO_PTR_CONTEXT: info->p = ppc; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; + + /* --- everything else is handled generically --- */ + default: ppccom_get_info(ppc, state, info); break; + } +} + + + +/*************************************************************************** + CACHE MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + code_flush_cache - flush the cache and + regenerate static code +-------------------------------------------------*/ + +static void code_flush_cache(drcuml_state *drcuml) +{ + int mode; + + /* 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); + static_generate_tlb_mismatch(drcuml); + if (ppc->cap & PPCCAP_603_MMU) + static_generate_swap_tgpr(drcuml); + + /* append exception handlers for various types */ + static_generate_exception(drcuml, EXCEPTION_RESET, TRUE, "exception_reset"); + static_generate_exception(drcuml, EXCEPTION_MACHCHECK, TRUE, "exception_machine_check"); + static_generate_exception(drcuml, EXCEPTION_DSI, TRUE, "exception_dsi"); + static_generate_exception(drcuml, EXCEPTION_ISI, TRUE, "exception_isi"); + static_generate_exception(drcuml, EXCEPTION_EI, TRUE, "exception_ei"); + static_generate_exception(drcuml, EXCEPTION_EI, FALSE, "exception_ei_norecover"); + static_generate_exception(drcuml, EXCEPTION_ALIGN, TRUE, "exception_align"); + static_generate_exception(drcuml, EXCEPTION_PROGRAM, TRUE, "exception_program"); + static_generate_exception(drcuml, EXCEPTION_NOFPU, TRUE, "exception_fpu_unavailable"); + static_generate_exception(drcuml, EXCEPTION_DECREMENT, TRUE, "exception_decrementer"); + static_generate_exception(drcuml, EXCEPTION_SYSCALL, TRUE, "exception_syscall"); + static_generate_exception(drcuml, EXCEPTION_TRACE, TRUE, "exception_trace"); + static_generate_exception(drcuml, EXCEPTION_FPASSIST, TRUE, "exception_floating_point_assist"); + if (ppc->cap & PPCCAP_603_MMU) + { + static_generate_exception(drcuml, EXCEPTION_ITLBMISS, TRUE, "exception_itlb_miss"); + static_generate_exception(drcuml, EXCEPTION_DTLBMISSL, TRUE, "exception_dtlb_miss_load"); + static_generate_exception(drcuml, EXCEPTION_DTLBMISSS, TRUE, "exception_dtlb_miss_store"); + } + + /* add subroutines for memory accesses */ + for (mode = 0; mode < 4; mode++) + { + static_generate_memory_accessor(drcuml, mode, 1, FALSE, FALSE, "read8", &ppc->impstate->read8[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 1, TRUE, FALSE, "write8", &ppc->impstate->write8[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 2, FALSE, TRUE, "read16mask", &ppc->impstate->read16mask[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 2, FALSE, FALSE, "read16", &ppc->impstate->read16[mode], ppc->impstate->read16mask[mode]); + static_generate_memory_accessor(drcuml, mode, 2, TRUE, TRUE, "write16mask", &ppc->impstate->write16mask[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 2, TRUE, FALSE, "write16", &ppc->impstate->write16[mode], ppc->impstate->write16mask[mode]); + static_generate_memory_accessor(drcuml, mode, 4, FALSE, TRUE, "read32mask", &ppc->impstate->read32mask[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 4, FALSE, FALSE, "read32align", &ppc->impstate->read32align[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 4, FALSE, FALSE, "read32", &ppc->impstate->read32[mode], ppc->impstate->read32mask[mode]); + static_generate_memory_accessor(drcuml, mode, 4, TRUE, TRUE, "write32mask", &ppc->impstate->write32mask[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 4, TRUE, FALSE, "write32align",&ppc->impstate->write32align[mode],NULL); + static_generate_memory_accessor(drcuml, mode, 4, TRUE, FALSE, "write32", &ppc->impstate->write32[mode], ppc->impstate->write32mask[mode]); + static_generate_memory_accessor(drcuml, mode, 8, FALSE, TRUE, "read64mask", &ppc->impstate->read64mask[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 8, FALSE, FALSE, "read64", &ppc->impstate->read64[mode], ppc->impstate->read64mask[mode]); + static_generate_memory_accessor(drcuml, mode, 8, TRUE, TRUE, "write64mask", &ppc->impstate->write64mask[mode], NULL); + static_generate_memory_accessor(drcuml, mode, 8, TRUE, FALSE, "write64", &ppc->impstate->write64[mode], ppc->impstate->write64mask[mode]); + } +} + + +/*------------------------------------------------- + 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(ppc->impstate->drcfe, pc); + if (LOG_UML || LOG_NATIVE) + 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) + { + 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(ppc->impstate->mode), IMM(seqhead->pc), ppc->impstate->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); // <checksum> + + /* 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); // <instruction> + + /* 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, IMM(nextpc), 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(&ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode + else if (seqlast->next == NULL || seqlast->next->pc != nextpc) + UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(nextpc), ppc->impstate->nocode);// hashjmp <mode>,nextpc,nocode + } + + /* 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: type=%2d EPC=%08X MSR=%08X\n", ppc->param0, ppc->spr[SPROEA_SRR0], ppc->spr[SPROEA_SRR1]); + cfunc_printf_probe((void *)(FPTR)ppc->spr[SPROEA_SRR0]); +} + + +/*------------------------------------------------- + cfunc_printf_debug - generic printf for + debugging +-------------------------------------------------*/ + +static void cfunc_printf_debug(void *param) +{ + const char *format = param; + printf(format, ppc->impstate->arg0, ppc->impstate->arg1); +} + + +/*------------------------------------------------- + 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\n", pc); + printf(" r0=%08X r1=%08X r2=%08X r3=%08X\n", + ppc->r[0], ppc->r[1], ppc->r[2], ppc->r[3]); + printf(" r4=%08X r5=%08X r6=%08X r7=%08X\n", + ppc->r[4], ppc->r[5], ppc->r[6], ppc->r[7]); + printf(" r8=%08X r9=%08X r10=%08X r11=%08X\n", + ppc->r[8], ppc->r[9], ppc->r[10], ppc->r[11]); + printf("r12=%08X r13=%08X r14=%08X r15=%08X\n", + ppc->r[12], ppc->r[13], ppc->r[14], ppc->r[15]); + printf("r16=%08X r17=%08X r18=%08X r19=%08X\n", + ppc->r[16], ppc->r[17], ppc->r[18], ppc->r[19]); + printf("r20=%08X r21=%08X r22=%08X r23=%08X\n", + ppc->r[20], ppc->r[21], ppc->r[22], ppc->r[23]); + printf("r24=%08X r25=%08X r26=%08X r27=%08X\n", + ppc->r[24], ppc->r[25], ppc->r[26], ppc->r[27]); + printf("r28=%08X r29=%08X r30=%08X r31=%08X\n", + ppc->r[28], ppc->r[29], ppc->r[30], ppc->r[31]); +} + + +/*------------------------------------------------- + cfunc_unimplemented - handler for + unimplemented opcdes +-------------------------------------------------*/ + +static void cfunc_unimplemented(void *param) +{ + UINT32 opcode = (FPTR)param; + fatalerror("PC=%08X: Unimplemented op %08X", ppc->pc, opcode); +} + + + +/*************************************************************************** + 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, &ppc->impstate->nocode, "nocode"); + alloc_handle(drcuml, &ppc->impstate->exception_norecover[EXCEPTION_EI], "exception_ei_norecover"); + + alloc_handle(drcuml, &ppc->impstate->entry, "entry"); + UML_HANDLE(block, ppc->impstate->entry); // handle entry + + /* reset the FPU mode */ + UML_AND(block, IREG(0), FPSCR32, IMM(3)); // and i0,fpscr,3 + UML_LOAD(block, IREG(0), &ppc->impstate->fpmode[0], IREG(0), BYTE); // load i0,fpmode,i0,byte + UML_SETFMOD(block, IREG(0)); // setfmod i0 + + /* load fast integer registers */ + load_fast_iregs(block); // <load fastregs> + + /* check for interrupts */ + UML_TEST(block, MEM(&ppc->irq_pending), IMM(~0)); // test [irq_pending],0 + UML_JMPc(block, IF_Z, skip); // jmp skip,Z + UML_TEST(block, MSR32, IMM(MSR_EE)); // test msr,MSR_EE + UML_JMPc(block, IF_Z, skip); // jmp skip,Z + UML_MOV(block, IREG(0), MEM(&ppc->pc)); // mov i0,pc + UML_MOV(block, IREG(1), IMM(0)); // mov i1,0 + UML_CALLH(block, ppc->impstate->exception_norecover[EXCEPTION_EI]); // callh exception_norecover + UML_LABEL(block, skip); // skip: + + /* generate a hash jump via the current mode and PC */ + UML_HASHJMP(block, MEM(&ppc->impstate->mode), MEM(&ppc->pc), ppc->impstate->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, &ppc->impstate->nocode, "nocode"); + UML_HANDLE(block, ppc->impstate->nocode); // handle nocode + UML_GETEXP(block, IREG(0)); // getexp i0 + UML_MOV(block, MEM(&ppc->pc), IREG(0)); // mov [pc],i0 + save_fast_iregs(block); // <save fastregs> + 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, &ppc->impstate->out_of_cycles, "out_of_cycles"); + UML_HANDLE(block, ppc->impstate->out_of_cycles); // handle out_of_cycles + UML_GETEXP(block, IREG(0)); // getexp i0 + UML_MOV(block, MEM(&ppc->pc), IREG(0)); // mov <pc>,i0 + save_fast_iregs(block); // <save fastregs> + UML_EXIT(block, IMM(EXECUTE_OUT_OF_CYCLES)); // exit EXECUTE_OUT_OF_CYCLES + + drcuml_block_end(block); +} + + +/*------------------------------------------------- + static_generate_tlb_mismatch - generate a + TLB mismatch handler +-------------------------------------------------*/ + +static void static_generate_tlb_mismatch(drcuml_state *drcuml) +{ + drcuml_block *block; + jmp_buf errorbuf; + int isi, label = 1; + + /* if we get an error back, we're screwed */ + if (setjmp(errorbuf) != 0) + fatalerror("Unrecoverable error in static_generate_tlb_mismatch"); + + /* forward references */ + alloc_handle(drcuml, &ppc->impstate->exception[EXCEPTION_ISI], "exception_isi"); + if (ppc->cap & PPCCAP_603_MMU) + alloc_handle(drcuml, &ppc->impstate->exception[EXCEPTION_ITLBMISS], "exception_itlb_miss"); + + /* begin generating */ + block = drcuml_block_begin(drcuml, 20, &errorbuf); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &ppc->impstate->tlb_mismatch, "tlb_mismatch"); + UML_HANDLE(block, ppc->impstate->tlb_mismatch); // handle tlb_mismatch + UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC + UML_MOV(block, MEM(&ppc->param0), IREG(0)); // mov [param0],i0 + UML_MOV(block, MEM(&ppc->param1), IMM(TRANSLATE_FETCH)); // mov [param1],TRANSLATE_FETCH + UML_CALLC(block, ppccom_tlb_fill, ppc); // callc tlbfill,ppc + UML_CMP(block, MEM(&ppc->param0), IMM(1)); // cmp [param0],1 + UML_JMPc(block, IF_A, isi = label++); // jmp isi,A + save_fast_iregs(block); // <save fastregs> + UML_EXIT(block, IMM(EXECUTE_MISSING_CODE)); // exit EXECUTE_MISSING_CODE + UML_LABEL(block, isi); // isi: + if (!(ppc->cap & PPCCAP_603_MMU)) + { + UML_MOV(block, SPR32(SPROEA_DSISR), MEM(&ppc->param0)); // mov [dsisr],[param0] + UML_EXH(block, ppc->impstate->exception[EXCEPTION_ISI], IREG(0)); // exh isi,i0 + } + else + { + UML_MOV(block, SPR32(SPR603_IMISS), IREG(0)); // mov [imiss],i0 + UML_MOV(block, SPR32(SPR603_ICMP), MEM(&ppc->mmu603_cmp)); // mov [icmp],[mmu603_cmp] + UML_MOV(block, SPR32(SPR603_HASH1), MEM(&ppc->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] + UML_MOV(block, SPR32(SPR603_HASH2), MEM(&ppc->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] + UML_EXH(block, ppc->impstate->exception[EXCEPTION_ITLBMISS], IREG(0)); // exh itlbmiss,i0 + } + + 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) +{ + drcuml_codehandle **exception_handle = recover ? &ppc->impstate->exception[exception] : &ppc->impstate->exception_norecover[exception]; + UINT32 vector = exception << 8; + drcuml_codelabel label = 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 */ + alloc_handle(drcuml, exception_handle, name); + UML_HANDLE(block, *exception_handle); // handle name + + /* exception parameter is expected to be the fault address in this case */ + if (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI) + { + UML_GETEXP(block, IREG(0)); // getexp i0 + UML_MOV(block, SPR32(SPROEA_DAR), IREG(0)); // mov [dar],i0 + } + + /* fetch the PC and uncounted cycles */ + if (recover) + { + UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC + UML_RECOVER(block, IREG(1), MAPVAR_CYCLES); // recover i1,CYCLES + } + + /* OEA handling of SRR exceptions */ + if (ppc->cap & PPCCAP_OEA) + { + UINT32 msrandmask = MSROEA_POW | MSR_EE | MSR_PR | MSROEA_FP | MSROEA_FE0 | MSROEA_SE | MSROEA_BE | MSROEA_FE1 | MSROEA_IR | MSROEA_DR | MSROEA_RI | MSR_LE; + UINT32 msrormask = 0; + + /* check registers to see the real source of our exception (EI exceptions only) */ + UML_MOV(block, IREG(3), IMM(vector)); // mov i3,vector + if (exception == EXCEPTION_EI) + { + drcuml_codelabel not_decrementer; + + UML_TEST(block, MEM(&ppc->irq_pending), IMM(0x01)); // test [irq_pending],0x01 + UML_JMPc(block, IF_NZ, not_decrementer = label++); // jmp not_decrementer,nz + UML_MOV(block, IREG(3), IMM(EXCEPTION_DECREMENT << 8)); // mov i3,EXCEPTION_DECREMENT << 8 + UML_AND(block, MEM(&ppc->irq_pending), MEM(&ppc->irq_pending), IMM(~0x02)); // and [irq_pending],[irq_pending],~0x02 + UML_LABEL(block, not_decrementer); // not_decrementer: + } + + /* exception PC goes into SRR0 */ + UML_MOV(block, SPR32(SPROEA_SRR0), IREG(0)); // mov [srr0],i0 + + /* MSR bits go into SRR1, along with some exception-specific data */ + UML_AND(block, SPR32(SPROEA_SRR1), MSR32, IMM(0x87c0ffff)); // and [srr1],[msr],0x87c0ffff + if (exception == EXCEPTION_PROGRAM) + { + UML_GETEXP(block, IREG(1)); // getexp i1 + UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), IREG(1)); // or [srr1],[srr1],i1 + } + if (ppc->cap & PPCCAP_603_MMU) + { + if (exception == EXCEPTION_ITLBMISS) + UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), IMM(0x00040000)); // or [srr1],0x00040000 + else if (exception == EXCEPTION_DTLBMISSL) + UML_OR(block, SPR32(SPROEA_SRR1), SPR32(SPROEA_SRR1), IMM(0x00010000)); // or [srr1],0x00010000 + if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) + UML_ROLINS(block, SPR32(SPROEA_SRR1), CR32, IMM(0), IMM(CRMASK(0))); // rolins [srr1],[cr],0,crmask(0) + } + + /* update MSR */ + if (ppc->cap & PPCCAP_603_MMU) + { + if (exception == EXCEPTION_ITLBMISS || exception == EXCEPTION_DTLBMISSL || exception == EXCEPTION_DTLBMISSS) + msrormask |= MSR603_TGPR; + else + msrandmask |= MSR603_TGPR; + UML_MOV(block, IREG(0), MSR32); // mov i0,[msr] + } + UML_AND(block, IREG(2), MSR32, IMM(~msrandmask)); // and i2,[msr],~andmask + UML_OR(block, IREG(2), IREG(2), IMM(msrormask)); // or i2,i2,ormask + UML_ROLINS(block, IREG(2), IREG(2), IMM(16), IMM(MSR_LE)); // rolins i2,u2,16,MSR_LE + UML_MOV(block, MSR32, IREG(2)); // mov [msr],i2 + if (ppc->cap & PPCCAP_603_MMU) + { + UML_XOR(block, IREG(0), IREG(0), IREG(2)); // xor i0,i0,i2 + UML_TEST(block, IREG(0), IMM(MSR603_TGPR)); // test i0,tgpr + UML_CALLHc(block, IF_NZ, ppc->impstate->swap_tgpr); // callh swap_tgpr,nz + } + generate_update_mode(block); // <update mode> + + /* determine our target PC */ + UML_MOV(block, IREG(0), IMM(0x00000000)); // mov i0,0x00000000 + UML_TEST(block, MSR32, IMM(MSROEA_IP)); // test [msr],IP + UML_MOVc(block, IF_NZ, IREG(0), IMM(0xfff00000)); // mov i0,0xfff00000,nz + UML_OR(block, IREG(0), IREG(0), IREG(3)); // or i0,i0,i3 + } + + /* 4XX handling of exceptions */ + if (ppc->cap & PPCCAP_4XX) + { + /* check registers to see the real source of our exception (EI exceptions only) */ + UML_MOV(block, IREG(3), IMM(vector)); // mov i3,vector + if (exception == EXCEPTION_EI) + { + drcuml_codelabel notwdog, common; + + UML_TEST(block, SPR32(SPR4XX_TSR), IMM(PPC4XX_TSR_PIS)); // test [tsr],PIS + UML_MOVc(block, IF_NZ, IREG(3), IMM(0x1000)); // mov i3,0x1000,NZ + UML_TEST(block, SPR32(SPR4XX_TSR), IMM(PPC4XX_TSR_FIS)); // test [tsr],FIS + UML_MOVc(block, IF_NZ, IREG(3), IMM(0x1010)); // mov i3,0x1010,NZ + UML_TEST(block, SPR32(DCR4XX_EXISR), SPR32(DCR4XX_EXIER)); // test [exisr],[exier] + UML_MOVc(block, IF_NZ, IREG(3), IMM(vector)); // mov i3,vector,NZ + UML_TEST(block, SPR32(SPR4XX_TSR), IMM(PPC4XX_TSR_WIS)); // test [tsr],WIS + UML_JMPc(block, IF_Z, notwdog = label++); // jz notwdog + UML_MOV(block, IREG(3), IMM(0x1020)); // mov i3,0x1020 + + /* exception PC goes into SRR2, MSR goes to SRR3 */ + UML_MOV(block, SPR32(SPR4XX_SRR2), IREG(0)); // mov [srr2],i0 + UML_MOV(block, SPR32(SPR4XX_SRR3), MSR32); // mov [srr3],[msr] + UML_AND(block, IREG(2), MSR32, IMM(~(MSR4XX_WE | MSR_PR | MSR4XX_CE | MSR_EE | MSR4XX_DE | MSR4XX_PE))); + UML_JMP(block, common = label++); // jmp common + + /* exception PC goes into SRR0, MSR goes to SRR1 */ + UML_LABEL(block, notwdog); // notwdog: + UML_MOV(block, SPR32(SPR4XX_SRR0), IREG(0)); // mov [srr0],i0 + UML_MOV(block, SPR32(SPR4XX_SRR1), MSR32); // mov [srr1],[msr] + UML_AND(block, IREG(2), MSR32, IMM(~(MSR4XX_WE | MSR_PR | MSR_EE | MSR4XX_PE)));// and i2,[msr],~(bunch-o-flags) + UML_LABEL(block, common); // common: + } + else + { + /* exception PC goes into SRR0, MSR goes to SRR1 */ + UML_MOV(block, SPR32(SPR4XX_SRR0), IREG(0)); // mov [srr0],i0 + UML_MOV(block, SPR32(SPR4XX_SRR1), MSR32); // mov [srr1],[msr] + UML_AND(block, IREG(2), MSR32, IMM(~(MSR4XX_WE | MSR_PR | MSR_EE | MSR4XX_PE)));// and i2,[msr],~(bunch-o-flags) + } + + /* finish updating MSR */ + UML_ROLINS(block, IREG(2), IREG(2), IMM(16), IMM(MSR_LE)); // rolins i2,u2,16,MSR_LE + UML_MOV(block, MSR32, IREG(2)); // mov [msr],i2 + generate_update_mode(block); // <update mode> + + /* program exception flags go to ESR */ + if (exception == EXCEPTION_PROGRAM) + { + UML_GETEXP(block, IREG(1)); // getexp i1 + UML_SHL(block, SPR32(SPR4XX_ESR), IREG(1), IMM(8)); // shl [esr],i1,8 + } + + /* determine our target PC */ + UML_ROLINS(block, IREG(3), SPR32(SPR4XX_EVPR), IMM(0), IMM(0xffff0000)); // rolins i3,[evpr],0,0xffff0000 + UML_MOV(block, IREG(0), IREG(3)); // mov i0,i3 + } + + /* optionally print exceptions */ + if ((PRINTF_EXCEPTIONS && exception != EXCEPTION_EI && exception != EXCEPTION_SYSCALL) || + (PRINTF_MMU && (exception == EXCEPTION_ISI || exception == EXCEPTION_DSI))) + { + UML_MOV(block, MEM(&ppc->param0), IMM(exception)); // mov [param0],exception + UML_CALLC(block, cfunc_printf_exception, NULL); // callc cfunc_printf_exception,NULL + } + + /* adjust cycles */ + UML_SUBf(block, MEM(&ppc->icount), MEM(&ppc->icount), IREG(1), FLAGS_S); // sub icount,icount,cycles,S + UML_EXHc(block, IF_S, ppc->impstate->out_of_cycles, IREG(0)); // exh out_of_cycles,i0 + UML_HASHJMP(block, MEM(&ppc->impstate->mode), IREG(0), ppc->impstate->nocode); // hashjmp <mode>,i0,nocode + + drcuml_block_end(block); +} + + +/*------------------------------------------------------------------ + static_generate_memory_accessor +------------------------------------------------------------------*/ + +static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int size, int iswrite, int ismasked, const char *name, drcuml_codehandle **handleptr, drcuml_codehandle *masked) +{ + /* on entry, address is in I0; data for writes is in I1; masks are in I2 */ + /* on exit, read result is in I0 */ + /* routine trashes I0-I3 */ + int fastxor = BYTE8_XOR_BE(0) >> (activecpu_databus_width(ADDRESS_SPACE_PROGRAM) < 64); + drcuml_block *block; + jmp_buf errorbuf; + int tlbreturn = 0; + int unaligned = 0; + int alignex = 0; + int tlbmiss = 0; + int label = 1; + 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 + + /* check for unaligned accesses and break into two */ + if (!ismasked && size != 1) + { + /* in little-endian mode, anything misaligned generates an exception */ + if ((mode & MODE_LITTLE_ENDIAN) || masked == NULL || !(ppc->cap & PPCCAP_MISALIGNED)) + { + UML_TEST(block, IREG(0), IMM(size - 1)); // test i0,size-1 + UML_JMPc(block, IF_NZ, alignex = label++); // jmp alignex,nz + } + + /* in big-endian mode, it's more complicated */ + else + { + /* 8-byte accesses must be word-aligned */ + if (size == 8) + { + UML_TEST(block, IREG(0), IMM(3)); // test i0,3 + UML_JMPc(block, IF_NZ, alignex = label++); // jmp alignex,nz + } + + /* unaligned 2 and 4 byte accesses need to be broken up */ + else + { + UML_TEST(block, IREG(0), IMM(size - 1)); // test i0,size-1 + UML_JMPc(block, IF_NZ, unaligned = label++); // jmp unaligned,nz + } + } + } + + /* general case: assume paging and perform a translation */ + if ((ppc->cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) + { + UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12 + UML_LOAD(block, IREG(3), ppc->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword + UML_TEST(block, IREG(3), IMM(iswrite ? TLB_WRITE : TLB_READ)); // test i3,iswrite ? TLB_WRITE : TLB_READ + UML_JMPc(block, IF_Z, tlbmiss = label++); // jmp tlbmiss,z + UML_LABEL(block, tlbreturn = label++); // tlbreturn: + UML_ROLINS(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // rolins i0,i3,0,0xfffff000 + } + UML_XOR(block, IREG(0), IREG(0), IMM((mode & MODE_LITTLE_ENDIAN) ? (8 - size) : 0)); // xor i0,i0,8-size + + for (ramnum = 0; ramnum < PPC_MAX_FASTRAM; ramnum++) + if (!Machine->debug_mode && ppc->impstate->fastram[ramnum].base != NULL && (!iswrite || !ppc->impstate->fastram[ramnum].readonly)) + { + void *fastbase = (UINT8 *)ppc->impstate->fastram[ramnum].base - ppc->impstate->fastram[ramnum].start; + UINT32 skip = label++; + + if (ppc->impstate->fastram[ramnum].end != 0xffffffff) + { + UML_CMP(block, IREG(0), IMM(ppc->impstate->fastram[ramnum].end)); // cmp i0,end + UML_JMPc(block, IF_A, skip); // ja skip + } + if (ppc->impstate->fastram[ramnum].start != 0x00000000) + { + UML_CMP(block, IREG(0), IMM(ppc->impstate->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(fastxor >> 0)); // xor i0,i0,fastxor >> 0 + UML_LOAD(block, IREG(0), fastbase, IREG(0), BYTE); // load i0,fastbase,i0,byte + } + 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(fastxor >> 1)); // xor i0,i0,fastxor >> 1 + UML_LOAD(block, IREG(0), fastbase, IREG(0), WORD); // load i0,fastbase,i0,word + } + else if (size == 4) + { + UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2 + UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 2)); // xor i0,i0,fastxor >> 2 + UML_LOAD(block, IREG(0), fastbase, IREG(0), DWORD); // load i0,fastbase,i0,dword + } + else if (size == 8) + { + UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3 + UML_DLOAD(block, IREG(0), fastbase, IREG(0), QWORD); // dload i0,fastbase,i0,qword + } + UML_RET(block); // ret + } + else + { + if (size == 1) + { + UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 0)); // xor i0,i0,fastxor >> 0 + UML_STORE(block, fastbase, IREG(0), IREG(1), BYTE); // store fastbase,i0,i1,byte + } + 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(fastxor >> 1)); // xor i0,i0,fastxor >> 1 + UML_STORE(block, fastbase, IREG(0), IREG(1), WORD); // store fastbase,i0,i1,word + } + else if (size == 4) + { + UML_SHR(block, IREG(0), IREG(0), IMM(2)); // shr i0,i0,2 + UML_XOR(block, IREG(0), IREG(0), IMM(fastxor >> 2)); // xor i0,i0,fastxor >> 2 + if (ismasked) + { + UML_LOAD(block, IREG(3), fastbase, IREG(0), DWORD); // load i3,fastbase,i0,dword + 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_STORE(block, fastbase, IREG(0), IREG(1), DWORD); // store fastbase,i0,i1,dword + } + else if (size == 8) + { + UML_SHR(block, IREG(0), IREG(0), IMM(3)); // shr i0,i0,3 + if (ismasked) + { + UML_DLOAD(block, IREG(3), fastbase, IREG(0), QWORD); // dload i3,fastbase,i0,qword + 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_DSTORE(block, fastbase, IREG(0), IREG(1), QWORD); // dstore fastbase,i0,i1,qword + } + UML_RET(block); // ret + } + + UML_LABEL(block, skip); // skip: + } + + switch (size) + { + case 1: + if (iswrite) + UML_WRITE(block, IREG(0), IREG(1), PROGRAM_BYTE); // write i0,i1,program_byte + else + UML_READ(block, IREG(0), IREG(0), PROGRAM_BYTE); // read i0,i0,program_byte + break; + + case 2: + if (iswrite) + { + if (!ismasked) + UML_WRITE(block, IREG(0), IREG(1), PROGRAM_WORD); // write i0,i1,program_word + else + UML_WRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_WORD); // writem i0,i2,i1,program_word + } + else + { + if (!ismasked) + UML_READ(block, IREG(0), IREG(0), PROGRAM_WORD); // read i0,i0,program_word + else + UML_READM(block, IREG(0), IREG(0), IREG(2), PROGRAM_WORD); // readm i0,i0,i2,program_word + } + break; + + case 4: + if (iswrite) + { + if (!ismasked) + UML_WRITE(block, IREG(0), IREG(1), PROGRAM_DWORD); // write i0,i1,program_dword + else + UML_WRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_DWORD); // writem i0,i2,i1,program_dword + } + else + { + if (!ismasked) + UML_READ(block, IREG(0), IREG(0), PROGRAM_DWORD); // read i0,i0,program_dword + else + UML_READM(block, IREG(0), IREG(0), IREG(2), PROGRAM_DWORD); // readm i0,i0,i2,program_dword + } + break; + + case 8: + if (iswrite) + { + if (!ismasked) + UML_DWRITE(block, IREG(0), IREG(1), PROGRAM_QWORD); // dwrite i0,i1,program_qword + else + UML_DWRITEM(block, IREG(0), IREG(2), IREG(1), PROGRAM_QWORD); // dwritem i0,i2,i1,program_qword + } + else + { + if (!ismasked) + UML_DREAD(block, IREG(0), IREG(0), PROGRAM_QWORD); // dread i0,i0,program_qword + else + UML_DREADM(block, IREG(0), IREG(0), IREG(2), PROGRAM_QWORD); // dreadm i0,i0,i2,program_qword + } + break; + } + UML_RET(block); // ret + + /* handle unaligned accesses */ + if (unaligned != 0) + { + UML_LABEL(block, unaligned); // unaligned: + if (size == 2) + { + if (iswrite) + { + UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 + UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(1)); // mov [tempdata],i1 + UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 + UML_SHR(block, IREG(1), IREG(1), IMM(8)); // shr i1,i1,8 + UML_MOV(block, IREG(2), IMM(0x00ff)); // mov i2,0x00ff + UML_CALLH(block, masked); // callh masked + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 + UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(8)); // shl i1,[tempdata],8 + UML_MOV(block, IREG(2), IMM(0xff00)); // mov i2,0xff00 + UML_CALLH(block, masked); // callh masked + } + else + { + UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 + UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 + UML_MOV(block, IREG(2), IMM(0x00ff)); // mov i2,0x00ff + UML_CALLH(block, masked); // callh masked + UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(8)); // shl [tempdata],i0,8 + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 + UML_MOV(block, IREG(2), IMM(0xff00)); // mov i2,0xff00 + UML_CALLH(block, masked); // callh masked + UML_SHR(block, IREG(0), IREG(0), IMM(8)); // shr i0,i0,8 + UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] + } + } + else if (size == 4) + { + int offs2, offs3; + if (iswrite) + { + UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 + UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(1)); // mov [tempdata],i1 + UML_TEST(block, IREG(0), IMM(2)); // test i0,i0,2 + UML_JMPc(block, IF_NZ, offs2 = label++); // jnz offs2 + UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 + UML_SHR(block, IREG(1), IREG(1), IMM(8)); // shr i1,i1,8 + UML_MOV(block, IREG(2), IMM(0x00ffffff)); // mov i2,0x00ffffff + UML_CALLH(block, masked); // callh masked + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(3)); // add i0,[tempaddr],3 + UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(24)); // shl i1,[tempdata],24 + UML_MOV(block, IREG(2), IMM(0xff000000)); // mov i2,0xff000000 + UML_CALLH(block, masked); // callh masked + UML_RET(block); // ret + UML_LABEL(block, offs2); // offs2: + UML_TEST(block, IREG(0), IMM(1)); // test i0,i0,1 + UML_JMPc(block, IF_NZ, offs3 = label++); // jnz offs3 + UML_SUB(block, IREG(0), IREG(0), IMM(2)); // sub i0,i0,2 + UML_SHR(block, IREG(1), IREG(1), IMM(16)); // shr i1,i1,16 + UML_MOV(block, IREG(2), IMM(0x0000ffff)); // mov i2,0x0000ffff + UML_CALLH(block, masked); // callh masked + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(2)); // add i0,[tempaddr],2 + UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(16)); // shl i1,[tempdata],16 + UML_MOV(block, IREG(2), IMM(0xffff0000)); // mov i2,0xffff0000 + UML_CALLH(block, masked); // callh masked + UML_RET(block); // ret + UML_LABEL(block, offs3); // offs3: + UML_SUB(block, IREG(0), IREG(0), IMM(3)); // sub i0,i0,3 + UML_SHR(block, IREG(1), IREG(1), IMM(24)); // shr i1,i1,24 + UML_MOV(block, IREG(2), IMM(0x000000ff)); // mov i2,0x000000ff + UML_CALLH(block, masked); // callh masked + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 + UML_SHL(block, IREG(1), MEM(&ppc->impstate->tempdata), IMM(8)); // shl i1,[tempdata],8 + UML_MOV(block, IREG(2), IMM(0xffffff00)); // mov i2,0xffffff00 + UML_CALLH(block, masked); // callh masked + } + else + { + UML_MOV(block, MEM(&ppc->impstate->tempaddr), IREG(0)); // mov [tempaddr],i0 + UML_TEST(block, IREG(0), IMM(2)); // test i0,i0,2 + UML_JMPc(block, IF_NZ, offs2 = label++); // jnz offs2 + UML_SUB(block, IREG(0), IREG(0), IMM(1)); // sub i0,i0,1 + UML_MOV(block, IREG(2), IMM(0x00ffffff)); // mov i2,0x00ffffff + UML_CALLH(block, masked); // callh masked + UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(8)); // shl [tempdata],i0,8 + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(3)); // add i0,[tempaddr],3 + UML_MOV(block, IREG(2), IMM(0xff000000)); // mov i2,0xff000000 + UML_CALLH(block, masked); // callh masked + UML_SHR(block, IREG(0), IREG(0), IMM(24)); // shr i0,i0,24 + UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] + UML_RET(block); // ret + UML_LABEL(block, offs2); // offs2: + UML_TEST(block, IREG(0), IMM(1)); // test i0,i0,1 + UML_JMPc(block, IF_NZ, offs3 = label++); // jnz offs3 + UML_SUB(block, IREG(0), IREG(0), IMM(2)); // sub i0,i0,2 + UML_MOV(block, IREG(2), IMM(0x0000ffff)); // mov i2,0x0000ffff + UML_CALLH(block, masked); // callh masked + UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(16)); // shl [tempdata],i0,16 + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(2)); // add i0,[tempaddr],2 + UML_MOV(block, IREG(2), IMM(0xffff0000)); // mov i2,0xffff0000 + UML_CALLH(block, masked); // callh masked + UML_SHR(block, IREG(0), IREG(0), IMM(16)); // shr i0,i0,16 + UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] + UML_RET(block); // ret + UML_LABEL(block, offs3); // offs3: + UML_SUB(block, IREG(0), IREG(0), IMM(3)); // sub i0,i0,3 + UML_MOV(block, IREG(2), IMM(0x000000ff)); // mov i2,0x000000ff + UML_CALLH(block, masked); // callh masked + UML_SHL(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(24)); // shl [tempdata],i0,24 + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(1)); // add i0,[tempaddr],1 + UML_MOV(block, IREG(2), IMM(0xffffff00)); // mov i2,0xffffff00 + UML_CALLH(block, masked); // callh masked + UML_SHR(block, IREG(0), IREG(0), IMM(8)); // shr i0,i0,8 + UML_OR(block, IREG(0), IREG(0), MEM(&ppc->impstate->tempdata)); // or i0,i0,[tempdata] + } + } + UML_RET(block); // ret + } + + /* handle an alignment exception */ + if (alignex != 0) + { + UML_LABEL(block, alignex); // alignex: + UML_RECOVER(block, SPR32(SPROEA_DSISR), MAPVAR_DSISR); // recover [dsisr],DSISR + UML_EXH(block, ppc->impstate->exception[EXCEPTION_ALIGN], IREG(0)); // exh align,i0 + } + + /* handle a TLB miss */ + if (tlbmiss != 0) + { + int dsi; + + UML_LABEL(block, tlbmiss); // tlbmiss: + UML_MOV(block, MEM(&ppc->param0), IREG(0)); // mov [param0],i0 + UML_MOV(block, MEM(&ppc->param1), IMM(iswrite ? TRANSLATE_WRITE : TRANSLATE_READ)); // mov [param1],TRANSLATE_READ/WRITE + UML_CALLC(block, ppccom_tlb_fill, ppc); // callc tlbfill,ppc + UML_CMP(block, MEM(&ppc->param0), IMM(1)); // cmp [param0],1 + UML_JMPc(block, IF_A, dsi = label++); // jmp dsi,A + UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12 + UML_LOAD(block, IREG(3), ppc->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword + UML_JMP(block, tlbreturn); // jmp tlbreturn + UML_LABEL(block, dsi); // dsi: + if (!(ppc->cap & PPCCAP_603_MMU)) + { + UML_MOV(block, SPR32(SPROEA_DSISR), MEM(&ppc->param0)); // mov [dsisr],[param0] + UML_EXH(block, ppc->impstate->exception[EXCEPTION_DSI], IREG(0)); // exh dsi,i0 + } + else + { + UML_MOV(block, SPR32(SPR603_DMISS), IREG(0)); // mov [dmiss],i0 + UML_MOV(block, SPR32(SPR603_DCMP), MEM(&ppc->mmu603_cmp)); // mov [dcmp],[mmu603_cmp] + UML_MOV(block, SPR32(SPR603_HASH1), MEM(&ppc->mmu603_hash[0])); // mov [hash1],[mmu603_hash][0] + UML_MOV(block, SPR32(SPR603_HASH2), MEM(&ppc->mmu603_hash[1])); // mov [hash2],[mmu603_hash][1] + if (iswrite) + UML_EXH(block, ppc->impstate->exception[EXCEPTION_DTLBMISSS], IREG(0)); // exh dtlbmisss,i0 + else + UML_EXH(block, ppc->impstate->exception[EXCEPTION_DTLBMISSL], IREG(0)); // exh dtlbmissl,i0 + } + } + + drcuml_block_end(block); +} + + +/*------------------------------------------------- + static_generate_swap_tgpr - generate a + subroutine to swap GPR0-3 with TGPR0-3 +-------------------------------------------------*/ + +static void static_generate_swap_tgpr(drcuml_state *drcuml) +{ + drcuml_block *block; + jmp_buf errorbuf; + int regnum; + + /* if we get an error back, we're screwed */ + if (setjmp(errorbuf) != 0) + fatalerror("Unrecoverable error in static_generate_swap_tgpr"); + + /* begin generating */ + block = drcuml_block_begin(drcuml, 30, &errorbuf); + + /* generate a hash jump via the current mode and PC */ + alloc_handle(drcuml, &ppc->impstate->swap_tgpr, "swap_tgpr"); + UML_HANDLE(block, ppc->impstate->swap_tgpr); // handle swap_tgpr + for (regnum = 0; regnum < 4; regnum++) + { + UML_MOV(block, IREG(1), R32(regnum)); // mov i1,r[regnum] + UML_MOV(block, R32(regnum), MEM(&ppc->mmu603_r[regnum])); // mov r[regnum],mmu603_r[regnum] + UML_MOV(block, MEM(&ppc->mmu603_r[regnum]), IREG(1)); // mov mmu603_r[regnum],i1 + } + UML_RET(block); // ret + + drcuml_block_end(block); +} + + + +/*************************************************************************** + CODE GENERATION +***************************************************************************/ + +/*------------------------------------------------- + generate_update_mode - update the mode based + on the MSR +-------------------------------------------------*/ + +static void generate_update_mode(drcuml_block *block) +{ + UML_AND(block, IREG(0), MSR32, IMM(MSR_LE)); // and i0,msr,MSR_LE + UML_AND(block, IREG(1), MSR32, IMM(MSROEA_DR)); // and i1,msr,MSR_DR + UML_SHR(block, IREG(1), IREG(1), IMM(3)); // shr i1,i1,3 + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 + UML_AND(block, IREG(1), MSR32, IMM(MSR_PR)); // and i1,msr,MSR_PR + UML_SHR(block, IREG(1), IREG(1), IMM(12)); // shr i1,i1,12 + UML_OR(block, MEM(&ppc->impstate->mode), IREG(0), IREG(1)); // or [mode],i0,i1 +} + + +/*------------------------------------------------- + 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, drcuml_ptype ptype, UINT64 pvalue, int allow_exception) +{ + /* check full interrupts if pending */ + if (compiler->checkints) + { + drcuml_codelabel skip; + + compiler->checkints = FALSE; + UML_TEST(block, MEM(&ppc->irq_pending), IMM(~0)); // test [irq_pending],0 + UML_JMPc(block, IF_Z, skip = compiler->labelnum++); // jmp skip,Z + UML_TEST(block, MSR32, IMM(MSR_EE)); // test [msr],MSR_EE + UML_JMPc(block, IF_Z, skip); // jmp skip,Z + UML_MOV(block, IREG(0), PARAM(ptype, pvalue)); // mov i0,nextpc + UML_MOV(block, IREG(1), IMM(compiler->cycles)); // mov i1,cycles + UML_CALLH(block, ppc->impstate->exception_norecover[EXCEPTION_EI]); // callh interrupt_norecover + UML_LABEL(block, skip); // skip: + } + + /* account for cycles */ + if (compiler->cycles > 0) + { + UML_SUBf(block, MEM(&ppc->icount), MEM(&ppc->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) + UML_EXHc(block, IF_S, ppc->impstate->out_of_cycles, PARAM(ptype, pvalue)); // exh out_of_cycles,nextpc + } + 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 (!(ppc->impstate->drcoptions & PPCDRC_STRICT_VERIFY) || seqhead->next == NULL) + { + if (!(seqhead->flags & OPFLAG_VIRTUAL_NOOP)) + { + UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,dword + UML_CMP(block, IREG(0), IMM(*seqhead->opptr.l)); // cmp i0,*opptr + UML_EXHc(block, IF_NE, ppc->impstate->nocode, IMM(seqhead->pc)); // exne nocode,seqhead->pc + } + } + + /* full verification; sum up everything */ + else + { +#if 0 + for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + UML_LOAD(block, IREG(0), curdesc->opptr.l, IMM(0), DWORD); // load i0,*opptr,dword + UML_CMP(block, IREG(0), IMM(*curdesc->opptr.l)); // cmp i0,*opptr + UML_EXHc(block, IF_NE, ppc->impstate->nocode, IMM(seqhead->pc)); // exne nocode,seqhead->pc + } +#else + UINT32 sum = 0; + UML_LOAD(block, IREG(0), seqhead->opptr.l, IMM(0), DWORD); // load i0,*opptr,dword + sum += *seqhead->opptr.l; + for (curdesc = seqhead->next; curdesc != seqlast->next; curdesc = curdesc->next) + if (!(curdesc->flags & OPFLAG_VIRTUAL_NOOP)) + { + UML_LOAD(block, IREG(1), curdesc->opptr.l, IMM(0), DWORD); // load i1,*opptr,dword + 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, ppc->impstate->nocode, IMM(seqhead->pc)); // exne nocode,seqhead->pc +#endif + } +} + + +/*------------------------------------------------- + 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) +{ + int hotnum; + + /* add an entry for the log */ + if (LOG_UML && !(desc->flags & OPFLAG_VIRTUAL_NOOP)) + log_add_disasm_comment(block, desc->pc, *desc->opptr.l); + + /* set the PC map variable */ + UML_MAPVAR(block, MAPVAR_PC, desc->pc); // mapvar PC,desc->pc + + /* accumulate total cycles */ + compiler->cycles += desc->cycles; + + /* is this a hotspot? */ + for (hotnum = 0; hotnum < PPC_MAX_HOTSPOTS; hotnum++) + if (ppc->impstate->hotspot[hotnum].pc != 0 && desc->pc == ppc->impstate->hotspot[hotnum].pc && *desc->opptr.l == ppc->impstate->hotspot[hotnum].opcode) + { + compiler->cycles += ppc->impstate->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(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc + save_fast_iregs(block); // <save fastregs> + UML_DEBUG(block, IMM(desc->pc)); // debug desc->pc + } + + /* if we hit an unmapped address, fatal error */ + if (desc->flags & OPFLAG_COMPILER_UNMAPPED) + { + UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc + save_fast_iregs(block); // <save fastregs> + UML_EXIT(block, IMM(EXECUTE_UNMAPPED_CODE)); // exit EXECUTE_UNMAPPED_CODE + } + + /* if we hit a compiler page fault, it's just like a TLB mismatch */ + if (desc->flags & OPFLAG_COMPILER_PAGE_FAULT) + { + if (PRINTF_MMU) + { + UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, "Compiler page fault @ %08X\n"); // callc printf_debug + } + UML_EXH(block, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0 + } + + /* validate our TLB entry at this PC; if we fail, we need to handle it */ + if ((desc->flags & OPFLAG_VALIDATE_TLB) && (ppc->impstate->mode & MODE_DATA_TRANSLATION)) + { + /* if we currently have a valid TLB read entry, we just verify */ + if (ppc->tlb_table[desc->pc >> 12] != 0) + { + if (PRINTF_MMU) + { + UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, "Checking TLB at @ %08X\n"); // callc printf_debug + } + UML_LOAD(block, IREG(0), &ppc->tlb_table[desc->pc >> 12], IMM(0), DWORD); // load i0,tlb_table[desc->pc >> 12],dword + UML_CMP(block, IREG(0), IMM(ppc->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry + UML_EXHc(block, IF_NE, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE + } + + /* otherwise, we generate an unconditional exception */ + else + { + if (PRINTF_MMU) + { + UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc + UML_CALLC(block, cfunc_printf_debug, "No valid TLB @ %08X\n"); // callc printf_debug + } + UML_EXH(block, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0 + } + } + + /* if this is an invalid opcode, generate the exception now */ + if (desc->flags & OPFLAG_INVALID_OPCODE) + UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x80000)); // exh exception_program,0x80000 + + /* if this is a privileged opcode in user mode, generate the exception */ + else if ((desc->flags & OPFLAG_PRIVILEGED) && (ppc->impstate->mode & MODE_USER)) + UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x40000)); // exh exception_program,0x40000 + + /* otherwise, unless this is a virtual no-op, it's a regular instruction */ + else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP)) + { + /* compile the instruction */ + if (!generate_opcode(block, compiler, desc)) + { + UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc + UML_CALLC(block, cfunc_unimplemented, (void *)(FPTR)*desc->opptr.l); // callc cfunc_unimplemented + } + } +} + + +/*------------------------------------------------------------------ + generate_compute_flags - compute CR0 and/or XER flags +------------------------------------------------------------------*/ + +static void generate_compute_flags(drcuml_block *block, int updatecr, UINT32 xermask, int invertcarry) +{ + int xerflags = ((xermask & XER_OV) ? DRCUML_FLAG_V : 0) | ((xermask & XER_CA) ? DRCUML_FLAG_C : 0); + UINT32 xermask_so = xermask | ((xermask & XER_OV) ? XER_SO : 0); + + /* easy case: nothing to do */ + if (!updatecr && xermask == 0) + return; + + /* semi-easy case: crfield only */ + if (xermask == 0) + { + UML_MOV(block, IREG(0), CR32); // mov i0,cr32 + UML_GETFLGS(block, IREG(1), DRCUML_FLAG_S | DRCUML_FLAG_Z); // getflgs i1,sz + UML_LOAD(block, IREG(1), ppc->impstate->sz_cr_table, IREG(1), DWORD); // load i1,sz_cr_table,i1,dword + UML_ROLINS(block, IREG(0), IREG(1), IMM(0), IMM(CRMASK(0))); // rolins i0,i1,0,crmask(field) + UML_AND(block, IREG(1), SPR32(SPR_XER), IMM(XER_SO)); // and i1,[xer],XER_SO + UML_SHR(block, IREG(1), IREG(1), IMM(3)); // shr i1,i1,3 + UML_OR(block, CR32, IREG(0), IREG(1)); // or [cr],i0,i1 + return; + } + + /* semi-easy case: xer only */ + if (!updatecr) + { + if (xermask & XER_OV) + { + UML_MOV(block, IREG(0), SPR32(SPR_XER)); // mov i0,[xer] + UML_GETFLGS(block, IREG(1), xerflags); // getflgs i1,xerflags + if (invertcarry && (xermask & XER_CA)) + UML_XOR(block, IREG(1), IREG(1), IMM(DRCUML_FLAG_C)); // xor i1,i1,FLAG_C + UML_ROLINS(block, IREG(0), IREG(1), IMM(29), IMM(xermask)); // rolins i0,i1,29,crmask(xermask) + UML_AND(block, IREG(1), SPR32(SPR_XER), IMM(XER_OV)); // and i1,[xer],XER_OV + UML_SHL(block, IREG(1), IREG(1), IMM(1)); // shl i1,i1,1 + UML_OR(block, SPR32(SPR_XER), IREG(0), IREG(1)); // or [xer],i0,i1 + } + else + { + UML_SETc(block, invertcarry ? IF_NC : IF_C, IREG(0)); // setc i0,nc/c + UML_ROLINS(block, SPR32(SPR_XER), IREG(0), IMM(29), IMM(XER_CA)); // rolins [xer],i0,29,XER_CA + } + return; + } + + /* tricky case: both */ + UML_GETFLGS(block, IREG(0), DRCUML_FLAG_S | DRCUML_FLAG_Z | xerflags); // getflgs i0,sz|xerflags + if (invertcarry) + UML_XOR(block, IREG(2), IREG(2), IMM(DRCUML_FLAG_C)); // xor i2,i2,FLAG_C + UML_LOAD(block, IREG(0), ppc->impstate->sz_cr_table, IREG(0), DWORD); // load i0,sz_cr_table,i0,dword + UML_AND(block, IREG(1), SPR32(SPR_XER), IMM(~xermask)); // and i1,[xer],~xermask + UML_SHL(block, IREG(2), IREG(0), IMM(4)); // shl i2,i0,4 + if (xermask_so != (XER_CA | XER_OV | XER_SO)) + UML_AND(block, IREG(2), IREG(2), IMM(xermask_so)); // and i2,i2,xermask + UML_OR(block, IREG(1), IREG(1), IREG(2)); // or i1,i1,i2 + UML_MOV(block, SPR32(SPR_XER), IREG(1)); // mov [xer],i1 + UML_SHR(block, IREG(1), IREG(1), IMM(3)); // shr i1,i1,3 + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i0,i1 + UML_AND(block, IREG(1), CR32, IMM(~CRMASK(0))); // and i1,[cr],~crmask(0) + UML_AND(block, IREG(0), IREG(0), IMM(CRMASK(0))); // and i0,i0,crmask(0) + UML_OR(block, CR32, IREG(0), IREG(1)); // or cr32,i0,i1 +} + + +/*------------------------------------------------- + generate_branch - generate an unconditional + branch +-------------------------------------------------*/ + +static void generate_branch(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, int source, UINT8 link) +{ + compiler_state compiler_temp = *compiler; + + /* set the link if needed */ + if (link) + UML_MOV(block, SPR32(SPR_LR), IMM(desc->pc + 4)); // mov [lr],desc->pc + 4 + + /* update the cycles and jump through the hash table to the target */ + if (desc->targetpc != BRANCH_TARGET_DYNAMIC) + { + generate_update_cycles(block, &compiler_temp, IMM(desc->targetpc), TRUE); // <subtract cycles> + if (desc->flags & OPFLAG_INTRABLOCK_BRANCH) + UML_JMP(block, desc->targetpc | 0x80000000); // jmp desc->targetpc | 0x80000000 + else + UML_HASHJMP(block, IMM(ppc->impstate->mode), IMM(desc->targetpc), ppc->impstate->nocode); // hashjmp <mode>,desc->targetpc,nocode + } + else + { +UML_CMP(block, SPR32(source), IMM(0xb032)); +UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); +UML_CALLCc(block, IF_E, cfunc_printf_debug, "b032 @ PC=%08X\n"); + + generate_update_cycles(block, &compiler_temp, SPR32(source), TRUE); // <subtract cycles> + UML_HASHJMP(block, IMM(ppc->impstate->mode), SPR32(source), ppc->impstate->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 +} + + +/*------------------------------------------------- + generate_branch_bo - generate a conditional + branch based on the BO and BI fields +-------------------------------------------------*/ + +static void generate_branch_bo(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc, UINT32 bo, UINT32 bi, int source, int link) +{ + int skip = compiler->labelnum++; + + if (!(bo & 0x04)) + { + UML_SUBf(block, SPR32(SPR_CTR), SPR32(SPR_CTR), IMM(1), FLAGS_Z); // sub [ctr],[ctr],1,z + UML_JMPc(block, (bo & 0x02) ? IF_NZ : IF_Z, skip); // jmp skip,nz/z + } + if (!(bo & 0x10)) + { + UML_TEST(block, CR32, IMM(0x80000000 >> bi)); // test cr32,0x80000000 >> bi + UML_JMPc(block, (bo & 0x08) ? IF_Z : IF_NZ, skip); // jmp skip,z/nz + } + generate_branch(block, compiler, desc, source, link); // <branch> + UML_LABEL(block, skip); // skip: +} + + +/*------------------------------------------------- + generate_opcode - generate code for a specific + opcode +-------------------------------------------------*/ + +static int generate_opcode(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = *desc->opptr.l; + UINT32 opswitch = op >> 26; + int regnum; + + switch (opswitch) + { + case 0x02: /* TDI - 64-bit only */ + case 0x1e: /* 0x1e group - 64-bit only */ + case 0x3a: /* 0x3a group - 64-bit only */ + case 0x3e: /* 0x3e group - 64-bit only */ + return FALSE; + + case 0x03: /* TWI */ + UML_CMP(block, R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // cmp ra,simm + if (G_TO(op) & 0x10) + UML_EXHc(block, IF_L, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,l + if (G_TO(op) & 0x08) + UML_EXHc(block, IF_G, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,g + if (G_TO(op) & 0x04) + UML_EXHc(block, IF_E, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,e + if (G_TO(op) & 0x02) + UML_EXHc(block, IF_B, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,b + if (G_TO(op) & 0x01) + UML_EXHc(block, IF_A, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,a + return TRUE; + + case 0x07: /* MULLI */ + UML_MULS(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); + // muls rd,rd,ra,simm + return TRUE; + + case 0x0e: /* ADDI */ + UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add rd,ra,simm + return TRUE; + + case 0x0f: /* ADDIS */ + UML_ADD(block, R32(G_RD(op)), R32Z(G_RA(op)), IMM(G_SIMM(op) << 16)); // add rd,ra,simm << 16 + return TRUE; + + case 0x0a: /* CMPLI */ + UML_CMP(block, R32(G_RA(op)), IMM(G_UIMM(op))); // cmp ra,uimm + UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C); // getflgs i0,zc + UML_LOAD(block, IREG(0), ppc->impstate->cmpl_cr_table, IREG(0), DWORD); // load i0,cmpl_cr_table,i0,dword + UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] + return TRUE; + + case 0x0b: /* CMPI */ + UML_CMP(block, R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // cmp ra,uimm + UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C | DRCUML_FLAG_S); // getflgs i0,zcs + UML_LOAD(block, IREG(0), ppc->impstate->cmp_cr_table, IREG(0), DWORD); // load i0,cmp_cr_table,i0,dword + UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] + return TRUE; + + case 0x08: /* SUBFIC */ + UML_SUBf(block, R32(G_RD(op)), IMM((INT16)G_SIMM(op)), R32(G_RA(op)), FLAGS_C); // sub rd,simm,ra,c + generate_compute_flags(block, FALSE, XER_CA, TRUE); // <update flags> + return TRUE; + + case 0x0c: /* ADDIC */ + UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), IMM((INT16)G_SIMM(op)), FLAGS_C); // add rd,ra,simm,c + generate_compute_flags(block, FALSE, XER_CA, FALSE); // <update flags> + return TRUE; + + case 0x0d: /* ADDIC. */ + UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), IMM((INT16)G_SIMM(op)), FLAGS_C); // add rd,ra,simm,c + generate_compute_flags(block, TRUE, XER_CA, FALSE); // <update flags> + return TRUE; + + case 0x10: /* BCx */ + generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), 0, op & M_LK); // <branch conditional> + return TRUE; + + case 0x11: /* SC */ + UML_EXH(block, ppc->impstate->exception[EXCEPTION_SYSCALL], IMM(0)); // exh syscall,0 + return TRUE; + + case 0x12: /* Bx */ + generate_branch(block, compiler, desc, 0, op & M_LK); // <branch> + return TRUE; + + case 0x13: /* 0x13 group */ + return generate_instruction_13(block, compiler, desc); // <group13> + + case 0x14: /* RLWIMIx */ + UML_ROLINS(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_SH(op)), IMM(compute_rlw_mask(G_MB(op), G_ME(op)))); + // rolins ra,rs,sh,mask + if (op & M_RC) + { + UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 + generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> + } + return TRUE; + + case 0x15: /* RLWINMx */ + UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_SH(op)), IMM(compute_rlw_mask(G_MB(op), G_ME(op)))); + // roland ra,rs,sh,mask + if (op & M_RC) + { + UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 + generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> + } + return TRUE; + + case 0x17: /* RLWNMx */ + UML_ROLAND(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), IMM(compute_rlw_mask(G_MB(op), G_ME(op)))); + // roland ra,rs,rb,mask + if (op & M_RC) + { + UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 + generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> + } + return TRUE; + + case 0x18: /* ORI */ + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op))); // or ra,rs,uimm + return TRUE; + + case 0x19: /* ORIS */ + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op) << 16)); // or ra,rs,uimm << 16 + return TRUE; + + case 0x1a: /* XORI */ + UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op))); // xor ra,rs,uimm + return TRUE; + + case 0x1b: /* XORIS */ + UML_XOR(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op) << 16)); // xor ra,rs,uimm << 16 + return TRUE; + + case 0x1c: /* ANDI. */ + UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op)), FLAGS_RC(op)); // and ra,rs,uimm,FLAGS_RC + generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> + return TRUE; + + case 0x1d: /* ANDIS. */ + UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_UIMM(op) << 16), FLAGS_RC(op));// and ra,rs,uimm << 16,FLAGS_RC + generate_compute_flags(block, TRUE, 0, FALSE); // <update flags> + return TRUE; + + case 0x1f: /* 0x1f group */ + return generate_instruction_1f(block, compiler, desc); // <group1f> + + case 0x22: /* LBZ */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x28: /* LHZ */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2a: /* LHA */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x20: /* LWZ */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x23: /* LBZU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x29: /* LHZU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2b: /* LHAU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x21: /* LWZU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x26: /* STB */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2c: /* STH */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x24: /* STW */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x27: /* STBU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2d: /* STHU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x25: /* STWU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2e: /* LMW */ + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + for (regnum = G_RD(op); regnum < 32; regnum++) + { + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op) + 4 * (regnum - G_RD(op)))); + // add i0,ra,simm + 4*(regnum-rd) + UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align + UML_MOV(block, R32(regnum), IREG(0)); // mov regnum,i0 + } + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2f: /* STMW */ + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + for (regnum = G_RS(op); regnum < 32; regnum++) + { + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op) + 4 * (regnum - G_RS(op)))); + // add i0,ra,simm + 4*(regnum-rs) + UML_MOV(block, IREG(1), R32(regnum)); // mov i1,regnum + UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode & 3]); // callh write32align + } + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x30: /* LFS */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x32: /* LFD */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 + UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x31: /* LFSU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x33: /* LFDU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 + UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x34: /* STFS */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x36: /* STFD */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op) + UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x35: /* STFSU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x37: /* STFDU */ + UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm + UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op) + UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x3b: /* 0x3b group */ + return generate_instruction_3b(block, compiler, desc); // <group3b> + + case 0x3f: /* 0x3f group */ + return generate_instruction_3f(block, compiler, desc); // <group3f> + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_instruction_13 - compile opcodes in + the 0x13 group +-------------------------------------------------*/ + +static int generate_instruction_13(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = *desc->opptr.l; + UINT32 opswitch = (op >> 1) & 0x3ff; + + switch (opswitch) + { + case 0x010: /* BCLRx */ + generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_LR, op & M_LK);// <branch conditional> + return TRUE; + + case 0x210: /* BCCTRx */ + generate_branch_bo(block, compiler, desc, G_BO(op), G_BI(op), SPR_CTR, op & M_LK); + // <branch conditional> + return TRUE; + + case 0x000: /* MCRF */ + UML_ROLINS(block, CR32, CR32, IMM(((G_CRFS(op) - G_CRFD(op)) & 7) * 4), IMM(CRMASK(G_CRFD(op)))); + // rolins cr,cr,4*(crfs-crfd),crmask[crfd] + return TRUE; + + case 0x101: /* CRAND */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_AND(block, IREG(0), IREG(0), IREG(1)); // and i0,i1 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x081: /* CRANDC */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_XOR(block, IREG(1), IREG(1), IMM(~0)); // xor i1,~0 + UML_AND(block, IREG(0), IREG(0), IREG(1)); // and i0,i1 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x0e1: /* CRNAND */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_AND(block, IREG(0), IREG(0), IREG(1)); // and i0,i1 + UML_XOR(block, IREG(0), IREG(0), IMM(~0)); // xor i0,~0 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x1c1: /* CROR */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i1 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x1a1: /* CRORC */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_XOR(block, IREG(1), IREG(1), IMM(~0)); // xor i1,~0 + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i1 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x021: /* CRNOR */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_OR(block, IREG(0), IREG(0), IREG(1)); // or i0,i1 + UML_XOR(block, IREG(0), IREG(0), IMM(~0)); // xor i0,~0 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x0c1: /* CRXOR */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_XOR(block, IREG(0), IREG(0), IREG(1)); // xor i0,i1 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x121: /* CREQV */ + UML_SHL(block, IREG(0), CR32, IMM(G_CRBA(op))); // shl i0,cr,crba(op) + UML_SHL(block, IREG(1), CR32, IMM(G_CRBB(op))); // shl i1,cr,crbb(op) + UML_XOR(block, IREG(0), IREG(0), IREG(1)); // xor i0,i1 + UML_XOR(block, IREG(0), IREG(0), IMM(~0)); // xor i0,~0 + UML_ROLINS(block, CR32, IREG(0), IMM(32 - G_CRBD(op)), IMM(0x80000000 >> G_CRBD(op))); + // rolins cr,i0,32-crbd,1<<crbd + return TRUE; + + case 0x032: /* RFI */ + if (ppc->cap & PPCCAP_OEA) + { + if (!(ppc->cap & PPCCAP_603_MMU)) + UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), IMM(0), IMM(0x87c0ffff)); // rolins [msr],[srr1],0,0x87c0ffff + else + { + UML_MOV(block, IREG(0), MSR32); // mov i0,[msr] + UML_ROLINS(block, MSR32, SPR32(SPROEA_SRR1), IMM(0), IMM(0x87c0ffff | MSR603_TGPR)); + // rolins [msr],[srr1],0,0x87c0ffff | MSR603_TGPR + UML_XOR(block, IREG(0), IREG(0), MSR32); // xor i0,i0,[msr] + UML_TEST(block, IREG(0), IMM(MSR603_TGPR)); // test i0,tgpr + UML_CALLHc(block, IF_NZ, ppc->impstate->swap_tgpr); // callh swap_tgpr,nz + } + } + else if (ppc->cap & PPCCAP_4XX) + UML_MOV(block, MSR32, SPR32(SPR4XX_SRR1)); // mov [msr],[srr1] + generate_update_mode(block); // <update mode> + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, SPR32(SPROEA_SRR0), TRUE); // <subtract cycles> + UML_HASHJMP(block, MEM(&ppc->impstate->mode), SPR32(SPROEA_SRR0), ppc->impstate->nocode); + // hashjmp mode,[srr0],nocode + return TRUE; + + case 0x033: /* RFCI */ + assert(ppc->cap & PPCCAP_4XX); + UML_MOV(block, MSR32, SPR32(SPR4XX_SRR3)); // mov [msr],[srr3] + generate_update_mode(block); // <update mode> + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, SPR32(SPR4XX_SRR2), TRUE); // <subtract cycles> + UML_HASHJMP(block, MEM(&ppc->impstate->mode), SPR32(SPR4XX_SRR2), ppc->impstate->nocode); + // hashjmp mode,[srr2],nocode + return TRUE; + + case 0x096: /* ISYNC */ + /* effective no-op */ + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_instruction_1f - compile opcodes in + the 0x1f group +-------------------------------------------------*/ + +static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = *desc->opptr.l; + UINT32 opswitch = (op >> 1) & 0x3ff; + drcuml_codelabel swloop, swloopend; + int item; + + switch (opswitch) + { + case 0x009: /* MULHDUx - 64-bit only */ + case 0x015: /* LDX - 64-bit only */ + case 0x01b: /* SLDx - 64-bit only */ + case 0x035: /* LDUX - 64-bit only */ + case 0x03a: /* CNTLZDx - 64-bit only */ + case 0x044: /* TD - 64-bit only */ + case 0x049: /* MULHDx - 64-bit only */ + case 0x054: /* LDARX - 64-bit only */ + case 0x095: /* STDX - 64-bit only */ + case 0x0b5: /* STDUX - 64-bit only */ + case 0x0d6: /* STDCX. - 64-bit only */ + case 0x0e9: /* MULLD - 64-bit only */ + case 0x2e9: /* MULLDO - 64-bit only */ + case 0x155: /* LWAX - 64-bit only */ + case 0x175: /* LWAUX - 64-bit only */ + case 0x33a: /* SRADIx - 64-bit only */ + case 0x33b: /* SRADIx - 64-bit only */ + case 0x1b2: /* SLBIE - 64-bit only */ + case 0x1c9: /* DIVDUx - 64-bit only */ + case 0x3c9: /* DIVDUOx - 64-bit only */ + case 0x1e9: /* DIVDx - 64-bit only */ + case 0x3e9: /* DIVDOx - 64-bit only */ + case 0x1f2: /* SLBIA - 64-bit only */ + case 0x21b: /* SRDx - 64-bit only */ + case 0x31a: /* SRADx - 64-bit only */ + case 0x3da: /* EXTSW - 64-bit only */ + return FALSE; + + case 0x004: /* TW */ + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb + if (G_TO(op) & 0x10) + UML_EXHc(block, IF_L, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,l + if (G_TO(op) & 0x08) + UML_EXHc(block, IF_G, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,g + if (G_TO(op) & 0x04) + UML_EXHc(block, IF_E, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,e + if (G_TO(op) & 0x02) + UML_EXHc(block, IF_B, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,b + if (G_TO(op) & 0x01) + UML_EXHc(block, IF_A, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x20000));// exh program,0x20000,a + return TRUE; + + case 0x10a: /* ADDx */ + case 0x30a: /* ADDOx */ + UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOE(op)); // add rd,ra,rb,FLAGS_RCOE(op) + generate_compute_flags(block, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); // <update flags> + return TRUE; + + case 0x00a: /* ADDCx */ + case 0x20a: /* ADDCOx */ + UML_ADDf(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOECA(op)); // add rd,ra,rb,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> + return TRUE; + + case 0x08a: /* ADDEx */ + case 0x28a: /* ADDEOx */ + UML_CARRY(block, SPR32(SPR_XER), IMM(29)); // carry [xer],XER_CA + UML_ADDCf(block, R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOECA(op));// addc rd,ra,rb,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> + return TRUE; + + case 0x0ca: /* ADDZEx */ + case 0x2ca: /* ADDZEOx */ + UML_CARRY(block, SPR32(SPR_XER), IMM(29)); // carry [xer],XER_CA + UML_ADDCf(block, R32(G_RD(op)), R32(G_RA(op)), IMM(0), FLAGS_RCOECA(op)); // addc rd,ra,0,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> + return TRUE; + + case 0x0ea: /* ADDMEx */ + case 0x2ea: /* ADDMEOx */ + UML_CARRY(block, SPR32(SPR_XER), IMM(29)); // carry [xer],XER_CA + UML_ADDCf(block, R32(G_RD(op)), R32(G_RA(op)), IMM(-1), FLAGS_RCOE(op)); // addc rd,ra,-1,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), FALSE);// <update flags> + return TRUE; + + case 0x028: /* SUBFx */ + case 0x228: /* SUBFOx */ + UML_SUBf(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op)), FLAGS_RCOE(op)); // sub rd,rb,ra,FLAGS_RCOE(op) + generate_compute_flags(block, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); // <update flags> + return TRUE; + + case 0x008: /* SUBFCx */ + case 0x208: /* SUBFCOx */ + UML_SUBf(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op)), FLAGS_RCOECA(op)); // sub rd,rb,ra,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> + return TRUE; + + case 0x088: /* SUBFEx */ + case 0x288: /* SUBFEOx */ + UML_XOR(block, IREG(0), SPR32(SPR_XER), IMM(XER_CA)); // xor i0,[xer],XER_CA + UML_CARRY(block, IREG(0), IMM(29)); // carry i0,XER_CA + UML_SUBBf(block, R32(G_RD(op)), R32(G_RB(op)), R32(G_RA(op)), FLAGS_RCOECA(op));// subc rd,rb,ra,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> + return TRUE; + + case 0x0c8: /* SUBFZEx */ + case 0x2c8: /* SUBFZEOx */ + UML_XOR(block, IREG(0), SPR32(SPR_XER), IMM(XER_CA)); // xor i0,[xer],XER_CA + UML_CARRY(block, IREG(0), IMM(29)); // carry i0,XER_CA + UML_SUBBf(block, R32(G_RD(op)), IMM(0), R32(G_RA(op)), FLAGS_RCOECA(op)); // subc rd,0,ra,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> + return TRUE; + + case 0x0e8: /* SUBFMEx */ + case 0x2e8: /* SUBFMEOx */ + UML_XOR(block, IREG(0), SPR32(SPR_XER), IMM(XER_CA)); // xor i0,[xer],XER_CA + UML_CARRY(block, IREG(0), IMM(29)); // carry i0,XER_CA + UML_SUBBf(block, R32(G_RD(op)), IMM(-1), R32(G_RA(op)), FLAGS_RCOECA(op)); // subc rd,-1,ra,,FLAGS_RCOECA(op) + generate_compute_flags(block, op & M_RC, XER_CA | ((op & M_OE) ? XER_OV : 0), TRUE);// <update flags> + return TRUE; + + case 0x068: /* NEGx */ + case 0x268: /* NEGOx */ + UML_SUBf(block, R32(G_RD(op)), IMM(0), R32(G_RA(op)), FLAGS_RCOE(op)); // sub rd,0,ra,FLAGS_RCOE(op) + generate_compute_flags(block, op & M_RC, (op & M_OE) ? XER_OV : 0, TRUE); // <update flags> + return TRUE; + + case 0x000: /* CMP */ + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb + UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C | DRCUML_FLAG_S); // getflgs i0,zcs + UML_LOAD(block, IREG(0), ppc->impstate->cmp_cr_table, IREG(0), DWORD); // load i0,cmp_cr_table,i0,dword + UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] + return TRUE; + + case 0x020: /* CMPL */ + UML_CMP(block, R32(G_RA(op)), R32(G_RB(op))); // cmp ra,rb + UML_GETFLGS(block, IREG(0), DRCUML_FLAG_Z | DRCUML_FLAG_C); // getflgs i0,zc + UML_LOAD(block, IREG(0), ppc->impstate->cmpl_cr_table, IREG(0), DWORD); // load i0,cmpl_cr_table,i0,dword + UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] + return TRUE; + + case 0x00b: /* MULHWUx */ + UML_MULUf(block, IREG(0), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); + // mulu i0,rd,ra,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x04b: /* MULHWx */ + UML_MULSf(block, IREG(0), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); + // muls i0,rd,ra,rb,,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x0eb: /* MULLWx */ + case 0x2eb: /* MULLWOx */ + if (!(op & M_OE)) + { + UML_MULSf(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); + // muls rd,rd,ra,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + } + else + { + UML_MULSf(block, IREG(0), IREG(1), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RC(op)); + // muls i0,i1,ra,rb + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 + UML_SAR(block, IREG(0), IREG(0), IMM(31)); // sar i0,i0,31 + UML_AND(block, SPR32(SPR_XER), SPR32(SPR_XER), IMM(XER_OV)); // and [xer],[xer],XER_OV + UML_XORf(block, IREG(0), IREG(0), IREG(1), FLAGS_Z); // xor i0,i0,i1,Z + UML_MOVc(block, IF_NZ, IREG(0), IMM(XER_OV | XER_SO)); // mov i0,XER_OV | XER_SO,NZ + UML_OR(block, SPR32(SPR_XER), SPR32(SPR_XER), IREG(0)); // or [xer],[xer],i0 + } + return TRUE; + + case 0x1cb: /* DIVWUx */ + case 0x3cb: /* DIVWUOx */ + UML_DIVUf(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOE(op)); + // divu rd,rd,ra,rb,FLAGS_RCOE(op) + generate_compute_flags(block, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); // <update flags> + return TRUE; + + case 0x1eb: /* DIVWx */ + case 0x3eb: /* DIVWOx */ + UML_DIVSf(block, R32(G_RD(op)), R32(G_RD(op)), R32(G_RA(op)), R32(G_RB(op)), FLAGS_RCOE(op)); + // divs rd,rd,ra,rb,FLAGS_RCOE(op) + generate_compute_flags(block, op & M_RC, ((op & M_OE) ? XER_OV : 0), FALSE); // <update flags> + return TRUE; + + case 0x01c: /* ANDx */ + UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // and ra,rs,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x03c: /* ANDCx */ + UML_XOR(block, IREG(0), R32(G_RB(op)), IMM(~0)); // xor i0,rb,~0 + UML_ANDf(block, R32(G_RA(op)), R32(G_RS(op)), IREG(0), FLAGS_RC(op)); // and ra,rs,i0,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x1dc: /* NANDx */ + UML_AND(block, IREG(0), R32(G_RS(op)), R32(G_RB(op))); // and i0,rs,rb + UML_XORf(block, R32(G_RA(op)), IREG(0), IMM(~0), FLAGS_RC(op)); // xor ra,i0,~0,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x1bc: /* ORx */ + UML_ORf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // or ra,rs,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x19c: /* ORCx */ + UML_XORf(block, IREG(0), R32(G_RB(op)), IMM(~0), FLAGS_RC(op)); // xor i0,rb,~0,FLAGS_RC(op) + UML_OR(block, R32(G_RA(op)), R32(G_RS(op)), IREG(0)); // or ra,rs,i0 + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x07c: /* NORx */ + UML_OR(block, IREG(0), R32(G_RS(op)), R32(G_RB(op))); // or i0,rs,rb + UML_XORf(block, R32(G_RA(op)), IREG(0), IMM(~0), FLAGS_RC(op)); // xor ra,i0,~0,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x13c: /* XORx */ + UML_XORf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // xor ra,rs,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x11c: /* EQVx */ + UML_XOR(block, IREG(0), R32(G_RS(op)), R32(G_RB(op))); // xor i0,rs,rb + UML_XORf(block, R32(G_RA(op)), IREG(0), IMM(~0), FLAGS_RC(op)); // xor ra,i0,~0,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x018: /* SLWx */ + UML_SHL(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op))); // shl ra,rs,rb + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x218: /* SRWx */ + UML_SHRf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // shr ra,rs,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x318: /* SRAWx */ + UML_SHL(block, IREG(1), IMM(0xffffffff), R32(G_RB(op))); // shl i1,0xffffffff,rb + UML_XOR(block, IREG(1), IREG(1), IMM(~0)); // xor i1,i1,~0 + UML_AND(block, IREG(0), R32(G_RS(op)), IREG(1)); // and i0,rs,i1 + UML_SAR(block, IREG(1), R32(G_RS(op)), IMM(31)); // sar i1,rs,31 + UML_ANDf(block, IREG(0), IREG(0), IREG(1), DRCUML_FLAG_Z); // and i0,i0,i1,z + UML_SETc(block, IF_NZ, IREG(0)); // set i0,nz + UML_ROLINS(block, SPR32(SPR_XER), IREG(0), IMM(29), IMM(XER_CA)); // rolins [xer],i0,29,XER_CA + UML_SARf(block, R32(G_RA(op)), R32(G_RS(op)), R32(G_RB(op)), FLAGS_RC(op)); // sar ra,rs,rb,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x338: /* SRAWIx */ + UML_AND(block, IREG(0), R32(G_RS(op)), IMM(~(0xffffffff << (G_SH(op) & 31)))); // and i0,rs,~(0xffffffff << (sh & 31)) + UML_SAR(block, IREG(1), R32(G_RS(op)), IMM(31)); // sar i1,rs,31 + UML_ANDf(block, IREG(0), IREG(0), IREG(1), DRCUML_FLAG_Z); // and i0,i0,i1,z + UML_SETc(block, IF_NZ, IREG(0)); // set i0,nz + UML_ROLINS(block, SPR32(SPR_XER), IREG(0), IMM(29), IMM(XER_CA)); // rolins [xer],i0,29,XER_CA + UML_SARf(block, R32(G_RA(op)), R32(G_RS(op)), IMM(G_SH(op)), FLAGS_RC(op)); // sar ra,rs,sh,FLAGS_RC(op) + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + return TRUE; + + case 0x01a: /* CNTLZWx */ + UML_LZCNT(block, R32(G_RA(op)), R32(G_RS(op))); // lzcnt ra,rs,rb + if (op & M_RC) + { + UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + } + return TRUE; + + case 0x3ba: /* EXTSBx */ + UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), BYTE); // sext ra,rs,byte + if (op & M_RC) + { + UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + } + return TRUE; + + case 0x39a: /* EXTSHx */ + UML_SEXT(block, R32(G_RA(op)), R32(G_RS(op)), WORD); // sext ra,rs,word + if (op & M_RC) + { + UML_TEST(block, R32(G_RA(op)), IMM(~0)); // test ra,~0 + generate_compute_flags(block, op & M_RC, 0, FALSE); // <update flags> + } + return TRUE; + + case 0x057: /* LBZX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x117: /* LHZX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x157: /* LHAX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x017: /* LWZX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x217: /* LFSX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x257: /* LFDX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 + UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x316: /* LHBRX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_BSWAP(block, IREG(0), IREG(0)); // bswap i0,i0 + UML_SHR(block, R32(G_RD(op)), IREG(0), IMM(16)); // shr rd,i0,16 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x216: /* LWBRX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align + UML_BSWAP(block, R32(G_RD(op)), IREG(0)); // bswap rd,i0 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x077: /* LBZUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x137: /* LHZUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x177: /* LHAUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16 + UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x037: /* LWZUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x237: /* LFSUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32 + UML_MOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // mov [tempdata],i0 + UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata), DWORD); // fdfrflt fd,[tempdata],dword + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x277: /* LFDUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64 + UML_DMOV(block, MEM(&ppc->impstate->tempdata), IREG(0)); // dmov [tempdata],i0 + UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmov fd,[tempdata] + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x014: /* LWARX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align + UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x255: /* LSWI */ + UML_MOV(block, MEM(&ppc->impstate->swcount), IMM(((G_NB(op) - 1) & 0x1f) + 1)); // mov [swcount],[xer],G_NB + UML_MOV(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra + UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RD(op))); // mov [swreg],4*G_RD(op) + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + save_fast_iregs(block); // <save fastregs> + UML_LABEL(block, swloop = compiler->labelnum++); // swloop: + UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] + UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 + UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 + UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] + UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 + UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f + UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) + UML_STORE(block, &ppc->r[0], IREG(1), IREG(0), BYTE); // store &r0,i1,i0,byte + UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); + // sub [swcount],[swcount],1,Z + UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ + load_fast_iregs(block); // <load fastregs> + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x215: /* LSWX */ + UML_ANDf(block, FLAGS_Z, MEM(&ppc->impstate->swcount), SPR32(SPR_XER), IMM(0x7f));// and [swcount],[xer],0x7f,Z + UML_JMPc(block, IF_Z, swloopend = compiler->labelnum++); // jmp swloopend,Z + UML_ADD(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb + UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RD(op))); // mov [swreg],4*G_RD(op) + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + save_fast_iregs(block); // <save fastregs> + UML_LABEL(block, swloop = compiler->labelnum++); // swloop: + UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] + UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 + UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8 + UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] + UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 + UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f + UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) + UML_STORE(block, &ppc->r[0], IREG(1), IREG(0), BYTE); // store &r0,i1,i0,byte + UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); + // sub [swcount],[swcount],1,Z + UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ + UML_LABEL(block, swloopend); // swloopend: + load_fast_iregs(block); // <load fastregs> + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x136: /* ECIWX */ + /* not implemented */ + return FALSE; + + case 0x0d7: /* STBX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x197: /* STHX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x097: /* STWX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x297: /* STFSX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x3d7: /* STFIWX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs + UML_MOV(block, IREG(1), MEM((UINT32 *)&ppc->impstate->tempdata + BYTE_XOR_LE(0)));// mov i1,[tempdata.lo] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2d7: /* STFDX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x396: /* STHBRX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_BSWAP(block, IREG(1), R32(G_RS(op))); // bswap i1,rs + UML_SHR(block, IREG(1), IREG(1), IMM(16)); // shr i1,i1,16 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x296: /* STWBRX */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_BSWAP(block, IREG(1), R32(G_RS(op))); // bswap i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x0f7: /* STBUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x1b7: /* STHUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x0b7: /* STWUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2b7: /* STFSUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword + UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // mov i1,[tempdata] + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2f7: /* STFDUX */ + UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_FDMOV(block, MEM(&ppc->impstate->tempdata), F64(G_RS(op))); // fdmov [tempdata],rs + UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata)); // dmov i1,[tempdata] + UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0 + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 + UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr] + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x096: /* STWCX. */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode & 3]); // callh write32align + UML_AND(block, IREG(0), CR32, IMM(~CRMASK(0))); // and i0,cr,~crmask(0) + UML_ROLINS(block, IREG(0), SPR32(SPR_XER), IMM(29), IMM(0x10000000)); // rolins i0,[xer],29,0x10000000 + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x2d5: /* STSWI */ + UML_MOV(block, MEM(&ppc->impstate->swcount), IMM(((G_NB(op) - 1) & 0x1f) + 1)); // mov [swcount],[xer],G_NB + UML_MOV(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra + UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RS(op))); // mov [swreg],4*G_RS(op) + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + save_fast_iregs(block); // <save fastregs> + UML_LABEL(block, swloop = compiler->labelnum++); // swloop: + UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] + UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 + UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] + UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 + UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f + UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) + UML_LOAD(block, IREG(1), &ppc->r[0], IREG(1), BYTE); // load i1,&r0,i1,byte + UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 + UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); + // sub [swcount],[swcount],1,Z + UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x295: /* STSWX */ + UML_ANDf(block, FLAGS_Z, MEM(&ppc->impstate->swcount), SPR32(SPR_XER), IMM(0x7f));// and [swcount],[xer],0x7f,Z + UML_JMPc(block, IF_Z, swloopend = compiler->labelnum++); // jmp swloopend,Z + UML_ADD(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb + UML_MOV(block, MEM(&ppc->impstate->swreg), IMM(4 * G_RS(op))); // mov [swreg],4*G_RS(op) + UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op) + save_fast_iregs(block); // <save fastregs> + UML_LABEL(block, swloop = compiler->labelnum++); // swloop: + UML_MOV(block, IREG(0), MEM(&ppc->impstate->updateaddr)); // mov i0,[updateaddr] + UML_ADD(block, MEM(&ppc->impstate->updateaddr), IREG(0), IMM(1)); // add [updateaddr],i0,1 + UML_MOV(block, IREG(1), MEM(&ppc->impstate->swreg)); // mov i1,[swreg] + UML_ADD(block, IREG(2), IREG(1), IMM(1)); // add i2,i1,1 + UML_AND(block, MEM(&ppc->impstate->swreg), IREG(2), IMM(0x7f)); // and [swreg],i2,0x7f + UML_XOR(block, IREG(1), IREG(1), IMM(BYTE4_XOR_BE(0))); // xor i1,i1,be_xor(0) + UML_LOAD(block, IREG(1), &ppc->r[0], IREG(1), BYTE); // load i1,&r0,i1,byte + UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8 + UML_SUBf(block, MEM(&ppc->impstate->swcount), MEM(&ppc->impstate->swcount), IMM(1), FLAGS_Z); + // sub [swcount],[swcount],1,Z + UML_JMPc(block, IF_NZ, swloop); // jmp swloop,NZ + UML_LABEL(block, swloopend); // swloopend: + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x1b6: /* ECOWX */ + /* not implemented */ + return FALSE; + + case 0x036: /* DCBST */ + case 0x056: /* DCBF */ + case 0x0f6: /* DCBTST */ + case 0x116: /* DCBT */ + case 0x3d6: /* ICBI */ + case 0x256: /* SYNC */ + case 0x356: /* EIEIO */ + case 0x1d6: /* DCBI */ + case 0x236: /* TLBSYNC */ + /* effective no-ops */ + return TRUE; + + case 0x3f6: /* DCBZ */ + UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb + UML_AND(block, MEM(&ppc->impstate->tempaddr), IREG(0), IMM(~(ppc->cache_line_size - 1))); + // and [tempaddr],i0,~(cache_line_size - 1) + for (item = 0; item < ppc->cache_line_size / 8; item++) + { + UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(8 * item)); // add i0,[tempaddr],8*item + UML_DMOV(block, IREG(1), IMM(0)); // dmov i1,0 + UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64 + } + return TRUE; + + case 0x132: /* TLBIE */ + UML_MOV(block, MEM(&ppc->param0), R32(G_RB(op))); // mov [param0],rb + UML_CALLC(block, ppccom_execute_tlbie, ppc); // callc ppccom_execute_tlbie,ppc + return TRUE; + + case 0x172: /* TLBIA */ + UML_CALLC(block, ppccom_execute_tlbia, ppc); // callc ppccom_execute_tlbia,ppc + return TRUE; + + case 0x3d2: /* TLBLD */ + assert(ppc->cap & PPCCAP_603_MMU); + UML_MOV(block, MEM(&ppc->param0), R32(G_RB(op))); // mov [param0],rb + UML_MOV(block, MEM(&ppc->param1), IMM(0)); // mov [param1],0 + UML_CALLC(block, ppccom_execute_tlbl, ppc); // callc ppccom_execute_tlbl,ppc + return TRUE; + + case 0x3f2: /* TLBLI */ + assert(ppc->cap & PPCCAP_603_MMU); + UML_MOV(block, MEM(&ppc->param0), R32(G_RB(op))); // mov [param0],rb + UML_MOV(block, MEM(&ppc->param1), IMM(1)); // mov [param1],1 + UML_CALLC(block, ppccom_execute_tlbl, ppc); // callc ppccom_execute_tlbl,ppc + return TRUE; + + case 0x013: /* MFCR */ + UML_MOV(block, R32(G_RD(op)), CR32); // mov rd,cr + return TRUE; + + case 0x053: /* MFMSR */ + UML_MOV(block, R32(G_RD(op)), MSR32); // mov rd,msr + return TRUE; + + case 0x153: /* MFSPR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + if (spr == SPR_LR || spr == SPR_CTR || spr == SPR_XER || (spr >= SPROEA_SPRG0 && spr <= SPROEA_SPRG3)) + UML_MOV(block, R32(G_RD(op)), SPR32(spr)); // mov rd,spr + else if (spr == SPROEA_PVR) + UML_MOV(block, R32(G_RD(op)), IMM(ppc->flavor)); // mov rd,flavor + else + { + generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> + UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr + UML_CALLC(block, ppccom_execute_mfspr, ppc); // callc ppccom_execute_mfspr,ppc + UML_MOV(block, R32(G_RD(op)), MEM(&ppc->param1)); // mov rd,[param1] + } + return TRUE; + } + + case 0x253: /* MFSR */ + UML_MOV(block, R32(G_RD(op)), SR32(G_SR(op))); // mov rd,sr + return TRUE; + + case 0x293: /* MFSRIN */ + UML_SHR(block, IREG(0), R32(G_RB(op)), IMM(28)); // shr i0,G_RB,28 + UML_LOAD(block, R32(G_RD(op)), &ppc->sr[0], IREG(0), DWORD); // load rd,sr,i0,dword + return TRUE; + + case 0x173: /* MFTB */ + { + UINT32 tbr = compute_spr(G_SPR(op)); + if (tbr != SPRVEA_TBL_R && tbr != SPRVEA_TBU_R) + return FALSE; + generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> + UML_MOV(block, MEM(&ppc->param0), IMM(tbr)); // mov [param0],tbr + UML_CALLC(block, ppccom_execute_mftb, ppc); // callc ppccom_execute_mftb,ppc + UML_MOV(block, R32(G_RD(op)), MEM(&ppc->param1)); // mov rd,[param1] + return TRUE; + } + + case 0x090: /* MTCRF */ + UML_ROLINS(block, CR32, R32(G_RS(op)), IMM(0), IMM(compute_crf_mask(G_CRM(op))));// rolins cr,rs,0,G_CRM + return TRUE; + + case 0x092: /* MTMSR */ + if (ppc->cap & PPCCAP_603_MMU) + UML_XOR(block, IREG(0), MSR32, R32(G_RS(op))); // xor i0,msr32,rs + UML_MOV(block, MSR32, R32(G_RS(op))); // mov msr,rs + if (ppc->cap & PPCCAP_603_MMU) + { + UML_TEST(block, IREG(0), IMM(MSR603_TGPR)); // test i0,tgpr + UML_CALLHc(block, IF_NZ, ppc->impstate->swap_tgpr); // callh swap_tgpr,nz + } + generate_update_mode(block); // <update mode> + return TRUE; + + case 0x1d3: /* MTSPR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + if (spr == SPR_LR || spr == SPR_CTR || spr == SPR_XER || (spr >= SPROEA_SPRG0 && spr <= SPROEA_SPRG3)) + UML_MOV(block, SPR32(spr), R32(G_RS(op))); // mov spr,rs + else if (spr == SPROEA_PVR) + ; // read only + else + { + generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> + UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr + UML_MOV(block, MEM(&ppc->param1), R32(G_RS(op))); // mov [param1],rs + UML_CALLC(block, ppccom_execute_mtspr, ppc); // callc ppccom_execute_mtspr,ppc + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + } + return TRUE; + } + + case 0x0d2: /* MTSR */ + UML_MOV(block, SR32(G_SR(op)), R32(G_RS(op))); // mov sr[G_SR],rs + UML_CALLC(block, ppccom_tlb_flush, ppc); // callc ppccom_tlb_flush,ppc + return TRUE; + + case 0x0f2: /* MTSRIN */ + UML_SHR(block, IREG(0), R32(G_RB(op)), IMM(28)); // shr i0,G_RB,28 + UML_STORE(block, &ppc->sr[0], IREG(0), R32(G_RS(op)), DWORD); // store sr,i0,rs,dword + UML_CALLC(block, ppccom_tlb_flush, ppc); // callc ppccom_tlb_flush,ppc + return TRUE; + + case 0x200: /* MCRXR */ + UML_ROLINS(block, CR32, SPR32(SPR_XER), IMM(32 - 4 * G_CRFD(op)), IMM(CRMASK(G_CRFD(op)))); + // rolins cr,[xer],32-4*crfd,crmask(crfd) + UML_AND(block, SPR32(SPR_XER), SPR32(SPR_XER), IMM(~0xf0000000)); // and [xer],[xer],~0xf0000000 + return TRUE; + + case 0x106: /* ICBT */ + case 0x1c6: /* DCCCI */ + case 0x3c6: /* ICCCI */ + assert(ppc->cap & PPCCAP_4XX); + /* effective no-nop */ + return TRUE; + + case 0x1e6: /* DCREAD */ + case 0x3e6: /* ICREAD */ + assert(ppc->cap & PPCCAP_4XX); + UML_MOV(block, R32(G_RT(op)), IMM(0)); // mov rt,0 + return TRUE; + + case 0x143: /* MFDCR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + assert(ppc->cap & PPCCAP_4XX); + generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> + UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr + UML_CALLC(block, ppccom_execute_mfdcr, ppc); // callc ppccom_execute_mfdcr,ppc + UML_MOV(block, R32(G_RD(op)), MEM(&ppc->param1)); // mov rd,[param1] + return TRUE; + } + + case 0x1c3: /* MTDCR */ + { + UINT32 spr = compute_spr(G_SPR(op)); + assert(ppc->cap & PPCCAP_4XX); + generate_update_cycles(block, compiler, IMM(desc->pc), TRUE); // <update cycles> + UML_MOV(block, MEM(&ppc->param0), IMM(spr)); // mov [param0],spr + UML_MOV(block, MEM(&ppc->param1), R32(G_RS(op))); // mov [param1],rs + UML_CALLC(block, ppccom_execute_mtdcr, ppc); // callc ppccom_execute_mtdcr,ppc + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + } + + case 0x083: /* WRTEE */ + assert(ppc->cap & PPCCAP_4XX); + UML_ROLINS(block, MSR32, R32(G_RS(op)), IMM(0), IMM(MSR_EE)); // rolins msr,rs,0,MSR_EE + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + return TRUE; + + case 0x0a3: /* WRTEEI */ + assert(ppc->cap & PPCCAP_4XX); + if (op & MSR_EE) + { + UML_OR(block, MSR32, MSR32, IMM(MSR_EE)); // or msr,msr,MSR_EE + compiler->checkints = TRUE; + generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles> + } + else + UML_AND(block, MSR32, MSR32, IMM(~MSR_EE)); // and msr,msr,~MSR_EE + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + generate_instruction_3b - compile opcodes in + the 0x3b group +-------------------------------------------------*/ + +static int generate_instruction_3b(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = *desc->opptr.l; + UINT32 opswitch = (op >> 1) & 0x1f; + + switch (opswitch) + { + case 0x15: /* FADDSx */ + UML_FDADD(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdadd f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x14: /* FSUBSx */ + UML_FDSUB(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdsub f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x19: /* FMULSx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fdmul f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x12: /* FDIVSx */ + UML_FDDIV(block, FREG(0), F64(G_RA(op)), F64(G_RB(op))); // fddiv f0,ra,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x16: /* FSQRTSx */ + UML_FDSQRT(block, FREG(0), F64(G_RB(op))); // fdsqrt f0,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x18: /* FRESx */ + UML_FSFRFLT(block, FREG(0), F64(G_RB(op)), QWORD); // fsfrlt f0,rb,qword + UML_FSRECIP(block, FREG(0), FREG(0)); // fsrecip f0,f0 + UML_FDFRFLT(block, F64(G_RD(op)), FREG(0), DWORD); // fdfrflt rd,f0,dword + return TRUE; + + case 0x1d: /* FMADDSx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x1c: /* FMSUBSx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, FREG(0), FREG(0), F64(G_RB(op))); // fdsub f0,f0,rb + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x1f: /* FNMADDSx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb + UML_FDNEG(block, FREG(0), FREG(0)); // fdneg f0,f0 + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + + case 0x1e: /* FNMSUBSx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, FREG(0), F64(G_RB(op)), FREG(0)); // fdsub f0,rb,f0 + UML_FDRNDS(block, F64(G_RD(op)), FREG(0)); // fdrnds rd,f0 + return TRUE; + } + + return FALSE; +} + + + +/*------------------------------------------------- + generate_instruction_3f - compile opcodes in + the 0x3f group +-------------------------------------------------*/ + +static int generate_instruction_3f(drcuml_block *block, compiler_state *compiler, const opcode_desc *desc) +{ + UINT32 op = *desc->opptr.l; + UINT32 opswitch = (op >> 1) & 0x3ff; + + if (opswitch & 0x10) + { + opswitch &= 0x1f; + switch (opswitch) + { + case 0x15: /* FADDx */ + UML_FDADD(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdadd rd,ra,rb + return TRUE; + + case 0x14: /* FSUBx */ + UML_FDSUB(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdsub rd,ra,rb + return TRUE; + + case 0x19: /* FMULx */ + UML_FDMUL(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fdmul rd,ra,rb + return TRUE; + + case 0x12: /* FDIVx */ + UML_FDDIV(block, F64(G_RD(op)), F64(G_RA(op)), F64(G_RB(op))); // fddiv rd,ra,rb + return TRUE; + + case 0x16: /* FSQRTx */ + UML_FDSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdsqrt rd,rb + return TRUE; + + case 0x1a: /* FRSQRTEx */ + UML_FDRSQRT(block, F64(G_RD(op)), F64(G_RB(op))); // fdrsqrt rd,rb + return TRUE; + + case 0x17: /* FSELx */ + UML_FDCMP(block, F64(G_RA(op)), MEM(&ppc->impstate->fp0)); // fdcmp f0,ra,[fp0] + UML_FDMOVc(block, IF_AE, F64(G_RD(op)), F64(G_REGC(op))); // fdmov rd,rc,AE + UML_FDMOVc(block, IF_B, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb,B + return TRUE; + + case 0x1d: /* FMADDx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, F64(G_RD(op)), FREG(0), F64(G_RB(op))); // fdadd rd,f0,rb + return TRUE; + + case 0x1f: /* FNMADDx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDADD(block, FREG(0), FREG(0), F64(G_RB(op))); // fdadd f0,f0,rb + UML_FDNEG(block, F64(G_RD(op)), FREG(0)); // fdneg rd,f0 + return TRUE; + + case 0x1c: /* FMSUBx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, F64(G_RD(op)), FREG(0), F64(G_RB(op))); // fdsub rd,f0,rb + return TRUE; + + case 0x1e: /* FNMSUBx */ + UML_FDMUL(block, FREG(0), F64(G_RA(op)), F64(G_REGC(op))); // fdmul f0,ra,rc + UML_FDSUB(block, F64(G_RD(op)), F64(G_RB(op)), FREG(0)); // fdsub rd,rb,f0 + return TRUE; + } + } + else + { + switch (opswitch) + { + case 0x32e: /* FCTIDx - 64-bit only */ + case 0x32f: /* FCTIDZx - 64-bit only */ + case 0x34e: /* FCFIDx - 64-bit only */ + return FALSE; + + case 0x000: /* FCMPU */ + case 0x020: /* FCMPO */ + UML_FDCMP(block, F64(G_RA(op)), F64(G_RB(op))); // fdcmp ra,rb + UML_GETFLGS(block, IREG(0), DRCUML_FLAG_C | DRCUML_FLAG_Z | DRCUML_FLAG_U); // getflgs i0,czu + UML_LOAD(block, IREG(0), ppc->impstate->fcmp_cr_table, IREG(0), DWORD); // load i0,fcmp_cr_table,i0,dword + UML_ROLINS(block, CR32, IREG(0), IMM(0), IMM(CRMASK(G_CRFD(op)))); // rolins cr,i0,0,crmask[cr] + return TRUE; + + case 0x00c: /* FRSPx */ + UML_FDRNDS(block, F64(G_RD(op)), F64(G_RB(op))); // fdrnds rd,rb + return TRUE; + + case 0x00e: /* FCTIWx */ + UML_FDTOINT(block, IREG(0), F64(G_RB(op)), DWORD, DEFAULT); // fdtoint i0,rb,dword,default + UML_DAND(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(0xffffffff)); // dand i0,i0,0xffffffff + UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmovr rd,i0 + return TRUE; + + case 0x00f: /* FCTIWZx */ + UML_FDTOINT(block, IREG(0), F64(G_RB(op)), DWORD, TRUNC); // fdtoint i0,rb,dword,default + UML_DAND(block, MEM(&ppc->impstate->tempdata), IREG(0), IMM(0xffffffff)); // dand i0,i0,0xffffffff + UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata)); // fdmovr rd,i0 + return TRUE; + + case 0x028: /* FNEGx */ + UML_FDNEG(block, F64(G_RD(op)), F64(G_RB(op))); // fdneg rd,rb + return TRUE; + + case 0x048: /* FMRx */ + UML_FDMOV(block, F64(G_RD(op)), F64(G_RB(op))); // fdmov rd,rb + return TRUE; + + case 0x088: /* FNABSx */ + UML_FDABS(block, FREG(0), F64(G_RB(op))); // fdabs f0,rb + UML_FDNEG(block, F64(G_RD(op)), FREG(0)); // fdneg rd,f0 + return TRUE; + + case 0x108: /* FABSx */ + UML_FDABS(block, F64(G_RD(op)), F64(G_RB(op))); // fdabs rd,rb + return TRUE; + + case 0x046: /* MTFSB0x */ + UML_AND(block, FPSCR32, FPSCR32, IMM(~(0x80000000 >> G_CRBD(op)))); // and fpscr32,fpscr32,~(0x80000000 >> G_CRBD) + return TRUE; + + case 0x026: /* MTFSB1x */ + UML_OR(block, FPSCR32, FPSCR32, IMM(0x80000000 >> G_CRBD(op))); // or fpscr32,fpscr32,(0x80000000 >> G_CRBD) + return TRUE; + + case 0x040: /* MCRFS */ + UML_ROLINS(block, CR32, FPSCR32, IMM(((G_CRFS(op) - G_CRFD(op)) & 7) * 4), IMM(CRMASK(G_CRFD(op)))); + // rolins cr,fpscr,shift,crmask[crfd] + UML_AND(block, FPSCR32, FPSCR32, IMM(~CRMASK(G_CRFS(op)))); // and fpscr,fpscr,~crmask[crfs] + return TRUE; + + case 0x247: /* MFFSx */ + UML_MOV(block, R32(G_RD(op)), FPSCR32); // mov rd,fpscr + return TRUE; + + case 0x2c7: /* MTFSFx */ + UML_ROLINS(block, FPSCR32, R32(G_RB(op)), IMM(0), IMM(compute_crf_mask(G_FM(op)))); + // rolins fpscr,rb,0,crf_mask + return TRUE; + + case 0x086: /* MTFSFIx */ + UML_ROLINS(block, FPSCR32, R32(G_IMM(op)), IMM(28 - 4 * G_CRFD(op)), IMM(CRMASK(G_CRFD(op)))); + // rolins fpscr,rb,0,crf_mask + return TRUE; + } + } + + return FALSE; +} + + + +/*************************************************************************** + CODE LOGGING HELPERS +***************************************************************************/ + +/*------------------------------------------------- + log_add_disasm_comment - add a comment + including disassembly of a PowerPC instruction +-------------------------------------------------*/ + +static void log_add_disasm_comment(drcuml_block *block, UINT32 pc, UINT32 op) +{ +#if (LOG_UML) + char buffer[100]; + ppc_dasm_one(buffer, pc, op); + UML_COMMENT(block, "%08X: %s", pc, buffer); // comment +#endif +} + + +/*------------------------------------------------- + log_desc_flags_to_string - generate a string + representing the instruction description + flags +-------------------------------------------------*/ + +static const char *log_desc_flags_to_string(UINT32 flags) +{ + static char tempbuf[30]; + char *dest = tempbuf; + + /* branches */ + if (flags & OPFLAG_IS_UNCONDITIONAL_BRANCH) + *dest++ = 'U'; + else if (flags & OPFLAG_IS_CONDITIONAL_BRANCH) + *dest++ = 'C'; + else + *dest++ = '.'; + + /* intrablock branches */ + *dest++ = (flags & OPFLAG_INTRABLOCK_BRANCH) ? 'i' : '.'; + + /* branch targets */ + *dest++ = (flags & OPFLAG_IS_BRANCH_TARGET) ? 'B' : '.'; + + /* delay slots */ + *dest++ = (flags & OPFLAG_IN_DELAY_SLOT) ? 'D' : '.'; + + /* exceptions */ + if (flags & OPFLAG_WILL_CAUSE_EXCEPTION) + *dest++ = 'E'; + else if (flags & OPFLAG_CAN_CAUSE_EXCEPTION) + *dest++ = 'e'; + else + *dest++ = '.'; + + /* read/write */ + if (flags & OPFLAG_READS_MEMORY) + *dest++ = 'R'; + else if (flags & OPFLAG_WRITES_MEMORY) + *dest++ = 'W'; + else + *dest++ = '.'; + + /* TLB validation */ + *dest++ = (flags & OPFLAG_VALIDATE_TLB) ? 'V' : '.'; + + /* TLB modification */ + *dest++ = (flags & OPFLAG_MODIFIES_TRANSLATION) ? 'T' : '.'; + + /* redispatch */ + *dest++ = (flags & OPFLAG_REDISPATCH) ? 'R' : '.'; + return tempbuf; +} + + +/*------------------------------------------------- + log_register_list - log a list of GPR registers +-------------------------------------------------*/ + +static void log_register_list(drcuml_state *drcuml, const char *string, UINT64 gprmask, UINT64 fprmask) +{ + int count = 0; + int regnum; + + /* skip if nothing */ + if ((gprmask & ~1) == 0 && fprmask == 0) + return; + + drcuml_log_printf(drcuml, "[%s:", string); + + for (regnum = 0; regnum < 32; regnum++) + if (gprmask & ((UINT64)1 << regnum)) + drcuml_log_printf(drcuml, "%sr%d", (count++ == 0) ? "" : ",", regnum); + for (regnum = 0; regnum < 8; regnum++) + if (gprmask & ((UINT64)1 << (32 + regnum))) + drcuml_log_printf(drcuml, "%scr%d", (count++ == 0) ? "" : ",", regnum); + if (gprmask & ((UINT64)1 << 40)) + drcuml_log_printf(drcuml, "%sxer", (count++ == 0) ? "" : ","); + if (gprmask & ((UINT64)1 << 41)) + drcuml_log_printf(drcuml, "%sctr", (count++ == 0) ? "" : ","); + if (gprmask & ((UINT64)1 << 42)) + drcuml_log_printf(drcuml, "%slr", (count++ == 0) ? "" : ","); + + for (regnum = 0; regnum < 32; regnum++) + if (fprmask & ((UINT64)1 << regnum)) + drcuml_log_printf(drcuml, "%sfpr%d", (count++ == 0) ? "" : ",", regnum); + if (fprmask & ((UINT64)1 << 32)) + drcuml_log_printf(drcuml, "%sfpscr", (count++ == 0) ? "" : ","); + drcuml_log_printf(drcuml, "] "); +} + + +/*------------------------------------------------- + log_opcode_desc - log a list of descriptions +-------------------------------------------------*/ + +static void log_opcode_desc(drcuml_state *drcuml, const opcode_desc *desclist, int indent) +{ + /* open the file, creating it if necessary */ + if (indent == 0) + drcuml_log_printf(drcuml, "\nDescriptor list @ %08X\n", desclist->pc); + + /* output each descriptor */ + for ( ; desclist != NULL; desclist = desclist->next) + { + char buffer[100]; + + /* disassemle the current instruction and output it to the log */ +#if (LOG_UML || LOG_NATIVE) + if (desclist->flags & OPFLAG_VIRTUAL_NOOP) + strcpy(buffer, "<virtual nop>"); + else + ppc_dasm_one(buffer, desclist->pc, *desclist->opptr.l); +#else + strcpy(buffer, "???"); +#endif + 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(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(drcuml, desclist->delay, indent + 1); + + /* at the end of a sequence add a dividing line */ + if (desclist->flags & OPFLAG_END_SEQUENCE) + drcuml_log_printf(drcuml, "-----\n"); + } +} + + + +/*************************************************************************** + PPC 4XX VARIANTS +***************************************************************************/ + +#if (HAS_PPC403GA || HAS_PPC403GCX) + +/*------------------------------------------------- + ppcdrc4xx_get_info - PowerPC 4XX-specific + information getter +-------------------------------------------------*/ + +static void ppcdrc4xx_get_info(UINT32 state, cpuinfo *info) +{ + ppcdrc_get_info(state, info); + ppc4xx_get_info(ppc, state, info); +} + + +/*------------------------------------------------- + ppcdrc4xx_set_info - PowerPC 4XX-specific + information setter +-------------------------------------------------*/ + +static void ppcdrc4xx_set_info(UINT32 state, cpuinfo *info) +{ + ppcdrc_set_info(state, info); + ppc4xx_set_info(ppc, state, info); +} + +#endif + + +#if (HAS_PPC403GA) + +/*------------------------------------------------- + ppc403ga_init - PowerPC 403GA-specific + initialization +-------------------------------------------------*/ + +static void ppc403ga_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_403GA, PPCCAP_4XX, 1, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc403ga_get_info - PowerPC 403GA-specific + information getter +-------------------------------------------------*/ + +void ppc403ga_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc403ga_init; break; + case CPUINFO_PTR_SET_INFO: info->setinfo = ppcdrc4xx_set_info; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 403GA"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc4xx_get_info(state, info); break; + } +} + +#endif + + +#if (HAS_PPC403GCX) + +/*------------------------------------------------- + ppc403gcx_init - PowerPC 403GCX-specific + initialization +-------------------------------------------------*/ + +static void ppc403gcx_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_403GCX, PPCCAP_4XX, 1, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc403gcx_get_info - PowerPC 403GCX-specific + information getter +-------------------------------------------------*/ + +void ppc403gcx_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc403gcx_init; break; + case CPUINFO_PTR_SET_INFO: info->setinfo = ppcdrc4xx_set_info; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 403GCX"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc4xx_get_info(state, info); break; + } +} + +#endif + + + +/*************************************************************************** + PPC 6XX VARIANTS +***************************************************************************/ + +#if (HAS_PPC601) + +/*------------------------------------------------- + ppc601_init - PowerPC 601-specific + initialization +-------------------------------------------------*/ + +static void ppc601_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_601, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 0/* no TB */, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc601_get_info - PowerPC 601-specific + information getter +-------------------------------------------------*/ + +void ppc601_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc601_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 601"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + +#if (HAS_PPC602) + +/*------------------------------------------------- + ppc602_init - PowerPC 602-specific + initialization +-------------------------------------------------*/ + +static void ppc602_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_602, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 1/* unknown */, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc602_get_info - PowerPC 602-specific + information getter +-------------------------------------------------*/ + +void ppc602_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc602_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 602"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + +#if (HAS_PPC603) + +/*------------------------------------------------- + ppc603_init - PowerPC 603-specific + initialization +-------------------------------------------------*/ + +static void ppc603_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_603, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc603_get_info - PowerPC 603-specific + information getter +-------------------------------------------------*/ + +void ppc603_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc603_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + +#if (HAS_PPC603E) + +/*------------------------------------------------- + ppc603e_init - PowerPC 603e-specific + initialization +-------------------------------------------------*/ + +static void ppc603e_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_603E, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc603e_get_info - PowerPC 603e-specific + information getter +-------------------------------------------------*/ + +void ppc603e_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc603e_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603e"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + +#if (HAS_PPC603R) + +/*------------------------------------------------- + ppc603r_init - PowerPC 603r-specific + initialization +-------------------------------------------------*/ + +static void ppc603r_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_603R, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED | PPCCAP_603_MMU, 4, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc603r_get_info - PowerPC 603r-specific + information getter +-------------------------------------------------*/ + +void ppc603r_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc603r_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 603R"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + +#if (HAS_PPC604) + +/*------------------------------------------------- + ppc604_init - PowerPC 604-specific + initialization +-------------------------------------------------*/ + +static void ppc604_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_604, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 4, clock, config, irqcallback); +} + + +/*------------------------------------------------- + ppc604_get_info - PowerPC 604-specific + information getter +-------------------------------------------------*/ + +void ppc604_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = ppc604_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC 604"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + + +/*************************************************************************** + PPC 6XX VARIANTS +***************************************************************************/ + +#if (HAS_MPC8240) + +/*------------------------------------------------- + mpc8240_init - PowerPC MPC8240-specific + initialization +-------------------------------------------------*/ + +static void mpc8240_init(int index, int clock, const void *config, int (*irqcallback)(int)) +{ + ppcdrc_init(PPC_MODEL_MPC8240, PPCCAP_OEA | PPCCAP_VEA | PPCCAP_FPU | PPCCAP_MISALIGNED, 4/* unknown */, clock, config, irqcallback); +} + + +/*------------------------------------------------- + mpc8240_get_info - PowerPC MPC8240-specific + information getter +-------------------------------------------------*/ + +void mpc8240_get_info(UINT32 state, cpuinfo *info) +{ + switch (state) + { + /* --- the following bits of info are returned as 64-bit signed integers --- */ + + /* --- the following bits of info are returned as pointers to data or functions --- */ + case CPUINFO_PTR_INIT: info->init = mpc8240_init; break; + + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case CPUINFO_STR_NAME: strcpy(info->s, "PowerPC MPC8240"); break; + + /* --- everything else is handled generically --- */ + default: ppcdrc_get_info(state, info); break; + } +} + +#endif + + + +/*************************************************************************** + DISASSEMBLERS +***************************************************************************/ + +#if !defined(MAME_DEBUG) && (LOG_UML || LOG_NATIVE) +#include "ppc_dasm.c" +#endif diff --git a/src/emu/cpu/powerpc/ppcdrco.c b/src/emu/cpu/powerpc/ppcdrco.c deleted file mode 100644 index 398228e53b6..00000000000 --- a/src/emu/cpu/powerpc/ppcdrco.c +++ /dev/null @@ -1,2485 +0,0 @@ -/* - PowerPC 4xx/6xx Dynamic Recompiler for x86 - - Written by Ville Linde -*/ - -#include "debugger.h" -#include "ppc.h" -#include "cpu/x86drc.h" - - -#define PPC_DRC -#define LOG_CODE (0) - -#define CACHE_SIZE (16 * 1024 * 1024) -#define MAX_INSTRUCTIONS 512 - - -#if (HAS_PPC603) -static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int)); -static void ppcdrc603_exit(void); -#endif -#if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240 || HAS_PPC604) -static void ppcdrc603_reset(void); -static int ppcdrc603_execute(int cycles); -static void ppcdrc603_set_irq_line(int irqline, int state); -#endif -#if (HAS_PPC602) -static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int)); -static void ppcdrc602_exit(void); -static void ppcdrc602_reset(void); -static int ppcdrc602_execute(int cycles); -static void ppcdrc602_set_irq_line(int irqline, int state); -#endif -#if (HAS_PPC403) -static UINT8 ppc403_spu_r(UINT32 a); -static void ppc403_spu_w(UINT32 a, UINT8 d); -static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int)); -static void ppcdrc403_exit(void); -static void ppcdrc403_reset(void); -static int ppcdrc403_execute(int cycles); -static void ppcdrc403_set_irq_line(int irqline, int state); -#endif - -static void ppcdrc_init(void); -static void ppcdrc_reset(drc_core *drc); -static void ppcdrc_recompile(drc_core *drc); -static void ppcdrc_entrygen(drc_core *drc); - -#define RD ((op >> 21) & 0x1F) -#define RT ((op >> 21) & 0x1f) -#define RS ((op >> 21) & 0x1f) -#define RA ((op >> 16) & 0x1f) -#define RB ((op >> 11) & 0x1f) -#define RC ((op >> 6) & 0x1f) - -#define MB ((op >> 6) & 0x1f) -#define ME ((op >> 1) & 0x1f) -#define SH ((op >> 11) & 0x1f) -#define BO ((op >> 21) & 0x1f) -#define BI ((op >> 16) & 0x1f) -#define CRFD ((op >> 23) & 0x7) -#define CRFA ((op >> 18) & 0x7) -#define FXM ((op >> 12) & 0xff) -#define SPR (((op >> 16) & 0x1f) | ((op >> 6) & 0x3e0)) - -#define SIMM16 (INT32)(INT16)(op & 0xffff) -#define UIMM16 (UINT32)(op & 0xffff) - -#define RCBIT (op & 0x1) -#define OEBIT (op & 0x400) -#define AABIT (op & 0x2) -#define LKBIT (op & 0x1) - -#define REG(x) (ppc.r[x]) -#define LR (ppc.lr) -#define CTR (ppc.ctr) -#define XER (ppc.xer) -#define CR(x) (ppc.cr[x]) -#define MSR (ppc.msr) -#define SRR0 (ppc.srr0) -#define SRR1 (ppc.srr1) -#define SRR2 (ppc.srr2) -#define SRR3 (ppc.srr3) -#define EVPR (ppc.evpr) -#define EXIER (ppc.exier) -#define EXISR (ppc.exisr) -#define DEC (ppc.dec) - - -// Stuff added for the 6xx -#define FPR(x) (ppc.fpr[x]) -#define FM ((op >> 17) & 0xFF) -#define SPRF (((op >> 6) & 0x3E0) | ((op >> 16) & 0x1F)) - - -#define CHECK_SUPERVISOR() \ - if((ppc.msr & 0x4000) != 0){ \ - } - -#define CHECK_FPU_AVAILABLE() \ - if((ppc.msr & 0x2000) == 0){ \ - } - -#if (HAS_PPC601||HAS_PPC602||HAS_PPC603||HAS_PPC604||HAS_MPC8240) -static UINT32 ppc_field_xlat[256]; -#endif - - - -#define FPSCR_FX 0x80000000 -#define FPSCR_FEX 0x40000000 -#define FPSCR_VX 0x20000000 -#define FPSCR_OX 0x10000000 -#define FPSCR_UX 0x08000000 -#define FPSCR_ZX 0x04000000 -#define FPSCR_XX 0x02000000 - - - -#define BITMASK_0(n) (UINT32)(((UINT64)1 << n) - 1) -#define CRBIT(x) ((ppc.cr[x / 4] & (1 << (3 - (x % 4)))) ? 1 : 0) -#define _BIT(n) (1 << (n)) -#define GET_ROTATE_MASK(mb,me) (ppc_rotate_mask[mb][me]) -#define ADD_CA(r,a,b) ((UINT32)r < (UINT32)a) -#define SUB_CA(r,a,b) (!((UINT32)a < (UINT32)b)) -#define ADD_OV(r,a,b) ((~((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) -#define SUB_OV(r,a,b) (( ((a) ^ (b)) & ((a) ^ (r))) & 0x80000000) - -#define XER_SO 0x80000000 -#define XER_OV 0x40000000 -#define XER_CA 0x20000000 - -#define MSR_AP 0x00800000 /* Access privilege state (PPC602) */ -#define MSR_SA 0x00400000 /* Supervisor access mode (PPC602) */ -#define MSR_POW 0x00040000 /* Power Management Enable */ -#define MSR_WE 0x00040000 -#define MSR_CE 0x00020000 -#define MSR_ILE 0x00010000 /* Interrupt Little Endian Mode */ -#define MSR_EE 0x00008000 /* External Interrupt Enable */ -#define MSR_PR 0x00004000 /* Problem State */ -#define MSR_FP 0x00002000 /* Floating Point Available */ -#define MSR_ME 0x00001000 /* Machine Check Enable */ -#define MSR_FE0 0x00000800 -#define MSR_SE 0x00000400 /* Single Step Trace Enable */ -#define MSR_BE 0x00000200 /* Branch Trace Enable */ -#define MSR_DE 0x00000200 -#define MSR_FE1 0x00000100 -#define MSR_IP 0x00000040 /* Interrupt Prefix */ -#define MSR_IR 0x00000020 /* Instruction Relocate */ -#define MSR_DR 0x00000010 /* Data Relocate */ -#define MSR_PE 0x00000008 -#define MSR_PX 0x00000004 -#define MSR_RI 0x00000002 /* Recoverable Interrupt Enable */ -#define MSR_LE 0x00000001 - -#define TSR_ENW 0x80000000 -#define TSR_WIS 0x40000000 - -#define BYTE_REVERSE16(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) -#define BYTE_REVERSE32(x) ((((x) >> 24) & 0xff) | (((x) >> 8) & 0xff00) | (((x) << 8) & 0xff0000) | (((x) << 24) & 0xff000000)) - -typedef struct { - UINT32 cr; - UINT32 da; - UINT32 sa; - UINT32 ct; - UINT32 cc; -} DMA_REGS; - -typedef struct { - UINT8 spls; - UINT8 sphs; - UINT16 brd; - UINT8 spctl; - UINT8 sprc; - UINT8 sptc; - UINT8 sprb; - UINT8 sptb; - emu_timer *rx_timer; - emu_timer *tx_timer; -} SPU_REGS; - -typedef union { - UINT64 id; - double fd; -} FPR; - -typedef union { - UINT32 i; - float f; -} FPR32; - -typedef struct { - UINT32 u; - UINT32 l; -} BATENT; - - -typedef struct { - UINT32 r[32]; - UINT32 pc; - UINT32 npc; - - UINT32 lr; - UINT32 ctr; - UINT32 xer; - UINT32 msr; - UINT8 cr[8]; - UINT32 pvr; - UINT32 srr0; - UINT32 srr1; - UINT32 srr2; - UINT32 srr3; - UINT32 hid0; - UINT32 hid1; - UINT32 hid2; - UINT32 sdr1; - UINT32 sprg[4]; - - UINT32 dsisr; - UINT32 dar; - UINT32 ear; - UINT32 dmiss; - UINT32 dcmp; - UINT32 hash1; - UINT32 hash2; - UINT32 imiss; - UINT32 icmp; - UINT32 rpa; - - BATENT ibat[4]; - BATENT dbat[4]; - - UINT32 evpr; - UINT32 exier; - UINT32 exisr; - UINT32 bear; - UINT32 besr; - UINT32 iocr; - UINT32 br[8]; - UINT32 iabr; - UINT32 esr; - UINT32 iccr; - UINT32 dccr; - UINT32 pit; - UINT32 tsr; - UINT32 tcr; - UINT32 dbsr; - UINT32 sgr; - UINT32 pid; - UINT32 pbl1, pbl2, pbu1, pbu2; - UINT32 fit_bit; - UINT32 fit_int_enable; - UINT32 wdt_bit; - UINT32 wdt_int_enable; - UINT32 dac1, dac2; - UINT32 iac1, iac2; - - SPU_REGS spu; - DMA_REGS dma[4]; - UINT32 dmasr; - - int reserved; - UINT32 reserved_address; - - int exception_pending; - - UINT64 tb; /* 56-bit timebase register */ - - int (*irq_callback)(int irqline); - drc_core *drc; - UINT32 drcoptions; - - x86code * invoke_exception_handler; - x86code * generate_interrupt_exception; - x86code * generate_syscall_exception; - x86code * generate_decrementer_exception; - x86code * generate_trap_exception; - x86code * generate_dsi_exception; - x86code * generate_isi_exception; - x86code * generate_fit_exception; - - // PowerPC 60x specific registers */ - UINT32 dec, dec_frac; - UINT32 fpscr; - - FPR fpr[32]; - UINT32 sr[16]; - - int is603; - int is602; - - /* PowerPC 602 specific registers */ - UINT32 lt; - UINT32 sp; - UINT32 ibr; - UINT32 esasrr; - UINT32 sebr; - UINT32 ser; - - /* PowerPC function pointers for memory accesses/exceptions */ - UINT8 (*read8)(offs_t address); - UINT16 (*read16)(offs_t address); - UINT32 (*read32)(offs_t address); - UINT64 (*read64)(offs_t address); - void (*write8)(offs_t address, UINT8 data); - void (*write16)(offs_t address, UINT16 data); - void (*write32)(offs_t address, UINT32 data); - void (*write64)(offs_t address, UINT64 data); - UINT16 (*read16_unaligned)(offs_t address); - UINT32 (*read32_unaligned)(offs_t address); - UINT64 (*read64_unaligned)(offs_t address); - void (*write16_unaligned)(offs_t address, UINT16 data); - void (*write32_unaligned)(offs_t address, UINT32 data); - void (*write64_unaligned)(offs_t address, UINT64 data); - - /* saved ESP when entering entry point */ - UINT32 host_esp; - - UINT32 (* optable19[1024])(drc_core *, UINT32); - UINT32 (* optable31[1024])(drc_core *, UINT32); - UINT32 (* optable59[1024])(drc_core *, UINT32); - UINT32 (* optable63[1024])(drc_core *, UINT32); - UINT32 (* optable[64])(drc_core *, UINT32); -} PPC_REGS; - - - -typedef struct { - int code; - int subcode; - UINT32 (* handler)(drc_core *, UINT32); -} PPC_OPCODE; - - -/* code logging info */ -typedef struct _code_log_entry code_log_entry; -struct _code_log_entry -{ - UINT32 pc; - UINT32 op; - void * base; -}; - - - -static int ppc_icount; -static int ppc_tb_base_icount; -static int ppc_dec_base_icount; -static int ppc_dec_trigger_cycle; -static int bus_freq_multiplier = 1; -static int ppc_fit_trigger_cycle; -static PPC_REGS ppc; -static UINT32 ppc_rotate_mask[32][32]; - -#define ROPCODE(pc) cpu_readop32(pc) -#define ROPCODE64(pc) cpu_readop64(DWORD_XOR_BE(pc)) - -INLINE void SET_CR0(INT32 rd) -{ - if( rd < 0 ) { - CR(0) = 0x8; - } else if( rd > 0 ) { - CR(0) = 0x4; - } else { - CR(0) = 0x2; - } - - if( XER & XER_SO ) - CR(0) |= 0x1; -} - -INLINE void SET_CR1(void) -{ - CR(1) = (ppc.fpscr >> 28) & 0xf; -} - -INLINE void SET_ADD_OV(UINT32 rd, UINT32 ra, UINT32 rb) -{ - if( ADD_OV(rd, ra, rb) ) - XER |= XER_SO | XER_OV; - else - XER &= ~XER_OV; -} - -INLINE void SET_SUB_OV(UINT32 rd, UINT32 ra, UINT32 rb) -{ - if( SUB_OV(rd, ra, rb) ) - XER |= XER_SO | XER_OV; - else - XER &= ~XER_OV; -} - -INLINE void SET_ADD_CA(UINT32 rd, UINT32 ra, UINT32 rb) -{ - if( ADD_CA(rd, ra, rb) ) - XER |= XER_CA; - else - XER &= ~XER_CA; -} - -INLINE void SET_SUB_CA(UINT32 rd, UINT32 ra, UINT32 rb) -{ - if( SUB_CA(rd, ra, rb) ) - XER |= XER_CA; - else - XER &= ~XER_CA; -} - -INLINE UINT32 check_condition_code(UINT32 bo, UINT32 bi) -{ - UINT32 ctr_ok; - UINT32 condition_ok; - UINT32 bo0 = (bo & 0x10) ? 1 : 0; - UINT32 bo1 = (bo & 0x08) ? 1 : 0; - UINT32 bo2 = (bo & 0x04) ? 1 : 0; - UINT32 bo3 = (bo & 0x02) ? 1 : 0; - - if( bo2 == 0 ) - --CTR; - - ctr_ok = bo2 | ((CTR != 0) ^ bo3); - condition_ok = bo0 | (CRBIT(bi) ^ (~bo1 & 0x1)); - - return ctr_ok && condition_ok; -} - -INLINE UINT64 ppc_read_timebase(void) -{ - int cycles = ppc_tb_base_icount - ppc_icount; - - if (ppc.is603 || ppc.is602) - { - // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly - return ppc.tb + (cycles / 4); - } - else - { - // timebase is incremented once every core cycle on PPC403 - return ppc.tb + cycles; - } -} - -INLINE void ppc_write_timebase_l(UINT32 tbl) -{ - ppc_tb_base_icount = ppc_icount; - - ppc.tb &= ~0xffffffff; - ppc.tb |= tbl; -} - -INLINE void ppc_write_timebase_h(UINT32 tbh) -{ - ppc_tb_base_icount = ppc_icount; - - ppc.tb &= 0xffffffff; - ppc.tb |= (UINT64)(tbh) << 32; -} - -INLINE UINT32 read_decrementer(void) -{ - int cycles = ppc_dec_base_icount - ppc_icount; - - // decrementer is decremented once every four bus clock cycles, so adjust the cycles accordingly - return DEC - (cycles / (bus_freq_multiplier * 2)); -} - -INLINE void write_decrementer(UINT32 value) -{ - ppc_dec_base_icount = ppc_icount + (ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2); - - DEC = value; - - // check if decrementer exception occurs during execution - if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) - { - ppc_dec_trigger_cycle = ppc_icount - DEC; - } - else - { - ppc_dec_trigger_cycle = 0x7fffffff; - } -} - -/*********************************************************************/ - -INLINE void ppc_exception(int exception_type) -{ - void *exception_code = NULL; - void (*invoke_exception_handler)(void *handler); - - switch(exception_type) - { - case EXCEPTION_DECREMENTER: - exception_code = ppc.generate_decrementer_exception; - break; - case EXCEPTION_DSI: - exception_code = ppc.generate_dsi_exception; - break; - case EXCEPTION_ISI: - exception_code = ppc.generate_isi_exception; - break; - default: - fatalerror("Unknown exception %d", exception_type); - break; - } - - memcpy(&invoke_exception_handler, &ppc.invoke_exception_handler, sizeof(invoke_exception_handler)); - invoke_exception_handler(exception_code); -} - -/*********************************************************************/ - -INLINE void ppc_set_spr(int spr, UINT32 value) -{ - switch (spr) - { - case SPR_LR: LR = value; return; - case SPR_CTR: CTR = value; return; - case SPR_XER: XER = value; return; - case SPR_SRR0: ppc.srr0 = value; return; - case SPR_SRR1: ppc.srr1 = value; return; - case SPR_SPRG0: ppc.sprg[0] = value; return; - case SPR_SPRG1: ppc.sprg[1] = value; return; - case SPR_SPRG2: ppc.sprg[2] = value; return; - case SPR_SPRG3: ppc.sprg[3] = value; return; - case SPR_PVR: return; - } - -#if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601 || HAS_PPC604) - if(ppc.is603 || ppc.is602) { - switch(spr) - { - case SPR603E_DEC: - if((value & 0x80000000) && !(DEC & 0x80000000)) - { - /* trigger interrupt */ - if( MSR & MSR_EE ) - ppc_exception(EXCEPTION_DECREMENTER); - } - write_decrementer(value); - return; - - case SPR603E_TBL_W: - case SPR603E_TBL_R: // special 603e case - ppc_write_timebase_l(value); - return; - - case SPR603E_TBU_R: - case SPR603E_TBU_W: // special 603e case - ppc_write_timebase_h(value); - return; - - case SPR603E_HID0: - ppc.hid0 = value; - return; - - case SPR603E_HID1: - ppc.hid1 = value; - return; - - case SPR603E_HID2: - ppc.hid1 = value; - return; - - case SPR603E_DSISR: ppc.dsisr = value; return; - case SPR603E_DAR: ppc.dar = value; return; - case SPR603E_EAR: ppc.ear = value; return; - case SPR603E_DMISS: ppc.dmiss = value; return; - case SPR603E_DCMP: ppc.dcmp = value; return; - case SPR603E_HASH1: ppc.hash1 = value; return; - case SPR603E_HASH2: ppc.hash2 = value; return; - case SPR603E_IMISS: ppc.imiss = value; return; - case SPR603E_ICMP: ppc.icmp = value; return; - case SPR603E_RPA: ppc.rpa = value; return; - - case SPR603E_IBAT0L: ppc.ibat[0].l = value; return; - case SPR603E_IBAT0U: ppc.ibat[0].u = value; return; - case SPR603E_IBAT1L: ppc.ibat[1].l = value; return; - case SPR603E_IBAT1U: ppc.ibat[1].u = value; return; - case SPR603E_IBAT2L: ppc.ibat[2].l = value; return; - case SPR603E_IBAT2U: ppc.ibat[2].u = value; return; - case SPR603E_IBAT3L: ppc.ibat[3].l = value; return; - case SPR603E_IBAT3U: ppc.ibat[3].u = value; return; - case SPR603E_DBAT0L: ppc.dbat[0].l = value; return; - case SPR603E_DBAT0U: ppc.dbat[0].u = value; return; - case SPR603E_DBAT1L: ppc.dbat[1].l = value; return; - case SPR603E_DBAT1U: ppc.dbat[1].u = value; return; - case SPR603E_DBAT2L: ppc.dbat[2].l = value; return; - case SPR603E_DBAT2U: ppc.dbat[2].u = value; return; - case SPR603E_DBAT3L: ppc.dbat[3].l = value; return; - case SPR603E_DBAT3U: ppc.dbat[3].u = value; return; - - case SPR603E_SDR1: - ppc.sdr1 = value; - return; - - case SPR603E_IABR: ppc.iabr = value; return; - } - } -#endif - -#if (HAS_PPC602) - if (ppc.is602) { - switch(spr) - { - case SPR602_LT: ppc.lt = value; return; - case SPR602_IBR: ppc.ibr = value; return; - case SPR602_SP: ppc.sp = value; return; - case SPR602_SEBR: ppc.sebr = value; return; - case SPR602_SER: ppc.ser = value; return; - case SPR602_TCR: ppc.tcr = value; return; - } - } -#endif - -#if (HAS_PPC403) - if (!ppc.is603 && !ppc.is602) { - switch(spr) - { - case SPR403_TBHI: ppc_write_timebase_h(value); return; - case SPR403_TBLO: ppc_write_timebase_l(value); return; - - case SPR403_TSR: - ppc.tsr &= ~value; // 1 clears, 0 does nothing - return; - - case SPR403_TCR: - switch((value >> 24) & 0x3) - { - case 0: ppc.fit_bit = 1 << 8; break; - case 1: ppc.fit_bit = 1 << 12; break; - case 2: ppc.fit_bit = 1 << 16; break; - case 3: ppc.fit_bit = 1 << 20; break; - } - switch((value >> 30) & 0x3) - { - case 0: ppc.wdt_bit = 1 << 16; break; - case 1: ppc.wdt_bit = 1 << 20; break; - case 2: ppc.wdt_bit = 1 << 24; break; - case 3: ppc.wdt_bit = 1 << 28; break; - } - ppc.fit_int_enable = (value >> 23) & 0x1; - ppc.wdt_int_enable = (value >> 27) & 0x1; - ppc.tcr = value; - - if (!ppc.fit_int_enable) - { - ppc.exception_pending &= ~0x4; - } - return; - - case SPR403_ESR: ppc.esr = value; return; - case SPR403_ICCR: ppc.iccr = value; return; - case SPR403_DCCR: ppc.dccr = value; return; - case SPR403_EVPR: EVPR = value & 0xffff0000; return; - case SPR403_PIT: ppc.pit = value; return; - case SPR403_SGR: ppc.sgr = value; return; - case SPR403_DBSR: ppc.dbsr = value; return; - case SPR403_DCWR: return; - case SPR403_PID: ppc.pid = value; return; - case SPR403_PBL1: ppc.pbl1 = value; return; - case SPR403_PBU1: ppc.pbu1 = value; return; - case SPR403_PBL2: ppc.pbl2 = value; return; - case SPR403_PBU2: ppc.pbu2 = value; return; - case SPR403_SRR2: ppc.srr2 = value; return; - case SPR403_SRR3: ppc.srr3 = value; return; - case SPR403_DAC1: ppc.dac1 = value; return; - case SPR403_DAC2: ppc.dac2 = value; return; - case SPR403_IAC1: ppc.iac1 = value; return; - case SPR403_IAC2: ppc.iac2 = value; return; - } - } -#endif - - fatalerror("ppc: set_spr: unknown spr %d (%03X) !", spr, spr); -} - -INLINE UINT32 ppc_get_spr(int spr) -{ - switch(spr) - { - case SPR_LR: return LR; - case SPR_CTR: return CTR; - case SPR_XER: return XER; - case SPR_SRR0: return ppc.srr0; - case SPR_SRR1: return ppc.srr1; - case SPR_SPRG0: return ppc.sprg[0]; - case SPR_SPRG1: return ppc.sprg[1]; - case SPR_SPRG2: return ppc.sprg[2]; - case SPR_SPRG3: return ppc.sprg[3]; - case SPR_PVR: return ppc.pvr; - } - -#if (HAS_PPC403) - if (!ppc.is603 && !ppc.is602) - { - switch (spr) - { - case SPR403_TBLU: - case SPR403_TBLO: return (UINT32)(ppc_read_timebase()); - case SPR403_TBHU: - case SPR403_TBHI: return (UINT32)(ppc_read_timebase() >> 32); - - case SPR403_EVPR: return EVPR; - case SPR403_ESR: return ppc.esr; - case SPR403_TCR: return ppc.tcr; - case SPR403_ICCR: return ppc.iccr; - case SPR403_DCCR: return ppc.dccr; - case SPR403_PIT: return ppc.pit; - case SPR403_DBSR: return ppc.dbsr; - case SPR403_SGR: return ppc.sgr; - case SPR403_TSR: return ppc.tsr; - case SPR403_PBL1: return ppc.pbl1; - case SPR403_PBU1: return ppc.pbu1; - case SPR403_PBL2: return ppc.pbl2; - case SPR403_PBU2: return ppc.pbu2; - case SPR403_SRR2: return ppc.srr2; - case SPR403_SRR3: return ppc.srr3; - case SPR403_DAC1: return ppc.dac1; - case SPR403_DAC2: return ppc.dac2; - case SPR403_IAC1: return ppc.iac1; - case SPR403_IAC2: return ppc.iac2; - } - } -#endif - -#if (HAS_PPC602) - if (ppc.is602) { - switch(spr) - { - case SPR602_LT: return ppc.lt; - case SPR602_IBR: return ppc.ibr; - case SPR602_ESASRR: return ppc.esasrr; - case SPR602_SEBR: return ppc.sebr; - case SPR602_SER: return ppc.ser; - case SPR602_SP: return ppc.sp; - case SPR602_TCR: return ppc.tcr; - } - } -#endif - -#if (HAS_PPC603 || HAS_PPC602 || HAS_PPC601 || HAS_PPC604) - if (ppc.is603 || ppc.is602) - { - switch (spr) - { - case SPR603E_TBL_R: - fatalerror("ppc: get_spr: TBL_R "); - break; - - case SPR603E_TBU_R: - fatalerror("ppc: get_spr: TBU_R "); - break; - - case SPR603E_TBL_W: return (UINT32)(ppc_read_timebase()); - case SPR603E_TBU_W: return (UINT32)(ppc_read_timebase() >> 32); - case SPR603E_HID0: return ppc.hid0; - case SPR603E_HID1: return ppc.hid1; - case SPR603E_HID2: return ppc.hid2; - case SPR603E_DEC: return read_decrementer(); - case SPR603E_SDR1: return ppc.sdr1; - case SPR603E_DSISR: return ppc.dsisr; - case SPR603E_DAR: return ppc.dar; - case SPR603E_EAR: return ppc.ear; - case SPR603E_IBAT0L: return ppc.ibat[0].l; - case SPR603E_IBAT0U: return ppc.ibat[0].u; - case SPR603E_IBAT1L: return ppc.ibat[1].l; - case SPR603E_IBAT1U: return ppc.ibat[1].u; - case SPR603E_IBAT2L: return ppc.ibat[2].l; - case SPR603E_IBAT2U: return ppc.ibat[2].u; - case SPR603E_IBAT3L: return ppc.ibat[3].l; - case SPR603E_IBAT3U: return ppc.ibat[3].u; - case SPR603E_DBAT0L: return ppc.dbat[0].l; - case SPR603E_DBAT0U: return ppc.dbat[0].u; - case SPR603E_DBAT1L: return ppc.dbat[1].l; - case SPR603E_DBAT1U: return ppc.dbat[1].u; - case SPR603E_DBAT2L: return ppc.dbat[2].l; - case SPR603E_DBAT2U: return ppc.dbat[2].u; - case SPR603E_DBAT3L: return ppc.dbat[3].l; - case SPR603E_DBAT3U: return ppc.dbat[3].u; - } - } -#endif - - fatalerror("ppc: get_spr: unknown spr %d (%03X) !", spr, spr); - return 0; -} - -static UINT8 ppc_read8_translated(offs_t address); -static UINT16 ppc_read16_translated(offs_t address); -static UINT32 ppc_read32_translated(offs_t address); -static UINT64 ppc_read64_translated(offs_t address); -static void ppc_write8_translated(offs_t address, UINT8 data); -static void ppc_write16_translated(offs_t address, UINT16 data); -static void ppc_write32_translated(offs_t address, UINT32 data); -static void ppc_write64_translated(offs_t address, UINT64 data); - -INLINE void ppc_set_msr(UINT32 value) -{ - if( value & (MSR_ILE | MSR_LE) ) - fatalerror("ppc: set_msr: little_endian mode not supported !"); - - MSR = value; - - if (ppc.is603 || ppc.is602) - { - if (!(MSR & MSR_DR)) - { - ppc.read8 = program_read_byte_64be; - ppc.read16 = program_read_word_64be; - ppc.read32 = program_read_dword_64be; - ppc.read64 = program_read_qword_64be; - ppc.write8 = program_write_byte_64be; - ppc.write16 = program_write_word_64be; - ppc.write32 = program_write_dword_64be; - ppc.write64 = program_write_qword_64be; - } - else - { - ppc.read8 = ppc_read8_translated; - ppc.read16 = ppc_read16_translated; - ppc.read32 = ppc_read32_translated; - ppc.read64 = ppc_read64_translated; - ppc.write8 = ppc_write8_translated; - ppc.write16 = ppc_write16_translated; - ppc.write32 = ppc_write32_translated; - ppc.write64 = ppc_write64_translated; - } - } -} - -INLINE UINT32 ppc_get_msr(void) -{ - return MSR; -} - -INLINE void ppc_set_cr(UINT32 value) -{ - CR(0) = (value >> 28) & 0xf; - CR(1) = (value >> 24) & 0xf; - CR(2) = (value >> 20) & 0xf; - CR(3) = (value >> 16) & 0xf; - CR(4) = (value >> 12) & 0xf; - CR(5) = (value >> 8) & 0xf; - CR(6) = (value >> 4) & 0xf; - CR(7) = (value >> 0) & 0xf; -} - -INLINE UINT32 ppc_get_cr(void) -{ - return CR(0) << 28 | CR(1) << 24 | CR(2) << 20 | CR(3) << 16 | CR(4) << 12 | CR(5) << 8 | CR(6) << 4 | CR(7); -} - -#ifdef UNUSED_FUNCTION -static void log_code(drc_core *drc) -{ -#if LOG_CODE - FILE *temp; - temp = fopen("code.bin", "wb"); - fwrite(drc->cache_base, 1, drc->cache_top - drc->cache_base, temp); - fclose(temp); -#endif -} -#endif - -/***********************************************************************/ - -#include "ppc_mem.c" - -#if (HAS_PPC403) -#include "ppc403.c" -#endif - -#if (HAS_PPC602) -#include "ppc602.c" -#endif - -/*************************************************************************** - CODE LOGGING -***************************************************************************/ - -#if LOG_CODE - -static code_log_entry code_log_buffer[MAX_INSTRUCTIONS*2]; -static int code_log_index; -static FILE *logfile; - - -/*------------------------------------------------- - open_logfile - open the log file if it is - not already opened --------------------------------------------------*/ - -INLINE int open_logfile(void) -{ - if (logfile == NULL) - logfile = fopen("ppcdrc.asm", "w"); - return (logfile != NULL); -} - - -/*------------------------------------------------- - code_log_reset - reset the logging index --------------------------------------------------*/ - -INLINE void code_log_reset(void) -{ - code_log_index = 0; -} - - -/*------------------------------------------------- - code_log_add_entry - add an entry to the log --------------------------------------------------*/ - -INLINE void code_log_add_entry(UINT32 pc, UINT32 op, void *base) -{ - code_log_buffer[code_log_index].pc = pc; - code_log_buffer[code_log_index].op = op; - code_log_buffer[code_log_index].base = base; - code_log_index++; -} - - -/*------------------------------------------------- - code_log - actually log some code --------------------------------------------------*/ - -static void code_log(const char *label, x86code *start, x86code *stop) -{ - extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode); - offs_t ppc_dasm_one(char *buffer, UINT32 pc, UINT32 op); - UINT8 *cur = start; - - /* open the file, creating it if necessary */ - if (!open_logfile()) - return; - fprintf(logfile, "\n%s\n", label); - - /* loop from the start until the cache top */ - while (cur < stop) - { - char buffer[100]; - int bytes; - int op; - - /* skip filler opcodes */ - if (*cur == 0xcc) - { - cur++; - continue; - } - - /* disassemble this instruction */ -#ifdef PTR64 - bytes = i386_dasm_one(buffer, (UINT32)(FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK; -#else - bytes = i386_dasm_one(buffer, (UINT32)cur, cur, 32) & DASMFLAG_LENGTHMASK; -#endif - - /* look for a match in the registered opcodes */ - for (op = 0; op < code_log_index; op++) - if (code_log_buffer[op].base == (void *)cur) - break; - - /* if no match, just output the current instruction */ - if (op == code_log_index) - fprintf(logfile, "%p: %s\n", cur, buffer); - - /* otherwise, output with the original instruction to the right */ - else - { - char buffer2[100]; - ppc_dasm_one(buffer2, code_log_buffer[op].pc, code_log_buffer[op].op); - fprintf(logfile, "%p: %-50s %08X: %s\n", cur, buffer, code_log_buffer[op].pc, buffer2); - } - - /* advance past this instruction */ - cur += bytes; - } - - /* flush the file */ - fflush(logfile); -} - -#else - -#define code_log_reset() -#define code_log_add_entry(a,b,c) -#define code_log(a,b,c) - -#endif - - -/********************************************************************/ - -#include "ppc_ops.c" -#include "drc_ops.c" -#include "drc_ops.h" - -/* Initialization and shutdown */ - -static void ppc_init(void) -{ - int i,j; - - for( i=0; i < 64; i++ ) { - ppc.optable[i] = recompile_invalid; - } - for( i=0; i < 1024; i++ ) { - ppc.optable19[i] = recompile_invalid; - ppc.optable31[i] = recompile_invalid; - ppc.optable59[i] = recompile_invalid; - ppc.optable63[i] = recompile_invalid; - } - - /* Fill the opcode tables */ - for( i=0; i < (sizeof(ppcdrc_opcode_common) / sizeof(PPC_OPCODE)); i++ ) { - - switch(ppcdrc_opcode_common[i].code) - { - case 19: - ppc.optable19[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler; - break; - - case 31: - ppc.optable31[ppcdrc_opcode_common[i].subcode] = ppcdrc_opcode_common[i].handler; - break; - - case 59: - case 63: - break; - - default: - ppc.optable[ppcdrc_opcode_common[i].code] = ppcdrc_opcode_common[i].handler; - } - - } - - /* Calculate rotate mask table */ - for( i=0; i < 32; i++ ) { - for( j=0; j < 32; j++ ) { - UINT32 mask; - int mb = i; - int me = j; - mask = ((UINT32)0xFFFFFFFF >> mb) ^ ((me >= 31) ? 0 : ((UINT32)0xFFFFFFFF >> (me + 1))); - if( mb > me ) - mask = ~mask; - - ppc_rotate_mask[i][j] = mask; - } - } -} - -#if (HAS_PPC403) -static void ppcdrc403_init(int index, int clock, const void *_config, int (*irqcallback)(int)) -{ - const ppc_config *config = _config; - - ppc_init(); - ppcdrc_init(); - - /* PPC403 specific opcodes */ - ppc.optable31[454] = recompile_dccci; - ppc.optable31[486] = recompile_dcread; - ppc.optable31[262] = recompile_icbt; - ppc.optable31[966] = recompile_iccci; - ppc.optable31[998] = recompile_icread; - ppc.optable31[323] = recompile_mfdcr; - ppc.optable31[451] = recompile_mtdcr; - ppc.optable31[131] = recompile_wrtee; - ppc.optable31[163] = recompile_wrteei; - ppc.optable19[51] = recompile_rfci; - - ppc.spu.rx_timer = timer_alloc(ppc403_spu_rx_callback, NULL); - ppc.spu.tx_timer = timer_alloc(ppc403_spu_tx_callback, NULL); - - ppc.is603 = 0; - ppc.is602 = 0; - - ppc.read8 = ppc403_read8; - ppc.read16 = ppc403_read16; - ppc.read32 = ppc403_read32; - ppc.write8 = ppc403_write8; - ppc.write16 = ppc403_write16; - ppc.write32 = ppc403_write32; - ppc.read16_unaligned = ppc403_read16_unaligned; - ppc.read32_unaligned = ppc403_read32_unaligned; - ppc.write16_unaligned = ppc403_write16_unaligned; - ppc.write32_unaligned = ppc403_write32_unaligned; - - ppc.irq_callback = irqcallback; - - ppc.pvr = config->pvr; -} - -static void ppcdrc403_exit(void) -{ -#if LOG_CODE - //if (symfile) fclose(symfile); -#endif - ppcdrc_exit(); -} - -static void ppcdrc403_reset(void) -{ - ppc.pc = ppc.npc = 0xfffffffc; - - ppc_set_msr(0); - change_pc(ppc.pc); - - /* reset the DRC */ - drc_cache_reset(ppc.drc); -} - -static int ppcdrc403_execute(int cycles) -{ - /* count cycles and interrupt cycles */ - ppc_icount = cycles; - ppc_tb_base_icount = cycles; - - ppc_fit_trigger_cycle = 0x7fffffff; - - if (ppc.fit_int_enable) - { - UINT32 tb = (UINT32)ppc.tb; - UINT32 fit_cycles = 0; - - if (ppc.tb & ppc.fit_bit) - { - fit_cycles += ppc.fit_bit; - tb += fit_cycles; - } - - fit_cycles += ppc.fit_bit - (tb & (ppc.fit_bit-1)); - - ppc_fit_trigger_cycle = ppc_icount - fit_cycles; - } - - drc_execute(ppc.drc); - - // update timebase - ppc.tb += (ppc_tb_base_icount - ppc_icount); - - return cycles - ppc_icount; -} - -static void ppcdrc403_set_irq_line(int irqline, int state) -{ - if (irqline >= INPUT_LINE_IRQ0 && irqline <= INPUT_LINE_IRQ4) - { - UINT32 mask = (1 << (4 - irqline)); - if( state == ASSERT_LINE) { - if (EXIER & mask) - { - ppc.exisr |= mask; - ppc.exception_pending |= 0x1; - - if (ppc.irq_callback) - { - ppc.irq_callback(irqline); - } - } - } - // clear line is used to clear the interrupt when the interrupts are level-sensitive - else if (state == CLEAR_LINE) - { - ppc.exisr &= ~mask; - } - } - else if (irqline == PPC403_SPU_RX) - { - UINT32 mask = 0x08000000; - if (state) { - if( EXIER & mask ) { - ppc.exisr |= mask; - ppc.exception_pending |= 0x1; - } - } - } - else if (irqline == PPC403_SPU_TX) - { - UINT32 mask = 0x04000000; - if (state) { - if( EXIER & mask ) { - ppc.exisr |= mask; - ppc.exception_pending |= 0x1; - } - } - } - else - { - fatalerror("PPC: Unknown IRQ line %d", irqline); - } -} -#endif - -#if (HAS_PPC603) -static void ppcdrc603_init(int index, int clock, const void *_config, int (*irqcallback)(int)) -{ - int pll_config = 0; - float multiplier; - const ppc_config *config = _config; - int i; - - ppc_init(); - ppcdrc_init(); - - ppc.optable[48] = recompile_lfs; - ppc.optable[49] = recompile_lfsu; - ppc.optable[50] = recompile_lfd; - ppc.optable[51] = recompile_lfdu; - ppc.optable[52] = recompile_stfs; - ppc.optable[53] = recompile_stfsu; - ppc.optable[54] = recompile_stfd; - ppc.optable[55] = recompile_stfdu; - ppc.optable31[631] = recompile_lfdux; - ppc.optable31[599] = recompile_lfdx; - ppc.optable31[567] = recompile_lfsux; - ppc.optable31[535] = recompile_lfsx; - ppc.optable31[595] = recompile_mfsr; - ppc.optable31[659] = recompile_mfsrin; - ppc.optable31[371] = recompile_mftb; - ppc.optable31[210] = recompile_mtsr; - ppc.optable31[242] = recompile_mtsrin; - ppc.optable31[758] = recompile_dcba; - ppc.optable31[759] = recompile_stfdux; - ppc.optable31[727] = recompile_stfdx; - ppc.optable31[983] = recompile_stfiwx; - ppc.optable31[695] = recompile_stfsux; - ppc.optable31[663] = recompile_stfsx; - ppc.optable31[370] = recompile_tlbia; - ppc.optable31[306] = recompile_tlbie; - ppc.optable31[566] = recompile_tlbsync; - ppc.optable31[310] = recompile_eciwx; - ppc.optable31[438] = recompile_ecowx; - - ppc.optable63[264] = recompile_fabsx; - ppc.optable63[21] = recompile_faddx; - ppc.optable63[32] = recompile_fcmpo; - ppc.optable63[0] = recompile_fcmpu; - ppc.optable63[14] = recompile_fctiwx; - ppc.optable63[15] = recompile_fctiwzx; - ppc.optable63[18] = recompile_fdivx; - ppc.optable63[72] = recompile_fmrx; - ppc.optable63[136] = recompile_fnabsx; - ppc.optable63[40] = recompile_fnegx; - ppc.optable63[12] = recompile_frspx; - ppc.optable63[26] = recompile_frsqrtex; - ppc.optable63[22] = recompile_fsqrtx; - ppc.optable63[20] = recompile_fsubx; - ppc.optable63[583] = recompile_mffsx; - ppc.optable63[70] = recompile_mtfsb0x; - ppc.optable63[38] = recompile_mtfsb1x; - ppc.optable63[711] = recompile_mtfsfx; - ppc.optable63[134] = recompile_mtfsfix; - ppc.optable63[64] = recompile_mcrfs; - - ppc.optable59[21] = recompile_faddsx; - ppc.optable59[18] = recompile_fdivsx; - ppc.optable59[24] = recompile_fresx; - ppc.optable59[22] = recompile_fsqrtsx; - ppc.optable59[20] = recompile_fsubsx; - - for(i = 0; i < 32; i++) - { - ppc.optable63[i * 32 | 29] = recompile_fmaddx; - ppc.optable63[i * 32 | 28] = recompile_fmsubx; - ppc.optable63[i * 32 | 25] = recompile_fmulx; - ppc.optable63[i * 32 | 31] = recompile_fnmaddx; - ppc.optable63[i * 32 | 30] = recompile_fnmsubx; - ppc.optable63[i * 32 | 23] = recompile_fselx; - - ppc.optable59[i * 32 | 29] = recompile_fmaddsx; - ppc.optable59[i * 32 | 28] = recompile_fmsubsx; - ppc.optable59[i * 32 | 25] = recompile_fmulsx; - ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; - ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; - } - -#if (HAS_PPC602 || HAS_MPC8240) - ppc.optable31[978] = recompile_tlbld; -#endif /* (HAS_PPC602 || HAS_MPC8240) */ - - for(i = 0; i < 256; i++) - { - ppc_field_xlat[i] = - ((i & 0x80) ? 0xF0000000 : 0) | - ((i & 0x40) ? 0x0F000000 : 0) | - ((i & 0x20) ? 0x00F00000 : 0) | - ((i & 0x10) ? 0x000F0000 : 0) | - ((i & 0x08) ? 0x0000F000 : 0) | - ((i & 0x04) ? 0x00000F00 : 0) | - ((i & 0x02) ? 0x000000F0 : 0) | - ((i & 0x01) ? 0x0000000F : 0); - } - - ppc.is603 = 1; - - ppc.read8 = program_read_byte_64be; - ppc.read16 = program_read_word_64be; - ppc.read32 = program_read_dword_64be; - ppc.read64 = program_read_qword_64be; - ppc.write8 = program_write_byte_64be; - ppc.write16 = program_write_word_64be; - ppc.write32 = program_write_dword_64be; - ppc.write64 = program_write_qword_64be; - ppc.read16_unaligned = ppc_read16_unaligned; - ppc.read32_unaligned = ppc_read32_unaligned; - ppc.read64_unaligned = ppc_read64_unaligned; - ppc.write16_unaligned = ppc_write16_unaligned; - ppc.write32_unaligned = ppc_write32_unaligned; - ppc.write64_unaligned = ppc_write64_unaligned; - - ppc.irq_callback = irqcallback; - - ppc.pvr = config->pvr; - - multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + - (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; - bus_freq_multiplier = (int)(multiplier * 2); - - switch(config->pvr) - { - case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; - case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; - case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; - default: break; - } - - if (pll_config == -1) - { - fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); - } - - ppc.hid1 = pll_config << 28; -} - -static void ppcdrc603_exit(void) -{ -#if LOG_CODE - //if (symfile) fclose(symfile); -#endif - ppcdrc_exit(); -} -#endif - -#if (HAS_PPC601 || HAS_PPC603 || HAS_MPC8240 || HAS_PPC604) -static void ppcdrc603_reset(void) -{ - ppc.pc = ppc.npc = 0xfff00100; - - ppc_set_msr(0x40); - change_pc(ppc.pc); - - /* reset the DRC */ - drc_cache_reset(ppc.drc); -} - -static int ppcdrc603_execute(int cycles) -{ - /* count cycles and interrupt cycles */ - ppc_icount = cycles; - ppc_tb_base_icount = cycles; - ppc_dec_base_icount = cycles + ppc.dec_frac; - - // check if decrementer exception occurs during execution - if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) - { - ppc_dec_trigger_cycle = ppc_icount - DEC; - } - else - { - ppc_dec_trigger_cycle = 0x7fffffff; - } - - drc_execute(ppc.drc); - - // update timebase - // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly - ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); - - // update decrementer - ppc.dec_frac = ((ppc_dec_base_icount - ppc_icount) % (bus_freq_multiplier * 2)); - DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); - - return cycles - ppc_icount; -} - -static void ppcdrc603_set_irq_line(int irqline, int state) -{ - if( state ) { - ppc.exception_pending |= 0x1; - if (ppc.irq_callback) - { - ppc.irq_callback(irqline); - } - } -} -#endif - -#if (HAS_PPC602) -static void ppcdrc602_init(int index, int clock, const void *_config, int (*irqcallback)(int)) -{ - float multiplier; - const ppc_config *config = _config; - int i; - - ppc_init(); - ppcdrc_init(); - - ppc.optable[48] = recompile_lfs; - ppc.optable[49] = recompile_lfsu; - ppc.optable[50] = recompile_lfd; - ppc.optable[51] = recompile_lfdu; - ppc.optable[52] = recompile_stfs; - ppc.optable[53] = recompile_stfsu; - ppc.optable[54] = recompile_stfd; - ppc.optable[55] = recompile_stfdu; - ppc.optable31[631] = recompile_lfdux; - ppc.optable31[599] = recompile_lfdx; - ppc.optable31[567] = recompile_lfsux; - ppc.optable31[535] = recompile_lfsx; - ppc.optable31[595] = recompile_mfsr; - ppc.optable31[659] = recompile_mfsrin; - ppc.optable31[371] = recompile_mftb; - ppc.optable31[210] = recompile_mtsr; - ppc.optable31[242] = recompile_mtsrin; - ppc.optable31[758] = recompile_dcba; - ppc.optable31[759] = recompile_stfdux; - ppc.optable31[727] = recompile_stfdx; - ppc.optable31[983] = recompile_stfiwx; - ppc.optable31[695] = recompile_stfsux; - ppc.optable31[663] = recompile_stfsx; - ppc.optable31[370] = recompile_tlbia; - ppc.optable31[306] = recompile_tlbie; - ppc.optable31[566] = recompile_tlbsync; - ppc.optable31[310] = recompile_eciwx; - ppc.optable31[438] = recompile_ecowx; - - ppc.optable63[264] = recompile_fabsx; - ppc.optable63[21] = recompile_faddx; - ppc.optable63[32] = recompile_fcmpo; - ppc.optable63[0] = recompile_fcmpu; - ppc.optable63[14] = recompile_fctiwx; - ppc.optable63[15] = recompile_fctiwzx; - ppc.optable63[18] = recompile_fdivx; - ppc.optable63[72] = recompile_fmrx; - ppc.optable63[136] = recompile_fnabsx; - ppc.optable63[40] = recompile_fnegx; - ppc.optable63[12] = recompile_frspx; - ppc.optable63[26] = recompile_frsqrtex; - ppc.optable63[22] = recompile_fsqrtx; - ppc.optable63[20] = recompile_fsubx; - ppc.optable63[583] = recompile_mffsx; - ppc.optable63[70] = recompile_mtfsb0x; - ppc.optable63[38] = recompile_mtfsb1x; - ppc.optable63[711] = recompile_mtfsfx; - ppc.optable63[134] = recompile_mtfsfix; - ppc.optable63[64] = recompile_mcrfs; - - ppc.optable59[21] = recompile_faddsx; - ppc.optable59[18] = recompile_fdivsx; - ppc.optable59[24] = recompile_fresx; - ppc.optable59[22] = recompile_fsqrtsx; - ppc.optable59[20] = recompile_fsubsx; - - for(i = 0; i < 32; i++) - { - ppc.optable63[i * 32 | 29] = recompile_fmaddx; - ppc.optable63[i * 32 | 28] = recompile_fmsubx; - ppc.optable63[i * 32 | 25] = recompile_fmulx; - ppc.optable63[i * 32 | 31] = recompile_fnmaddx; - ppc.optable63[i * 32 | 30] = recompile_fnmsubx; - ppc.optable63[i * 32 | 23] = recompile_fselx; - - ppc.optable59[i * 32 | 29] = recompile_fmaddsx; - ppc.optable59[i * 32 | 28] = recompile_fmsubsx; - ppc.optable59[i * 32 | 25] = recompile_fmulsx; - ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; - ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; - } - - for(i = 0; i < 256; i++) - { - ppc_field_xlat[i] = - ((i & 0x80) ? 0xF0000000 : 0) | - ((i & 0x40) ? 0x0F000000 : 0) | - ((i & 0x20) ? 0x00F00000 : 0) | - ((i & 0x10) ? 0x000F0000 : 0) | - ((i & 0x08) ? 0x0000F000 : 0) | - ((i & 0x04) ? 0x00000F00 : 0) | - ((i & 0x02) ? 0x000000F0 : 0) | - ((i & 0x01) ? 0x0000000F : 0); - } - - // PPC602 specific opcodes - ppc.optable31[596] = recompile_esa; - ppc.optable31[628] = recompile_dsa; - ppc.optable31[1010] = recompile_tlbli; - ppc.optable31[978] = recompile_tlbld; - - ppc.is603 = 0; - ppc.is602 = 1; - - ppc.read8 = program_read_byte_64be; - ppc.read16 = program_read_word_64be; - ppc.read32 = program_read_dword_64be; - ppc.read64 = program_read_qword_64be; - ppc.write8 = program_write_byte_64be; - ppc.write16 = program_write_word_64be; - ppc.write32 = program_write_dword_64be; - ppc.write64 = program_write_qword_64be; - ppc.read16_unaligned = ppc_read16_unaligned; - ppc.read32_unaligned = ppc_read32_unaligned; - ppc.read64_unaligned = ppc_read64_unaligned; - ppc.write16_unaligned = ppc_write16_unaligned; - ppc.write32_unaligned = ppc_write32_unaligned; - ppc.write64_unaligned = ppc_write64_unaligned; - - ppc.irq_callback = irqcallback; - - ppc.pvr = config->pvr; - - multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + - (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; - bus_freq_multiplier = (int)(multiplier * 2); -} - -static void ppcdrc602_exit(void) -{ -#if LOG_CODE - //if (symfile) fclose(symfile); -#endif - ppcdrc_exit(); -} - -static void ppcdrc602_reset(void) -{ - ppc.pc = ppc.npc = 0xfff00100; - - ppc_set_msr(0x40); - change_pc(ppc.pc); - - ppc.hid0 = 1; - - /* reset the DRC */ - drc_cache_reset(ppc.drc); -} - -static int ppcdrc602_execute(int cycles) -{ - /* count cycles and interrupt cycles */ - ppc_icount = cycles; - ppc_tb_base_icount = cycles; - ppc_dec_base_icount = cycles; - - // check if decrementer exception occurs during execution - if ((UINT32)(DEC - ppc_icount) > (UINT32)(DEC)) - { - ppc_dec_trigger_cycle = ppc_icount - DEC; - } - else - { - ppc_dec_trigger_cycle = 0x7fffffff; - } - - drc_execute(ppc.drc); - - // update timebase - // timebase is incremented once every four core clock cycles, so adjust the cycles accordingly - ppc.tb += ((ppc_tb_base_icount - ppc_icount) / 4); - - // update decrementer - DEC -= ((ppc_dec_base_icount - ppc_icount) / (bus_freq_multiplier * 2)); - - return cycles - ppc_icount; -} - -static void ppcdrc602_set_irq_line(int irqline, int state) -{ - if( state ) { - ppc.exception_pending |= 0x1; - if (ppc.irq_callback) - { - ppc.irq_callback(irqline); - } - } -} -#endif - -#if (HAS_MPC8240) -static void mpc8240drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) -{ - float multiplier; - const ppc_config *config = _config; - int i; - - ppc_init(); - ppcdrc_init(); - - ppc.optable[48] = recompile_lfs; - ppc.optable[49] = recompile_lfsu; - ppc.optable[50] = recompile_lfd; - ppc.optable[51] = recompile_lfdu; - ppc.optable[52] = recompile_stfs; - ppc.optable[53] = recompile_stfsu; - ppc.optable[54] = recompile_stfd; - ppc.optable[55] = recompile_stfdu; - ppc.optable31[631] = recompile_lfdux; - ppc.optable31[599] = recompile_lfdx; - ppc.optable31[567] = recompile_lfsux; - ppc.optable31[535] = recompile_lfsx; - ppc.optable31[595] = recompile_mfsr; - ppc.optable31[659] = recompile_mfsrin; - ppc.optable31[371] = recompile_mftb; - ppc.optable31[210] = recompile_mtsr; - ppc.optable31[242] = recompile_mtsrin; - ppc.optable31[758] = recompile_dcba; - ppc.optable31[759] = recompile_stfdux; - ppc.optable31[727] = recompile_stfdx; - ppc.optable31[983] = recompile_stfiwx; - ppc.optable31[695] = recompile_stfsux; - ppc.optable31[663] = recompile_stfsx; - ppc.optable31[370] = recompile_tlbia; - ppc.optable31[306] = recompile_tlbie; - ppc.optable31[566] = recompile_tlbsync; - ppc.optable31[310] = recompile_eciwx; - ppc.optable31[438] = recompile_ecowx; - - ppc.optable63[264] = recompile_fabsx; - ppc.optable63[21] = recompile_faddx; - ppc.optable63[32] = recompile_fcmpo; - ppc.optable63[0] = recompile_fcmpu; - ppc.optable63[14] = recompile_fctiwx; - ppc.optable63[15] = recompile_fctiwzx; - ppc.optable63[18] = recompile_fdivx; - ppc.optable63[72] = recompile_fmrx; - ppc.optable63[136] = recompile_fnabsx; - ppc.optable63[40] = recompile_fnegx; - ppc.optable63[12] = recompile_frspx; - ppc.optable63[26] = recompile_frsqrtex; - ppc.optable63[22] = recompile_fsqrtx; - ppc.optable63[20] = recompile_fsubx; - ppc.optable63[583] = recompile_mffsx; - ppc.optable63[70] = recompile_mtfsb0x; - ppc.optable63[38] = recompile_mtfsb1x; - ppc.optable63[711] = recompile_mtfsfx; - ppc.optable63[134] = recompile_mtfsfix; - ppc.optable63[64] = recompile_mcrfs; - - ppc.optable59[21] = recompile_faddsx; - ppc.optable59[18] = recompile_fdivsx; - ppc.optable59[24] = recompile_fresx; - ppc.optable59[22] = recompile_fsqrtsx; - ppc.optable59[20] = recompile_fsubsx; - - for(i = 0; i < 32; i++) - { - ppc.optable63[i * 32 | 29] = recompile_fmaddx; - ppc.optable63[i * 32 | 28] = recompile_fmsubx; - ppc.optable63[i * 32 | 25] = recompile_fmulx; - ppc.optable63[i * 32 | 31] = recompile_fnmaddx; - ppc.optable63[i * 32 | 30] = recompile_fnmsubx; - ppc.optable63[i * 32 | 23] = recompile_fselx; - - ppc.optable59[i * 32 | 29] = recompile_fmaddsx; - ppc.optable59[i * 32 | 28] = recompile_fmsubsx; - ppc.optable59[i * 32 | 25] = recompile_fmulsx; - ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; - ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; - } - - for(i = 0; i < 256; i++) - { - ppc_field_xlat[i] = - ((i & 0x80) ? 0xF0000000 : 0) | - ((i & 0x40) ? 0x0F000000 : 0) | - ((i & 0x20) ? 0x00F00000 : 0) | - ((i & 0x10) ? 0x000F0000 : 0) | - ((i & 0x08) ? 0x0000F000 : 0) | - ((i & 0x04) ? 0x00000F00 : 0) | - ((i & 0x02) ? 0x000000F0 : 0) | - ((i & 0x01) ? 0x0000000F : 0); - } - - // MPC8240 specific opcodes - ppc.optable31[978] = recompile_tlbld; - ppc.optable31[1010] = recompile_tlbli; - - ppc.is603 = 1; - - ppc.read8 = program_read_byte_64be; - ppc.read16 = program_read_word_64be; - ppc.read32 = program_read_dword_64be; - ppc.read64 = program_read_qword_64be; - ppc.write8 = program_write_byte_64be; - ppc.write16 = program_write_word_64be; - ppc.write32 = program_write_dword_64be; - ppc.write64 = program_write_qword_64be; - ppc.read16_unaligned = ppc_read16_unaligned; - ppc.read32_unaligned = ppc_read32_unaligned; - ppc.read64_unaligned = ppc_read64_unaligned; - ppc.write16_unaligned = ppc_write16_unaligned; - ppc.write32_unaligned = ppc_write32_unaligned; - ppc.write64_unaligned = ppc_write64_unaligned; - - ppc.irq_callback = irqcallback; - - ppc.pvr = config->pvr; - - multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + - (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; - bus_freq_multiplier = (int)(multiplier * 2); -} - -static void mpc8240drc_exit(void) -{ - ppcdrc_exit(); -} -#endif - - -#if (HAS_PPC601) -static void ppc601drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) -{ - int pll_config = 0; - float multiplier; - const ppc_config *config = _config; - int i; - - ppc_init(); - ppcdrc_init(); - - ppc.optable[48] = recompile_lfs; - ppc.optable[49] = recompile_lfsu; - ppc.optable[50] = recompile_lfd; - ppc.optable[51] = recompile_lfdu; - ppc.optable[52] = recompile_stfs; - ppc.optable[53] = recompile_stfsu; - ppc.optable[54] = recompile_stfd; - ppc.optable[55] = recompile_stfdu; - ppc.optable31[631] = recompile_lfdux; - ppc.optable31[599] = recompile_lfdx; - ppc.optable31[567] = recompile_lfsux; - ppc.optable31[535] = recompile_lfsx; - ppc.optable31[595] = recompile_mfsr; - ppc.optable31[659] = recompile_mfsrin; - ppc.optable31[371] = recompile_mftb; - ppc.optable31[210] = recompile_mtsr; - ppc.optable31[242] = recompile_mtsrin; - ppc.optable31[758] = recompile_dcba; - ppc.optable31[759] = recompile_stfdux; - ppc.optable31[727] = recompile_stfdx; - ppc.optable31[983] = recompile_stfiwx; - ppc.optable31[695] = recompile_stfsux; - ppc.optable31[663] = recompile_stfsx; - ppc.optable31[370] = recompile_tlbia; - ppc.optable31[306] = recompile_tlbie; - ppc.optable31[566] = recompile_tlbsync; - ppc.optable31[310] = recompile_eciwx; - ppc.optable31[438] = recompile_ecowx; - - ppc.optable63[264] = recompile_fabsx; - ppc.optable63[21] = recompile_faddx; - ppc.optable63[32] = recompile_fcmpo; - ppc.optable63[0] = recompile_fcmpu; - ppc.optable63[14] = recompile_fctiwx; - ppc.optable63[15] = recompile_fctiwzx; - ppc.optable63[18] = recompile_fdivx; - ppc.optable63[72] = recompile_fmrx; - ppc.optable63[136] = recompile_fnabsx; - ppc.optable63[40] = recompile_fnegx; - ppc.optable63[12] = recompile_frspx; - ppc.optable63[26] = recompile_frsqrtex; - ppc.optable63[22] = recompile_fsqrtx; - ppc.optable63[20] = recompile_fsubx; - ppc.optable63[583] = recompile_mffsx; - ppc.optable63[70] = recompile_mtfsb0x; - ppc.optable63[38] = recompile_mtfsb1x; - ppc.optable63[711] = recompile_mtfsfx; - ppc.optable63[134] = recompile_mtfsfix; - ppc.optable63[64] = recompile_mcrfs; - - ppc.optable59[21] = recompile_faddsx; - ppc.optable59[18] = recompile_fdivsx; - ppc.optable59[24] = recompile_fresx; - ppc.optable59[22] = recompile_fsqrtsx; - ppc.optable59[20] = recompile_fsubsx; - - for(i = 0; i < 32; i++) - { - ppc.optable63[i * 32 | 29] = recompile_fmaddx; - ppc.optable63[i * 32 | 28] = recompile_fmsubx; - ppc.optable63[i * 32 | 25] = recompile_fmulx; - ppc.optable63[i * 32 | 31] = recompile_fnmaddx; - ppc.optable63[i * 32 | 30] = recompile_fnmsubx; - ppc.optable63[i * 32 | 23] = recompile_fselx; - - ppc.optable59[i * 32 | 29] = recompile_fmaddsx; - ppc.optable59[i * 32 | 28] = recompile_fmsubsx; - ppc.optable59[i * 32 | 25] = recompile_fmulsx; - ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; - ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; - } - - for(i = 0; i < 256; i++) - { - ppc_field_xlat[i] = - ((i & 0x80) ? 0xF0000000 : 0) | - ((i & 0x40) ? 0x0F000000 : 0) | - ((i & 0x20) ? 0x00F00000 : 0) | - ((i & 0x10) ? 0x000F0000 : 0) | - ((i & 0x08) ? 0x0000F000 : 0) | - ((i & 0x04) ? 0x00000F00 : 0) | - ((i & 0x02) ? 0x000000F0 : 0) | - ((i & 0x01) ? 0x0000000F : 0); - } - - ppc.is603 = 1; - - ppc.read8 = program_read_byte_64be; - ppc.read16 = program_read_word_64be; - ppc.read32 = program_read_dword_64be; - ppc.read64 = program_read_qword_64be; - ppc.write8 = program_write_byte_64be; - ppc.write16 = program_write_word_64be; - ppc.write32 = program_write_dword_64be; - ppc.write64 = program_write_qword_64be; - ppc.read16_unaligned = ppc_read16_unaligned; - ppc.read32_unaligned = ppc_read32_unaligned; - ppc.read64_unaligned = ppc_read64_unaligned; - ppc.write16_unaligned = ppc_write16_unaligned; - ppc.write32_unaligned = ppc_write32_unaligned; - ppc.write64_unaligned = ppc_write64_unaligned; - - ppc.irq_callback = irqcallback; - - ppc.pvr = config->pvr; - - multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + - (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; - bus_freq_multiplier = (int)(multiplier * 2); - - switch(config->pvr) - { - case PPC_MODEL_603E: pll_config = mpc603e_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; - case PPC_MODEL_603EV: pll_config = mpc603ev_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; - case PPC_MODEL_603R: pll_config = mpc603r_pll_config[bus_freq_multiplier-1][config->bus_frequency]; break; - default: break; - } - - if (pll_config == -1) - { - fatalerror("PPC: Invalid bus/multiplier combination (bus frequency = %d, multiplier = %1.1f)", config->bus_frequency, multiplier); - } - - ppc.hid1 = pll_config << 28; -} - -static void ppc601drc_exit(void) -{ -#if LOG_CODE - //if (symfile) fclose(symfile); -#endif - ppcdrc_exit(); -} -#endif - - -#if (HAS_PPC604) -static void ppc604drc_init(int index, int clock, const void *_config, int (*irqcallback)(int)) -{ - float multiplier; - const ppc_config *config = _config; - int i; - - ppc_init(); - ppcdrc_init(); - - ppc.optable[48] = recompile_lfs; - ppc.optable[49] = recompile_lfsu; - ppc.optable[50] = recompile_lfd; - ppc.optable[51] = recompile_lfdu; - ppc.optable[52] = recompile_stfs; - ppc.optable[53] = recompile_stfsu; - ppc.optable[54] = recompile_stfd; - ppc.optable[55] = recompile_stfdu; - ppc.optable31[631] = recompile_lfdux; - ppc.optable31[599] = recompile_lfdx; - ppc.optable31[567] = recompile_lfsux; - ppc.optable31[535] = recompile_lfsx; - ppc.optable31[595] = recompile_mfsr; - ppc.optable31[659] = recompile_mfsrin; - ppc.optable31[371] = recompile_mftb; - ppc.optable31[210] = recompile_mtsr; - ppc.optable31[242] = recompile_mtsrin; - ppc.optable31[758] = recompile_dcba; - ppc.optable31[759] = recompile_stfdux; - ppc.optable31[727] = recompile_stfdx; - ppc.optable31[983] = recompile_stfiwx; - ppc.optable31[695] = recompile_stfsux; - ppc.optable31[663] = recompile_stfsx; - ppc.optable31[370] = recompile_tlbia; - ppc.optable31[306] = recompile_tlbie; - ppc.optable31[566] = recompile_tlbsync; - ppc.optable31[310] = recompile_eciwx; - ppc.optable31[438] = recompile_ecowx; - - ppc.optable63[264] = recompile_fabsx; - ppc.optable63[21] = recompile_faddx; - ppc.optable63[32] = recompile_fcmpo; - ppc.optable63[0] = recompile_fcmpu; - ppc.optable63[14] = recompile_fctiwx; - ppc.optable63[15] = recompile_fctiwzx; - ppc.optable63[18] = recompile_fdivx; - ppc.optable63[72] = recompile_fmrx; - ppc.optable63[136] = recompile_fnabsx; - ppc.optable63[40] = recompile_fnegx; - ppc.optable63[12] = recompile_frspx; - ppc.optable63[26] = recompile_frsqrtex; - ppc.optable63[22] = recompile_fsqrtx; - ppc.optable63[20] = recompile_fsubx; - ppc.optable63[583] = recompile_mffsx; - ppc.optable63[70] = recompile_mtfsb0x; - ppc.optable63[38] = recompile_mtfsb1x; - ppc.optable63[711] = recompile_mtfsfx; - ppc.optable63[134] = recompile_mtfsfix; - ppc.optable63[64] = recompile_mcrfs; - - ppc.optable59[21] = recompile_faddsx; - ppc.optable59[18] = recompile_fdivsx; - ppc.optable59[24] = recompile_fresx; - ppc.optable59[22] = recompile_fsqrtsx; - ppc.optable59[20] = recompile_fsubsx; - - for(i = 0; i < 32; i++) - { - ppc.optable63[i * 32 | 29] = recompile_fmaddx; - ppc.optable63[i * 32 | 28] = recompile_fmsubx; - ppc.optable63[i * 32 | 25] = recompile_fmulx; - ppc.optable63[i * 32 | 31] = recompile_fnmaddx; - ppc.optable63[i * 32 | 30] = recompile_fnmsubx; - ppc.optable63[i * 32 | 23] = recompile_fselx; - - ppc.optable59[i * 32 | 29] = recompile_fmaddsx; - ppc.optable59[i * 32 | 28] = recompile_fmsubsx; - ppc.optable59[i * 32 | 25] = recompile_fmulsx; - ppc.optable59[i * 32 | 31] = recompile_fnmaddsx; - ppc.optable59[i * 32 | 30] = recompile_fnmsubsx; - } - - ppc.optable31[978] = recompile_tlbld; - - for(i = 0; i < 256; i++) - { - ppc_field_xlat[i] = - ((i & 0x80) ? 0xF0000000 : 0) | - ((i & 0x40) ? 0x0F000000 : 0) | - ((i & 0x20) ? 0x00F00000 : 0) | - ((i & 0x10) ? 0x000F0000 : 0) | - ((i & 0x08) ? 0x0000F000 : 0) | - ((i & 0x04) ? 0x00000F00 : 0) | - ((i & 0x02) ? 0x000000F0 : 0) | - ((i & 0x01) ? 0x0000000F : 0); - } - - ppc.is603 = 1; - - ppc.read8 = program_read_byte_64be; - ppc.read16 = program_read_word_64be; - ppc.read32 = program_read_dword_64be; - ppc.read64 = program_read_qword_64be; - ppc.write8 = program_write_byte_64be; - ppc.write16 = program_write_word_64be; - ppc.write32 = program_write_dword_64be; - ppc.write64 = program_write_qword_64be; - ppc.read16_unaligned = ppc_read16_unaligned; - ppc.read32_unaligned = ppc_read32_unaligned; - ppc.read64_unaligned = ppc_read64_unaligned; - ppc.write16_unaligned = ppc_write16_unaligned; - ppc.write32_unaligned = ppc_write32_unaligned; - ppc.write64_unaligned = ppc_write64_unaligned; - - ppc.irq_callback = irqcallback; - - ppc.pvr = config->pvr; - - multiplier = (float)((config->bus_frequency_multiplier >> 4) & 0xf) + - (float)(config->bus_frequency_multiplier & 0xf) / 10.0f; - bus_freq_multiplier = (int)(multiplier * 2); -} - -static void ppc604drc_exit(void) -{ -#if LOG_CODE - //if (symfile) fclose(symfile); -#endif - ppcdrc_exit(); -} -#endif - - -static void ppc_get_context(void *dst) -{ - /* copy the context */ - if (dst) - *(PPC_REGS *)dst = ppc; -} - - -static void ppc_set_context(void *src) -{ - /* copy the context */ - if (src) - ppc = *(PPC_REGS *)src; - - change_pc(ppc.pc); -} - - -/************************************************************************** - * Generic set_info - **************************************************************************/ - -static void ppc_set_info(UINT32 state, cpuinfo *info) -{ - switch (state) - { - case CPUINFO_INT_PC: - case CPUINFO_INT_REGISTER + PPC_PC: ppc.pc = info->i; break; - case CPUINFO_INT_REGISTER + PPC_MSR: ppc_set_msr(info->i); break; - case CPUINFO_INT_REGISTER + PPC_CR: ppc_set_cr(info->i); break; - case CPUINFO_INT_REGISTER + PPC_LR: LR = info->i; break; - case CPUINFO_INT_REGISTER + PPC_CTR: CTR = info->i; break; - case CPUINFO_INT_REGISTER + PPC_XER: XER = info->i; break; - case CPUINFO_INT_REGISTER + PPC_SRR0: SRR0 = info->i; break; - case CPUINFO_INT_REGISTER + PPC_SRR1: SRR1 = info->i; break; - - case CPUINFO_INT_REGISTER + PPC_R0: ppc.r[0] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R1: ppc.r[1] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R2: ppc.r[2] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R3: ppc.r[3] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R4: ppc.r[4] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R5: ppc.r[5] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R6: ppc.r[6] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R7: ppc.r[7] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R8: ppc.r[8] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R9: ppc.r[9] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R10: ppc.r[10] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R11: ppc.r[11] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R12: ppc.r[12] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R13: ppc.r[13] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R14: ppc.r[14] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R15: ppc.r[15] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R16: ppc.r[16] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R17: ppc.r[17] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R18: ppc.r[18] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R19: ppc.r[19] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R20: ppc.r[20] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R21: ppc.r[21] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R22: ppc.r[22] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R23: ppc.r[23] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R24: ppc.r[24] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R25: ppc.r[25] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R26: ppc.r[26] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R27: ppc.r[27] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R28: ppc.r[28] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R29: ppc.r[29] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R30: ppc.r[30] = info->i; break; - case CPUINFO_INT_REGISTER + PPC_R31: ppc.r[31] = info->i; break; - - case CPUINFO_INT_PPC_DRC_OPTIONS: ppc.drcoptions = info->i; break; - } -} - -static void ppc_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(ppc); break; - case CPUINFO_INT_INPUT_LINES: info->i = 1; break; - case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break; - case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break; - case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break; - case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break; - case CPUINFO_INT_MIN_CYCLES: info->i = 1; break; - case CPUINFO_INT_MAX_CYCLES: info->i = 40; break; - - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break; - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break; - case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break; - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break; - case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break; - - case CPUINFO_INT_INPUT_STATE: info->i = CLEAR_LINE; break; - - case CPUINFO_INT_PREVIOUSPC: /* not implemented */ break; - - case CPUINFO_INT_PC: /* intentional fallthrough */ - case CPUINFO_INT_REGISTER + PPC_PC: info->i = ppc.pc; break; - case CPUINFO_INT_REGISTER + PPC_MSR: info->i = ppc_get_msr(); break; - case CPUINFO_INT_REGISTER + PPC_CR: info->i = ppc_get_cr(); break; - case CPUINFO_INT_REGISTER + PPC_LR: info->i = LR; break; - case CPUINFO_INT_REGISTER + PPC_CTR: info->i = CTR; break; - case CPUINFO_INT_REGISTER + PPC_XER: info->i = XER; break; - case CPUINFO_INT_REGISTER + PPC_SRR0: info->i = SRR0; break; - case CPUINFO_INT_REGISTER + PPC_SRR1: info->i = SRR1; break; - - case CPUINFO_INT_REGISTER + PPC_R0: info->i = ppc.r[0]; break; - case CPUINFO_INT_REGISTER + PPC_R1: info->i = ppc.r[1]; break; - case CPUINFO_INT_REGISTER + PPC_R2: info->i = ppc.r[2]; break; - case CPUINFO_INT_REGISTER + PPC_R3: info->i = ppc.r[3]; break; - case CPUINFO_INT_REGISTER + PPC_R4: info->i = ppc.r[4]; break; - case CPUINFO_INT_REGISTER + PPC_R5: info->i = ppc.r[5]; break; - case CPUINFO_INT_REGISTER + PPC_R6: info->i = ppc.r[6]; break; - case CPUINFO_INT_REGISTER + PPC_R7: info->i = ppc.r[7]; break; - case CPUINFO_INT_REGISTER + PPC_R8: info->i = ppc.r[8]; break; - case CPUINFO_INT_REGISTER + PPC_R9: info->i = ppc.r[9]; break; - case CPUINFO_INT_REGISTER + PPC_R10: info->i = ppc.r[10]; break; - case CPUINFO_INT_REGISTER + PPC_R11: info->i = ppc.r[11]; break; - case CPUINFO_INT_REGISTER + PPC_R12: info->i = ppc.r[12]; break; - case CPUINFO_INT_REGISTER + PPC_R13: info->i = ppc.r[13]; break; - case CPUINFO_INT_REGISTER + PPC_R14: info->i = ppc.r[14]; break; - case CPUINFO_INT_REGISTER + PPC_R15: info->i = ppc.r[15]; break; - case CPUINFO_INT_REGISTER + PPC_R16: info->i = ppc.r[16]; break; - case CPUINFO_INT_REGISTER + PPC_R17: info->i = ppc.r[17]; break; - case CPUINFO_INT_REGISTER + PPC_R18: info->i = ppc.r[18]; break; - case CPUINFO_INT_REGISTER + PPC_R19: info->i = ppc.r[19]; break; - case CPUINFO_INT_REGISTER + PPC_R20: info->i = ppc.r[20]; break; - case CPUINFO_INT_REGISTER + PPC_R21: info->i = ppc.r[21]; break; - case CPUINFO_INT_REGISTER + PPC_R22: info->i = ppc.r[22]; break; - case CPUINFO_INT_REGISTER + PPC_R23: info->i = ppc.r[23]; break; - case CPUINFO_INT_REGISTER + PPC_R24: info->i = ppc.r[24]; break; - case CPUINFO_INT_REGISTER + PPC_R25: info->i = ppc.r[25]; break; - case CPUINFO_INT_REGISTER + PPC_R26: info->i = ppc.r[26]; break; - case CPUINFO_INT_REGISTER + PPC_R27: info->i = ppc.r[27]; break; - case CPUINFO_INT_REGISTER + PPC_R28: info->i = ppc.r[28]; break; - case CPUINFO_INT_REGISTER + PPC_R29: info->i = ppc.r[29]; break; - case CPUINFO_INT_REGISTER + PPC_R30: info->i = ppc.r[30]; break; - case CPUINFO_INT_REGISTER + PPC_R31: info->i = ppc.r[31]; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_GET_CONTEXT: info->getcontext = ppc_get_context; break; - case CPUINFO_PTR_SET_CONTEXT: info->setcontext = ppc_set_context; break; - case CPUINFO_PTR_BURN: info->burn = NULL; break; -#ifdef ENABLE_DEBUGGER - case CPUINFO_PTR_DISASSEMBLE: info->disassemble = ppc_dasm; break; -#endif /* ENABLE_DEBUGGER */ - case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &ppc_icount; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; - case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "PowerPC"); break; - case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break; - case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break; - case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; - - case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break; - - case CPUINFO_STR_REGISTER + PPC_PC: sprintf(info->s, "PC: %08X", ppc.pc); break; - case CPUINFO_STR_REGISTER + PPC_MSR: sprintf(info->s, "MSR: %08X", ppc_get_msr()); break; - case CPUINFO_STR_REGISTER + PPC_CR: sprintf(info->s, "CR: %08X", ppc_get_cr()); break; - case CPUINFO_STR_REGISTER + PPC_LR: sprintf(info->s, "LR: %08X", LR); break; - case CPUINFO_STR_REGISTER + PPC_CTR: sprintf(info->s, "CTR: %08X", CTR); break; - case CPUINFO_STR_REGISTER + PPC_XER: sprintf(info->s, "XER: %08X", XER); break; - case CPUINFO_STR_REGISTER + PPC_SRR0: sprintf(info->s, "SRR0: %08X", SRR0); break; - case CPUINFO_STR_REGISTER + PPC_SRR1: sprintf(info->s, "SRR1: %08X", SRR1); break; - - case CPUINFO_STR_REGISTER + PPC_R0: sprintf(info->s, "R0: %08X", ppc.r[0]); break; - case CPUINFO_STR_REGISTER + PPC_R1: sprintf(info->s, "R1: %08X", ppc.r[1]); break; - case CPUINFO_STR_REGISTER + PPC_R2: sprintf(info->s, "R2: %08X", ppc.r[2]); break; - case CPUINFO_STR_REGISTER + PPC_R3: sprintf(info->s, "R3: %08X", ppc.r[3]); break; - case CPUINFO_STR_REGISTER + PPC_R4: sprintf(info->s, "R4: %08X", ppc.r[4]); break; - case CPUINFO_STR_REGISTER + PPC_R5: sprintf(info->s, "R5: %08X", ppc.r[5]); break; - case CPUINFO_STR_REGISTER + PPC_R6: sprintf(info->s, "R6: %08X", ppc.r[6]); break; - case CPUINFO_STR_REGISTER + PPC_R7: sprintf(info->s, "R7: %08X", ppc.r[7]); break; - case CPUINFO_STR_REGISTER + PPC_R8: sprintf(info->s, "R8: %08X", ppc.r[8]); break; - case CPUINFO_STR_REGISTER + PPC_R9: sprintf(info->s, "R9: %08X", ppc.r[9]); break; - case CPUINFO_STR_REGISTER + PPC_R10: sprintf(info->s, "R10: %08X", ppc.r[10]); break; - case CPUINFO_STR_REGISTER + PPC_R11: sprintf(info->s, "R11: %08X", ppc.r[11]); break; - case CPUINFO_STR_REGISTER + PPC_R12: sprintf(info->s, "R12: %08X", ppc.r[12]); break; - case CPUINFO_STR_REGISTER + PPC_R13: sprintf(info->s, "R13: %08X", ppc.r[13]); break; - case CPUINFO_STR_REGISTER + PPC_R14: sprintf(info->s, "R14: %08X", ppc.r[14]); break; - case CPUINFO_STR_REGISTER + PPC_R15: sprintf(info->s, "R15: %08X", ppc.r[15]); break; - case CPUINFO_STR_REGISTER + PPC_R16: sprintf(info->s, "R16: %08X", ppc.r[16]); break; - case CPUINFO_STR_REGISTER + PPC_R17: sprintf(info->s, "R17: %08X", ppc.r[17]); break; - case CPUINFO_STR_REGISTER + PPC_R18: sprintf(info->s, "R18: %08X", ppc.r[18]); break; - case CPUINFO_STR_REGISTER + PPC_R19: sprintf(info->s, "R19: %08X", ppc.r[19]); break; - case CPUINFO_STR_REGISTER + PPC_R20: sprintf(info->s, "R20: %08X", ppc.r[20]); break; - case CPUINFO_STR_REGISTER + PPC_R21: sprintf(info->s, "R21: %08X", ppc.r[21]); break; - case CPUINFO_STR_REGISTER + PPC_R22: sprintf(info->s, "R22: %08X", ppc.r[22]); break; - case CPUINFO_STR_REGISTER + PPC_R23: sprintf(info->s, "R23: %08X", ppc.r[23]); break; - case CPUINFO_STR_REGISTER + PPC_R24: sprintf(info->s, "R24: %08X", ppc.r[24]); break; - case CPUINFO_STR_REGISTER + PPC_R25: sprintf(info->s, "R25: %08X", ppc.r[25]); break; - case CPUINFO_STR_REGISTER + PPC_R26: sprintf(info->s, "R26: %08X", ppc.r[26]); break; - case CPUINFO_STR_REGISTER + PPC_R27: sprintf(info->s, "R27: %08X", ppc.r[27]); break; - case CPUINFO_STR_REGISTER + PPC_R28: sprintf(info->s, "R28: %08X", ppc.r[28]); break; - case CPUINFO_STR_REGISTER + PPC_R29: sprintf(info->s, "R29: %08X", ppc.r[29]); break; - case CPUINFO_STR_REGISTER + PPC_R30: sprintf(info->s, "R30: %08X", ppc.r[30]); break; - case CPUINFO_STR_REGISTER + PPC_R31: sprintf(info->s, "R31: %08X", ppc.r[31]); break; - } -} - - - -/* PowerPC 403 */ -#if (HAS_PPC403) -static void ppc403_set_info(UINT32 state, cpuinfo *info) -{ - if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) - { - ppcdrc403_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); - return; - } - switch(state) - { - default: ppc_set_info(state, info); break; - } -} - -void ppc403_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_LINES: info->i = 7; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_SET_INFO: info->setinfo = ppc403_set_info; break; - case CPUINFO_PTR_INIT: info->init = ppcdrc403_init; break; - case CPUINFO_PTR_RESET: info->reset = ppcdrc403_reset; break; - case CPUINFO_PTR_EXIT: info->exit = ppcdrc403_exit; break; - case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc403_execute; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "PPC403"); break; - - default: ppc_get_info(state, info); break; - } -} -#endif - -/* PowerPC 603 */ -#if (HAS_PPC603) -static void ppc603_set_info(UINT32 state, cpuinfo *info) -{ - if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) - { - ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); - return; - } - switch(state) - { - case CPUINFO_INT_REGISTER + PPC_DEC: write_decrementer(info->i); break; - default: ppc_set_info(state, info); break; - } -} - -void ppc603_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_LINES: info->i = 5; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - case CPUINFO_INT_REGISTER + PPC_DEC: info->i = read_decrementer(); break; - - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_SET_INFO: info->setinfo = ppc603_set_info; break; - case CPUINFO_PTR_INIT: info->init = ppcdrc603_init; break; - case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; - case CPUINFO_PTR_EXIT: info->exit = ppcdrc603_exit; break; - case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; - case CPUINFO_PTR_READ: info->read = ppc_read; break; - case CPUINFO_PTR_WRITE: info->write = ppc_write; break; - case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; - case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "PPC603"); break; - case CPUINFO_STR_REGISTER + PPC_DEC: sprintf(info->s, "DEC: %08X", read_decrementer()); break; - - default: ppc_get_info(state, info); break; - } -} -#endif - -/* PowerPC 602 */ -#if (HAS_PPC602) -static void ppc602_set_info(UINT32 state, cpuinfo *info) -{ - if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) - { - ppcdrc602_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); - return; - } - switch(state) - { - default: ppc_set_info(state, info); break; - } -} - -void ppc602_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_LINES: info->i = 5; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 17; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_SET_INFO: info->setinfo = ppc602_set_info; break; - case CPUINFO_PTR_INIT: info->init = ppcdrc602_init; break; - case CPUINFO_PTR_RESET: info->reset = ppcdrc602_reset; break; - case CPUINFO_PTR_EXIT: info->exit = ppcdrc602_exit; break; - case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc602_execute; break; - case CPUINFO_PTR_READ: info->read = ppc_read; break; - case CPUINFO_PTR_WRITE: info->write = ppc_write; break; - case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; - case CPUINFO_PTR_TRANSLATE: info->translate = ppc_translate_address_cb; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "PPC602"); break; - - default: ppc_get_info(state, info); break; - } -} -#endif - -/* Motorola MPC8240 */ - -#if (HAS_MPC8240) -static void mpc8240_set_info(UINT32 state, cpuinfo *info) -{ - if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) - { - ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); - return; - } - switch(state) - { - default: ppc_set_info(state, info); break; - } -} - -void mpc8240_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_LINES: info->i = 5; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_SET_INFO: info->setinfo = mpc8240_set_info; break; - case CPUINFO_PTR_INIT: info->init = mpc8240drc_init; break; - case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; - case CPUINFO_PTR_EXIT: info->exit = mpc8240drc_exit; break; - case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; - case CPUINFO_PTR_READ: info->read = ppc_read; break; - case CPUINFO_PTR_WRITE: info->write = ppc_write; break; - case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "MPC8240"); break; - - default: ppc_get_info(state, info); break; - } -} -#endif - - -/* PPC601 */ - -#if (HAS_PPC601) -static void ppc601_set_info(UINT32 state, cpuinfo *info) -{ - if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) - { - ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); - return; - } - switch(state) - { - default: ppc_set_info(state, info); break; - } -} - -void ppc601_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_LINES: info->i = 5; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_SET_INFO: info->setinfo = ppc601_set_info; break; - case CPUINFO_PTR_INIT: info->init = ppc601drc_init; break; - case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; - case CPUINFO_PTR_EXIT: info->exit = ppc601drc_exit; break; - case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; - case CPUINFO_PTR_READ: info->read = ppc_read; break; - case CPUINFO_PTR_WRITE: info->write = ppc_write; break; - case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "PPC601"); break; - - default: ppc_get_info(state, info); break; - } -} -#endif - -/* PPC604 */ - -#if (HAS_PPC604) -static void ppc604_set_info(UINT32 state, cpuinfo *info) -{ - if (state >= CPUINFO_INT_INPUT_STATE && state <= CPUINFO_INT_INPUT_STATE + 5) - { - ppcdrc603_set_irq_line(state-CPUINFO_INT_INPUT_STATE, info->i); - return; - } - switch(state) - { - default: ppc_set_info(state, info); break; - } -} - -void ppc604_get_info(UINT32 state, cpuinfo *info) -{ - switch(state) - { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case CPUINFO_INT_INPUT_LINES: info->i = 5; break; - case CPUINFO_INT_ENDIANNESS: info->i = CPU_IS_BE; break; - - case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 64; break; - case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case CPUINFO_PTR_SET_INFO: info->setinfo = ppc604_set_info; break; - case CPUINFO_PTR_INIT: info->init = ppc604drc_init; break; - case CPUINFO_PTR_RESET: info->reset = ppcdrc603_reset; break; - case CPUINFO_PTR_EXIT: info->exit = ppc604drc_exit; break; - case CPUINFO_PTR_EXECUTE: info->execute = ppcdrc603_execute; break; - case CPUINFO_PTR_READ: info->read = ppc_read; break; - case CPUINFO_PTR_WRITE: info->write = ppc_write; break; - case CPUINFO_PTR_READOP: info->readop = ppc_readop; break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case CPUINFO_STR_NAME: strcpy(info->s, "PPC604"); break; - - default: ppc_get_info(state, info); break; - } -} -#endif diff --git a/src/emu/cpu/powerpc/ppcfe.c b/src/emu/cpu/powerpc/ppcfe.c new file mode 100644 index 00000000000..f232793e0d1 --- /dev/null +++ b/src/emu/cpu/powerpc/ppcfe.c @@ -0,0 +1,942 @@ +/*************************************************************************** + + ppcfe.c + + Front-end for PowerPC recompiler + + Copyright Aaron Giles + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#include <stddef.h> +#include "cpuintrf.h" +#include "ppcfe.h" +#include "ppccom.h" + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static int describe_instruction_13(powerpc_state *ppc, UINT32 op, opcode_desc *desc); +static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *desc); +static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *desc); +static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *desc); + + + +/*************************************************************************** + INSTRUCTION PARSERS +***************************************************************************/ + +/*------------------------------------------------- + ppcfe_describe - build a description + of a single instruction +-------------------------------------------------*/ + +int ppcfe_describe(void *param, opcode_desc *desc) +{ + powerpc_state *ppc = param; + UINT32 op = *desc->opptr.l; + UINT32 opswitch = op >> 26; + + /* all instructions are 4 bytes and default to a single cycle each */ + desc->length = 4; + desc->cycles = 1; + + /* parse the instruction */ + switch (opswitch) + { + case 0x02: /* TDI - 64-bit only */ + case 0x1e: /* 0x1e group - 64-bit only */ + case 0x3a: /* 0x3a group - 64-bit only */ + case 0x3e: /* 0x3e group - 64-bit only */ + return FALSE; + + case 0x03: /* TWI */ + desc->gpr.used |= REGFLAG_R(G_RA(op)); + desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x07: /* MULLI */ + desc->gpr.used |= REGFLAG_R(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + return TRUE; + + case 0x0e: /* ADDI */ + case 0x0f: /* ADDIS */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + return TRUE; + + case 0x0a: /* CMPLI */ + case 0x0b: /* CMPI */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(G_CRFD(op)); + return TRUE; + + case 0x08: /* SUBFIC */ + case 0x0c: /* ADDIC */ + desc->gpr.used |= REGFLAG_R(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)) | REGFLAG_XER; + return TRUE; + + case 0x0d: /* ADDIC. */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_XER; + desc->gpr.modified |= REGFLAG_R(G_RT(op)) | REGFLAG_CR(0) | REGFLAG_XER; + return TRUE; + + case 0x10: /* BCx */ + desc->gpr.used |= REGFLAG_CR(G_BI(op) / 4); + if (op & M_LK) desc->gpr.modified |= REGFLAG_LR; + if (!(G_BO(op) & 4)) + { + desc->gpr.used |= REGFLAG_CTR; + desc->gpr.modified |= REGFLAG_CTR; + } + if ((G_BO(op) & 0x14) == 0x14) + desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc->targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc->pc); + return TRUE; + + case 0x11: /* SC */ + if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) + return FALSE; + desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION; + return TRUE; + + case 0x12: /* Bx */ + if (op & M_LK) desc->gpr.modified |= REGFLAG_LR; + desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + desc->targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc->pc); + return TRUE; + + case 0x13: /* 0x13 group */ + return describe_instruction_13(ppc, op, desc); + + case 0x14: /* RLWIMIx */ + desc->gpr.used |= REGFLAG_R(G_RS(op)) | REGFLAG_R(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x15: /* RLWINMx */ + desc->gpr.used |= REGFLAG_R(G_RS(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x17: /* RLWNMx */ + desc->gpr.used |= REGFLAG_R(G_RS(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x18: /* ORI */ + case 0x19: /* ORIS */ + case 0x1a: /* XORI */ + case 0x1b: /* XORIS */ + desc->gpr.used |= REGFLAG_R(G_RS(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + return TRUE; + + case 0x1c: /* ANDI. */ + case 0x1d: /* ANDIS. */ + desc->gpr.used |= REGFLAG_R(G_RS(op)) | REGFLAG_XER; + desc->gpr.modified |= REGFLAG_R(G_RA(op)) | REGFLAG_CR(0); + return TRUE; + + case 0x1f: /* 0x1f group */ + return describe_instruction_1f(ppc, op, desc); + + case 0x20: /* LWZ */ + case 0x22: /* LBZ */ + case 0x28: /* LHZ */ + case 0x2a: /* LHA */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x21: /* LWZU */ + case 0x23: /* LBZU */ + case 0x29: /* LHZU */ + case 0x2b: /* LHAU */ + if (G_RA(op) == 0) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)) | REGFLAG_R(G_RA(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x24: /* STW */ + case 0x26: /* STB */ + case 0x2c: /* STH */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x25: /* STWU */ + case 0x27: /* STBU */ + case 0x2d: /* STHU */ + if (G_RA(op) == 0) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RS(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x2e: /* LMW */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->gpr.modified |= ((REGFLAG_R(31) << 1) - 1) & ~(REGFLAG_R(G_RD(op)) - 1); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x2f: /* STMW */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | (((REGFLAG_R(31) << 1) - 1) & ~(REGFLAG_R(G_RS(op)) - 1)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x30: /* LFS */ + case 0x32: /* LFD */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x31: /* LFSU */ + case 0x33: /* LFDU */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x34: /* STFS */ + case 0x36: /* STFD */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->fpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x35: /* STFSU */ + case 0x37: /* STFDU */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + desc->fpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x3b: /* 0x3b group */ + return describe_instruction_3b(ppc, op, desc); + + case 0x3f: /* 0x3f group */ + return describe_instruction_3f(ppc, op, desc); + } + + return FALSE; +} + + +/*------------------------------------------------- + describe_instruction_13 - build a + description of a single instruction in the + 0x13 group +-------------------------------------------------*/ + +static int describe_instruction_13(powerpc_state *ppc, UINT32 op, opcode_desc *desc) +{ + UINT32 opswitch = (op >> 1) & 0x3ff; + + switch (opswitch) + { + case 0x000: /* MTCRF */ + desc->gpr.used |= REGFLAG_CR(G_CRFS(op)); + desc->gpr.modified |= REGFLAG_CR(G_CRFD(op)); + return TRUE; + + case 0x010: /* BCLRx */ + desc->gpr.used |= REGFLAG_CR(G_BI(op) / 4) | REGFLAG_LR; + if (op & M_LK) desc->gpr.modified |= REGFLAG_LR; + if (!(G_BO(op) & 4)) + { + desc->gpr.used |= REGFLAG_CTR; + desc->gpr.modified |= REGFLAG_CTR; + } + if ((G_BO(op) & 0x14) == 0x14) + desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc->targetpc = BRANCH_TARGET_DYNAMIC; + return TRUE; + + case 0x021: /* CRNOR */ + case 0x081: /* CRANDC */ + case 0x0c1: /* CRXOR */ + case 0x0e1: /* CRNAND */ + case 0x101: /* CRAND */ + case 0x121: /* CREQV */ + case 0x1a1: /* CRORC */ + case 0x1c1: /* CROR */ + desc->gpr.used |= REGFLAG_CR(G_CRBA(op) / 4) | REGFLAG_CR(G_CRBB(op) / 4); + desc->gpr.modified |= REGFLAG_CR(G_CRBD(op) / 4); + return TRUE; + + case 0x032: /* RFI */ + if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) + return FALSE; + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; + desc->targetpc = BRANCH_TARGET_DYNAMIC; + return TRUE; + + case 0x033: /* RFCI */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CHANGE_MODES | OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE | OPFLAG_CAN_CAUSE_EXCEPTION; + desc->targetpc = BRANCH_TARGET_DYNAMIC; + return TRUE; + + case 0x096: /* ISYNC */ + if (!(ppc->cap & (PPCCAP_VEA | PPCCAP_4XX))) + return FALSE; + return TRUE; + + case 0x210: /* BCCTRx */ + desc->gpr.used |= REGFLAG_CR(G_BI(op) / 4) | REGFLAG_CTR; + if (op & M_LK) desc->gpr.modified |= REGFLAG_LR; + if ((G_BO(op) & 0x14) == 0x14) + desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE; + else + desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH; + desc->targetpc = BRANCH_TARGET_DYNAMIC; + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + describe_instruction_1f - build a + description of a single instruction in the + 0x1f group +-------------------------------------------------*/ + +static int describe_instruction_1f(powerpc_state *ppc, UINT32 op, opcode_desc *desc) +{ + UINT32 opswitch = (op >> 1) & 0x3ff; + + switch (opswitch) + { + case 0x009: /* MULHDUx - 64-bit only */ + case 0x015: /* LDX - 64-bit only */ + case 0x01b: /* SLDx - 64-bit only */ + case 0x035: /* LDUX - 64-bit only */ + case 0x03a: /* CNTLZDx - 64-bit only */ + case 0x044: /* TD - 64-bit only */ + case 0x049: /* MULHDx - 64-bit only */ + case 0x054: /* LDARX - 64-bit only */ + case 0x095: /* STDX - 64-bit only */ + case 0x0b5: /* STDUX - 64-bit only */ + case 0x0d6: /* STDCX. - 64-bit only */ + case 0x0e9: /* MULLD - 64-bit only */ + case 0x2e9: /* MULLDO - 64-bit only */ + case 0x155: /* LWAX - 64-bit only */ + case 0x175: /* LWAUX - 64-bit only */ + case 0x33a: /* SRADIx - 64-bit only */ + case 0x33b: /* SRADIx - 64-bit only */ + case 0x1b2: /* SLBIE - 64-bit only */ + case 0x1c9: /* DIVDUx - 64-bit only */ + case 0x3c9: /* DIVDUOx - 64-bit only */ + case 0x1e9: /* DIVDx - 64-bit only */ + case 0x3e9: /* DIVDOx - 64-bit only */ + case 0x1f2: /* SLBIA - 64-bit only */ + case 0x21b: /* SRDx - 64-bit only */ + case 0x31a: /* SRADx - 64-bit only */ + case 0x3da: /* EXTSW - 64-bit only */ + return FALSE; + + case 0x000: /* CMP */ + case 0x020: /* CMPL */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)) | REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(G_CRFD(op)); + return TRUE; + + case 0x004: /* TW */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x008: /* SUBFCx */ + case 0x00a: /* ADDCx */ + case 0x00b: /* MULHWUx */ + case 0x028: /* SUBFx */ + case 0x04b: /* MULHWx */ + case 0x088: /* SUBFEx */ + case 0x08a: /* ADDEx */ + case 0x0c8: /* SUBFZEx */ + case 0x0ca: /* ADDZEx */ + case 0x0e8: /* SUBFMEx */ + case 0x0ea: /* ADDMEx */ + case 0x0eb: /* MULLWx */ + case 0x10a: /* ADDx */ + case 0x1cb: /* DIVWUx */ + case 0x1eb: /* DIVWx */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x208: /* SUBFCOx */ + case 0x20a: /* ADDCOx */ + case 0x228: /* SUBFOx */ + case 0x288: /* SUBFEOx */ + case 0x28a: /* ADDEOx */ + case 0x2c8: /* SUBFZEOx */ + case 0x2ca: /* ADDZEOx */ + case 0x2e8: /* SUBFMEOx */ + case 0x2ea: /* ADDMEOx */ + case 0x2eb: /* MULLWOx */ + case 0x30a: /* ADDOx */ + case 0x3cb: /* DIVWUOx */ + case 0x3eb: /* DIVWOx */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)) | REGFLAG_XER; + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x013: /* MFCR */ + desc->gpr.used |= ((REGFLAG_CR(7) << 1) - 1) & ~(REGFLAG_CR(0) - 1); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + return TRUE; + + case 0x136: /* ECIWX */ + if (!(ppc->cap & PPCCAP_VEA)) + return FALSE; + case 0x014: /* LWARX */ + case 0x017: /* LWZX */ + case 0x057: /* LBZX */ + case 0x117: /* LHZX */ + case 0x157: /* LHAX */ + case 0x216: /* LWBRX */ + case 0x316: /* LHBRX */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x018: /* SLWx */ + case 0x01c: /* ANDx */ + case 0x03c: /* ANDCx */ + case 0x07c: /* NORx */ + case 0x11c: /* EQVx */ + case 0x13c: /* XORx */ + case 0x19c: /* ORCx */ + case 0x1bc: /* ORx */ + case 0x1dc: /* NANDx */ + case 0x218: /* SRWx */ + case 0x318: /* SRAWx */ + desc->gpr.used |= REGFLAG_RZ(G_RS(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + return TRUE; + + case 0x01a: /* CNTLZWx */ + case 0x39a: /* EXTSHx */ + case 0x3ba: /* EXTSBx */ + desc->gpr.used |= REGFLAG_RZ(G_RS(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + return TRUE; + + case 0x036: /* DCBST */ + case 0x056: /* DCBF */ + case 0x0f6: /* DCBTST */ + case 0x116: /* DCBT */ + case 0x2f6: /* DCBA */ + case 0x3d6: /* ICBI */ + if (!(ppc->cap & (PPCCAP_VEA | PPCCAP_4XX))) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + return TRUE; + + case 0x1d6: /* DCBI */ + if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX))) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x037: /* LWZUX */ + case 0x077: /* LBZUX */ + case 0x137: /* LHZUX */ + case 0x177: /* LHAUX */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)) | REGFLAG_R(G_RA(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x153: /* MFSPR */ + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + if (G_SPR(op) & 0x200) + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x053: /* MFMSR */ + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return TRUE; + + case 0x253: /* MFSR */ + case 0x293: /* MFSRIN */ + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x173: /* MFTB */ + if (!(ppc->cap & PPCCAP_VEA)) + return FALSE; + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + return TRUE; + + case 0x068: /* NEGx */ + desc->gpr.used |= REGFLAG_R(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x268: /* NEGOx */ + desc->gpr.used |= REGFLAG_R(G_RA(op)); + desc->gpr.modified |= REGFLAG_R(G_RD(op)) | REGFLAG_XER; + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(0); + } + return TRUE; + + case 0x090: /* MTCRF */ + desc->gpr.used |= REGFLAG_R(G_RS(op)); + if (G_CRM(op) & 0x01) desc->gpr.modified |= REGFLAG_CR(0); + if (G_CRM(op) & 0x02) desc->gpr.modified |= REGFLAG_CR(1); + if (G_CRM(op) & 0x04) desc->gpr.modified |= REGFLAG_CR(2); + if (G_CRM(op) & 0x08) desc->gpr.modified |= REGFLAG_CR(3); + if (G_CRM(op) & 0x10) desc->gpr.modified |= REGFLAG_CR(4); + if (G_CRM(op) & 0x20) desc->gpr.modified |= REGFLAG_CR(5); + if (G_CRM(op) & 0x40) desc->gpr.modified |= REGFLAG_CR(6); + if (G_CRM(op) & 0x80) desc->gpr.modified |= REGFLAG_CR(7); + return TRUE; + + case 0x092: /* MTMSR */ + desc->gpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_CHANGE_MODES | OPFLAG_END_SEQUENCE; + return TRUE; + + case 0x0d2: /* MTSR */ + if (!(ppc->cap & PPCCAP_OEA)) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x1d3: /* MTSPR */ + desc->gpr.used |= REGFLAG_R(G_RS(op)); + if (G_SPR(op) & 0x200) + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x1b6: /* ECOWX */ + if (!(ppc->cap & PPCCAP_VEA)) + return FALSE; + case 0x096: /* STWCX. */ + case 0x097: /* STWX */ + case 0x0d7: /* STBX */ + case 0x197: /* STHX */ + case 0x296: /* STWBRX */ + case 0x396: /* STHBRX */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)) | REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x0b7: /* STWUX */ + case 0x0f7: /* STBUX */ + case 0x1b7: /* STHUX */ + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)) | REGFLAG_R(G_RS(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x0f2: /* MTSRIN */ + if (!(ppc->cap & PPCCAP_OEA)) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RS(op)) | REGFLAG_R(G_RB(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x132: /* TLBIE */ + if (!(ppc->cap & PPCCAP_OEA)) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RB(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x172: /* TLBIA */ + if (!(ppc->cap & PPCCAP_OEA) || (ppc->cap & PPCCAP_603_MMU)) + return FALSE; + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x3d2: /* TLBLD */ + case 0x3f2: /* TLBLI */ + if (!(ppc->cap & PPCCAP_603_MMU)) + return FALSE; + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x200: /* MCRXR */ + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(G_CRFD(op)); + return TRUE; + + case 0x215: /* LSWX */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)) | REGFLAG_XER; + desc->gpr.modified |= ((REGFLAG_R(31) << 1) - 1) & ~(REGFLAG_R(0) - 1); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x217: /* LFSX */ + case 0x257: /* LFDX */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x236: /* TLBSYNC */ + if (!(ppc->cap & PPCCAP_OEA)) + return FALSE; + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x256: /* SYNC */ + return TRUE; + + case 0x356: /* EIEIO */ + if (!(ppc->cap & PPCCAP_VEA)) + return FALSE; + return TRUE; + + case 0x237: /* LFSUX */ + case 0x277: /* LFDUX */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x255: /* LSWI */ + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= ((REGFLAG_R(31) << 1) - 1) & ~(REGFLAG_R(0) - 1); + desc->flags |= OPFLAG_READS_MEMORY; + return TRUE; + + case 0x295: /* STSWX */ + case 0x2d5: /* STSWI */ + desc->gpr.used |= (((REGFLAG_R(31) << 1) - 1) & ~(REGFLAG_R(0) - 1)) | REGFLAG_XER; + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x297: /* STFSX */ + case 0x2d7: /* STFDX */ + case 0x3d7: /* STFIWX */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->fpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x2b7: /* STFSUX */ + case 0x2f7: /* STFDUX */ + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_RZ(G_RA(op)); + desc->fpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x338: /* SRAWIx */ + desc->gpr.used |= REGFLAG_RZ(G_RS(op)); + desc->gpr.modified |= REGFLAG_R(G_RA(op)); + return TRUE; + + case 0x3f6: /* DCBZ */ + if (!(ppc->cap & (PPCCAP_VEA | PPCCAP_4XX))) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->flags |= OPFLAG_WRITES_MEMORY; + return TRUE; + + case 0x106: /* ICBT */ + case 0x1c6: /* DCCCI */ + case 0x3c6: /* ICCCI */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x1e6: /* DCREAD */ + case 0x3e6: /* ICREAD */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + desc->gpr.used |= REGFLAG_RZ(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_R(G_RT(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x143: /* MFDCR */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + desc->gpr.modified |= REGFLAG_R(G_RD(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION; + return TRUE; + + case 0x1c3: /* MTDCR */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_PRIVILEGED | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return TRUE; + + case 0x083: /* WRTEE */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + desc->gpr.used |= REGFLAG_R(G_RS(op)); + desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return TRUE; + + case 0x0a3: /* WRTEEI */ + if (!(ppc->cap & PPCCAP_4XX)) + return FALSE; + if (op & MSR_EE) + desc->flags |= OPFLAG_CAN_EXPOSE_EXTERNAL_INT; + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + describe_instruction_3b - build a + description of a single instruction in the + 0x3b group +-------------------------------------------------*/ + +static int describe_instruction_3b(powerpc_state *ppc, UINT32 op, opcode_desc *desc) +{ + UINT32 opswitch = (op >> 1) & 0x1f; + + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + + switch (opswitch) + { + case 0x12: /* FDIVSx */ + case 0x14: /* FSUBSx */ + case 0x15: /* FADDSx */ + case 0x19: /* FMULSx */ + desc->fpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + + case 0x16: /* FSQRTSx */ + case 0x18: /* FRESx */ + desc->fpr.used |= REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + + case 0x1c: /* FMSUBSx */ + case 0x1d: /* FMADDSx */ + case 0x1e: /* FNMSUBSx */ + case 0x1f: /* FNMADDSx */ + desc->fpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)) | REGFLAG_R(G_REGC(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + } + + return FALSE; +} + + +/*------------------------------------------------- + describe_instruction_3f - build a + description of a single instruction in the + 0x3f group +-------------------------------------------------*/ + +static int describe_instruction_3f(powerpc_state *ppc, UINT32 op, opcode_desc *desc) +{ + UINT32 opswitch = (op >> 1) & 0x3ff; + + if (!(ppc->cap & PPCCAP_FPU)) + return FALSE; + + if (opswitch & 0x10) + { + opswitch &= 0x1f; + switch (opswitch) + { + case 0x12: /* FDIVx */ + case 0x14: /* FSUBx */ + case 0x15: /* FADDx */ + case 0x19: /* FMULx */ + desc->fpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + + case 0x16: /* FSQRTx */ + case 0x1a: /* FSQRTEx */ + desc->fpr.used |= REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + + case 0x17: /* FSELx */ + case 0x1c: /* FMSUBx */ + case 0x1d: /* FMADDx */ + case 0x1e: /* FNMSUBx */ + case 0x1f: /* FNMADDx */ + desc->fpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)) | REGFLAG_R(G_REGC(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + } + } + else + { + switch (opswitch) + { + case 0x32e: /* FCTIDx - 64-bit only */ + case 0x32f: /* FCTIDZx - 64-bit only */ + case 0x34e: /* FCFIDx - 64-bit only */ + return FALSE; + + case 0x000: /* FCMPU */ + case 0x020: /* FCMPO */ + desc->gpr.used |= REGFLAG_XER; + desc->fpr.used |= REGFLAG_R(G_RA(op)) | REGFLAG_R(G_RB(op)); + desc->gpr.modified |= REGFLAG_CR(G_CRFD(op)); + return TRUE; + + case 0x00c: /* FRSPx */ + case 0x00e: /* FCTIWx */ + case 0x00f: /* FCTIWZx */ + case 0x028: /* FNEGx */ + case 0x048: /* FMRx */ + case 0x088: /* FNABSx */ + case 0x108: /* FABSx */ + desc->fpr.used |= REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + if (op & M_RC) + { + desc->gpr.used |= REGFLAG_XER; + desc->gpr.modified |= REGFLAG_CR(1); + } + return TRUE; + + case 0x026: /* MTFSB1x */ + case 0x046: /* MTFSB0x */ + desc->fpr.modified |= REGFLAG_FPSCR; + return TRUE; + + case 0x040: /* MCRFS */ + desc->fpr.used |= REGFLAG_FPSCR; + desc->gpr.modified |= REGFLAG_CR(G_CRFD(op)); + return TRUE; + + case 0x086: /* MTFSFIx */ + desc->fpr.modified |= REGFLAG_FPSCR; + return TRUE; + + case 0x247: /* MFFSx */ + desc->fpr.used |= REGFLAG_FPSCR; + desc->fpr.modified |= REGFLAG_R(G_RD(op)); + return TRUE; + + case 0x2c7: /* MTFSFx */ + desc->fpr.used |= REGFLAG_R(G_RB(op)); + desc->fpr.modified |= REGFLAG_FPSCR; + return TRUE; + } + } + + return FALSE; +} diff --git a/src/emu/cpu/powerpc/ppcfe.h b/src/emu/cpu/powerpc/ppcfe.h new file mode 100644 index 00000000000..7c96d22f64f --- /dev/null +++ b/src/emu/cpu/powerpc/ppcfe.h @@ -0,0 +1,40 @@ +/*************************************************************************** + + ppcfe.h + + Front-end for PowerPC recompiler + + Copyright Aaron Giles + Released for general non-commercial use under the MAME license + Visit http://mamedev.org for licensing and usage restrictions. + +***************************************************************************/ + +#ifndef __PPCFE_H__ +#define __PPCFE_H__ + +#include "cpu/drcfe.h" + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* register flags */ +#define REGFLAG_R(n) ((UINT64)1 << (n)) +#define REGFLAG_RZ(n) (((n) == 0) ? 0 : REGFLAG_R(n)) +#define REGFLAG_CR(n) REGFLAG_R(32 + (n)) +#define REGFLAG_XER REGFLAG_R(40) +#define REGFLAG_CTR REGFLAG_R(41) +#define REGFLAG_LR REGFLAG_R(42) +#define REGFLAG_FPSCR REGFLAG_R(32) + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +int ppcfe_describe(void *param, opcode_desc *desc); + +#endif diff --git a/src/emu/cpu/x64drc.c b/src/emu/cpu/x64drc.c deleted file mode 100644 index 266edce7fba..00000000000 --- a/src/emu/cpu/x64drc.c +++ /dev/null @@ -1,633 +0,0 @@ -/*************************************************************************** - - x64drc.c - - x64 Dynamic recompiler support routines. - - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. - -**************************************************************************** - - Windows x64 conventions: - - Register Status Use - -------- ------ --- - RAX Volatile Return value register - RCX Volatile First integer argument - RDX Volatile Second integer argument - R8 Volatile Third integer argument - R9 Volatile Fourth integer argument - R10:R11 Volatile Must be preserved as needed by caller; used in syscall/sysret instructions - R12:R15 Nonvolatile Must be preserved by callee - RDI Nonvolatile Must be preserved by callee - RSI Nonvolatile Must be preserved by callee - RBX Nonvolatile Must be preserved by callee - RBP Nonvolatile May be used as a frame pointer; must be preserved by callee - RSP Nonvolatile Stack pointer - - XMM0 Volatile First FP argument - XMM1 Volatile Second FP argument - XMM2 Volatile Third FP argument - XMM3 Volatile Fourth FP argument - XMM4:XMM5 Volatile Must be preserved as needed by caller - XMM6:XMM15 Nonvolatile Must be preserved as needed by callee. - - - Linux/MacOS x64 conventions: - - Register Status Use - -------- ------ --- - RAX Volatile Return value register - RDI Volatile First integer argument - RSI Volatile Second integer argument - RDX Volatile Third integer argument - RCX Volatile Fourth integer argument - R8 Volatile Fifth integer argument - R9 Volatile Sixth integer argument - R10:R11 Volatile Must be preserved as needed by caller - R12:R15 Nonvolatile Must be preserved by callee - RBX Nonvolatile Must be preserved by callee - RBP Nonvolatile Must be preserved by callee - RSP Nonvolatile Stack pointer - - XMM0 Volatile First FP argument - XMM1 Volatile Second FP argument - XMM2 Volatile Third FP argument - XMM3 Volatile Fourth FP argument - XMM4 Volatile Fifth FP argument - XMM5 Volatile Sixth FP argument - XMM6:XMM15 Volatile Must be preserved as needed by caller. - -***************************************************************************/ - -#include "cpuintrf.h" -#include "x64drc.h" -#include "debugger.h" - -#ifdef ENABLE_DEBUGGER -#include "deprecat.h" -#endif - - - -/*************************************************************************** - MACROS -***************************************************************************/ - -#define MXCSR_VALUE(x) (0x1fc0 | ((x) << 14)) - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -static void append_entry_point(drc_core *drc); -static void append_exit_point(drc_core *drc); -static void recompile_code(drc_core *drc); -static void append_recompile(drc_core *drc); -static void append_flush(drc_core *drc); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - allocate_l2_table - allocate an L2 table - if necessary --------------------------------------------------*/ - -INLINE void allocate_l2_table(drc_core *drc, UINT32 l1index) -{ - if (drc->lookup_l1[l1index] == drc->lookup_l2_recompile) - { - /* create a new copy of the recompile table */ - drc->lookup_l1[l1index] = drc_alloc(drc, sizeof(*drc->lookup_l2_recompile) << drc->l2bits); - memcpy(drc->lookup_l1[l1index], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) << drc->l2bits); - } -} - - -/*************************************************************************** - EXTERNAL INTERFACES -***************************************************************************/ - -/*------------------------------------------------- - drc_init - initialize the DRC core --------------------------------------------------*/ - -drc_core *drc_init(UINT8 cpunum, drc_config *config) -{ - int address_bits = config->address_bits; - int effective_address_bits = address_bits - config->lsbs_to_ignore; - drc_core *drc; - int i; - - /* the drc structure lives at the start of the cache */ - drc = (drc_core *)config->cache_base; - memset(drc, 0, sizeof(*drc)); - - /* copy in relevant data from the config */ - drc->baseptr = config->baseptr; - drc->pcptr = config->pcptr; - drc->cb_reset = config->cb_reset; - drc->cb_recompile = config->cb_recompile; - drc->cb_entrygen = config->cb_entrygen; - drc->mxcsr_curr = MXCSR_VALUE(FPRND_NEAR); - - /* configure cache */ - drc->cache_base = (UINT8 *)config->cache_base + sizeof(*drc); - drc->cache_size = config->cache_size - sizeof(*drc); - drc->cache_end = drc->cache_base + drc->cache_size; - drc->cache_danger = drc->cache_end - 65536; - - /* compute shifts and masks */ - drc->l1bits = effective_address_bits / 2; - drc->l2bits = effective_address_bits - drc->l1bits; - drc->l1shift = config->lsbs_to_ignore + drc->l2bits; - drc->l2mask = ((1 << drc->l2bits) - 1) << config->lsbs_to_ignore; - drc->l2scale = sizeof(x86code *) >> config->lsbs_to_ignore; - - /* configure the MXCSR states */ - for (i = 0; i < 4; i++) - drc->mxcsr_values[i] = MXCSR_VALUE(i); - - /* allocate lookup tables out of the cache */ - drc->lookup_l1 = drc_alloc(drc, sizeof(*drc->lookup_l1) << drc->l1bits); - drc->lookup_l2_recompile = drc_alloc(drc, sizeof(*drc->lookup_l2_recompile) << drc->l2bits); - if (drc->lookup_l1 == NULL || drc->lookup_l2_recompile == NULL) - goto error; - memset(drc->lookup_l1, 0, sizeof(*drc->lookup_l1) << drc->l1bits); - memset(drc->lookup_l2_recompile, 0, sizeof(*drc->lookup_l2_recompile) << drc->l2bits); - - /* allocate the sequence and tentative lists */ - drc->sequence_count_max = config->max_instructions * 2; - drc->sequence_list = malloc(drc->sequence_count_max * sizeof(*drc->sequence_list)); - if (drc->sequence_list == NULL) - goto error; - - drc->tentative_count_max = config->max_instructions * 2; - drc->tentative_list = malloc(drc->tentative_count_max * sizeof(*drc->tentative_list)); - if (drc->tentative_list == NULL) - goto error; - - /* get pointers to external C functions */ -#ifdef ENABLE_DEBUGGER - drc->mame_debug_hook = (x86code *)mame_debug_hook; -#endif - drc->recompile_code = (x86code *)recompile_code; - drc->drc_cache_reset = (x86code *)drc_cache_reset; - return drc; - -error: - if (drc != NULL) - drc_exit(drc); - return NULL; -} - - -/*------------------------------------------------- - drc_alloc - allocate memory from the top of - the DRC cache --------------------------------------------------*/ - -void *drc_alloc(drc_core *drc, size_t amount) -{ - /* if we don't have enough space, reset the cache */ - if (drc->cache_top >= drc->cache_danger - amount) - drc_cache_reset(drc); - - /* if we still don't have enough space, fail */ - if (drc->cache_top >= drc->cache_danger - amount) - return NULL; - - /* adjust the end and danger values downward */ - drc->cache_end -= amount; - drc->cache_danger -= amount; - return drc->cache_end; -} - - -/*------------------------------------------------- - drc_cache_reset - reset the DRC cache --------------------------------------------------*/ - -void drc_cache_reset(drc_core *drc) -{ - int i; - - /* reset the cache and add the basics */ - drc->cache_top = drc->cache_base; - - /* append the core entry points to the fresh cache */ - drc->entry_point = (void (*)(void *))(FPTR)drc->cache_top; - append_entry_point(drc); - drc->exit_point = drc->cache_top; - append_exit_point(drc); - drc->recompile = drc->cache_top; - append_recompile(drc); - drc->dispatch = drc->cache_top; - drc_append_dispatcher(drc); - drc->flush = drc->cache_top; - append_flush(drc); - - /* populate the recompile table */ - for (i = 0; i < (1 << drc->l2bits); i++) - drc->lookup_l2_recompile[i] = drc->recompile; - - /* reset all the l1 tables */ - for (i = 0; i < (1 << drc->l1bits); i++) - { - /* point NULL entries to the generic recompile table */ - if (drc->lookup_l1[i] == NULL) - drc->lookup_l1[i] = drc->lookup_l2_recompile; - - /* reset allocated tables to point all entries back to the recompiler */ - else if (drc->lookup_l1[i] != drc->lookup_l2_recompile) - memcpy(drc->lookup_l1[i], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) << drc->l2bits); - } - - /* call back to the host */ - if (drc->cb_reset != NULL) - (*drc->cb_reset)(drc); -} - - -/*------------------------------------------------- - drc_execute - execute generated code --------------------------------------------------*/ - -void drc_execute(drc_core *drc) -{ - (*drc->entry_point)(drc->baseptr); -} - - -/*------------------------------------------------- - drc_exit - release resources allocated by - the DRC core --------------------------------------------------*/ - -void drc_exit(drc_core *drc) -{ - /* free the lists */ - if (drc->sequence_list != NULL) - free(drc->sequence_list); - if (drc->tentative_list != NULL) - free(drc->tentative_list); -} - - -/*------------------------------------------------- - drc_begin_sequence - begin code generation - for a particular PC --------------------------------------------------*/ - -void drc_begin_sequence(drc_core *drc, UINT32 pc) -{ - /* reset the sequence and tentative counts */ - drc->sequence_count = 0; - drc->tentative_count = 0; -} - - -/*------------------------------------------------- - drc_add_entry_point - add a new external - entry point for a given PC --------------------------------------------------*/ - -int drc_add_entry_point(drc_core *drc, UINT32 pc, int override) -{ - UINT32 l1index = pc >> drc->l1shift; - UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / sizeof(x86code *); - int was_occupied; - - /* allocate memory if necessary */ - allocate_l2_table(drc, l1index); - - /* in case anybody was jumping directly to this code entry, replace - the code with a jmp to the new code */ - was_occupied = (drc->lookup_l1[l1index][l2index] != drc->recompile); - if (was_occupied && override) - { - x86code *dest = drc->lookup_l1[l1index][l2index]; - emit_jmp(&dest, drc->cache_top); - } - - /* note the current location for this instruction */ - if (!was_occupied || override) - drc->lookup_l1[l1index][l2index] = drc->cache_top; - return was_occupied; -} - - -/*------------------------------------------------------------------ - drc_end_sequence -------------------------------------------------------------------*/ - -void drc_end_sequence(drc_core *drc) -{ - int i, j; - - /* fix up any internal links */ - for (i = 0; i < drc->tentative_count; i++) - { - for (j = 0; j < drc->sequence_count; j++) - if (drc->tentative_list[i].pc == drc->sequence_list[j].pc) - { - x86code *dest = drc->tentative_list[i].target; - emit_jmp(&dest, drc->sequence_list[j].target); - while (dest < drc->tentative_list[i].end) - emit_int_3(&dest); - break; - } - } -} - - -/*------------------------------------------------------------------ - drc_register_code_at_cache_top -------------------------------------------------------------------*/ - -void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc) -{ - pc_ptr_pair *pair = &drc->sequence_list[drc->sequence_count++]; - assert_always(drc->sequence_count <= drc->sequence_count_max, "drc_register_code_at_cache_top: too many instructions!"); - - pair->target = drc->cache_top; - pair->pc = pc; -} - - -/*------------------------------------------------------------------ - drc_get_code_at_pc -------------------------------------------------------------------*/ - -x86code *drc_get_code_at_pc(drc_core *drc, UINT32 pc) -{ - UINT32 l1index = pc >> drc->l1shift; - UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / sizeof(x86code *); - x86code *codeptr = drc->lookup_l1[l1index][l2index]; - return (codeptr != drc->recompile) ? codeptr : NULL; -} - - -/*------------------------------------------------------------------ - drc_invalidate_code_range -------------------------------------------------------------------*/ - -void drc_invalidate_code_range(drc_core *drc, UINT32 startpc, UINT32 endpc) -{ - UINT32 startl1index = startpc >> drc->l1shift; - UINT32 startl2index = ((startpc & drc->l2mask) * drc->l2scale) / sizeof(x86code *); - UINT32 endl1index = endpc >> drc->l1shift; - UINT32 endl2index = ((endpc & drc->l2mask) * drc->l2scale) / sizeof(x86code *); - UINT32 curl1; - - /* iterate over l1 bunches */ - for (curl1 = startl1index; curl1 <= endl1index; curl1++) - { - x86code **l2table = drc->lookup_l1[curl1]; - UINT32 l2start, l2end, curl2; - - /* if this is already empty, skip it */ - if (l2table == drc->lookup_l2_recompile) - continue; - - /* determine start/stop for this range */ - l2start = (curl1 == startl1index) ? startl2index : 0; - l2end = (curl1 == endl1index) ? endl2index : ((1 << drc->l2bits) - 1); - - /* invalidate any code entries here */ - for (curl2 = l2start; curl2 <= l2end; curl2++) - if (l2table[curl2] != drc->recompile) - { - /* overwrite code there with a jump to the recompiler in case we ever get there */ - x86code *dest = l2table[curl2]; -// emit_int_3(&dest); - emit_jmp(&dest, drc->recompile); - l2table[curl2] = drc->recompile; - } - } -} - - -/*------------------------------------------------------------------ - drc_append_call_debugger -------------------------------------------------------------------*/ - -void drc_append_call_debugger(drc_core *drc) -{ -#ifdef ENABLE_DEBUGGER - if (Machine->debug_mode) - emit_call_m64(DRCTOP, MDRC(&drc->mame_debug_hook)); // call mame_debug_hook -#endif -} - - -/*------------------------------------------------------------------ - drc_append_dispatcher -------------------------------------------------------------------*/ - -void drc_append_dispatcher(drc_core *drc) -{ - /* target PC is in P1 on entry; we must keep P1 intact in case we jump to the recompile callback */ - emit_mov_r32_r32(DRCTOP, REG_P2, REG_P1); // mov p2,p1 - emit_mov_r32_r32(DRCTOP, REG_EAX, REG_P1); // mov eax,p1 - emit_shr_r32_imm(DRCTOP, REG_P2, drc->l1shift); // shr p2,l1shift - emit_mov_r64_m64(DRCTOP, REG_P2, MDRCISD(drc->lookup_l1, REG_P2, 8, 0)); // mov p2,[rbp+p2*8+l1lookup] - emit_and_r32_imm(DRCTOP, REG_EAX, drc->l2mask); // and eax,l2mask - emit_jmp_m64(DRCTOP, MBISD(REG_P2, REG_EAX, drc->l2scale, 0)); // jmp [p2 + eax*l2scale] -} - - -/*------------------------------------------------------------------ - drc_append_fixed_dispatcher -------------------------------------------------------------------*/ - -void drc_append_fixed_dispatcher(drc_core *drc, UINT32 pc, int loadpc) -{ - UINT32 l1index = pc >> drc->l1shift; - UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / sizeof(x86code *); - - /* make sure we have an L2 table for this entry */ - allocate_l2_table(drc, l1index); - - /* emit a jump through the table entry */ - if (loadpc) - emit_mov_r32_imm(DRCTOP, REG_P1, pc); // mov p1,pc - emit_jmp_m64(DRCTOP, MDRC(&drc->lookup_l1[l1index][l2index])); // jmp [lookup[l1index][l2index]] -} - - -/*------------------------------------------------------------------ - drc_append_tentative_fixed_dispatcher -------------------------------------------------------------------*/ - -void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc, int loadpc) -{ - pc_ptr_pair *pair = &drc->tentative_list[drc->tentative_count++]; - assert_always(drc->tentative_count <= drc->tentative_count_max, "drc_append_tentative_fixed_dispatcher: too many tentative branches!"); - - pair->target = drc->cache_top; - pair->pc = newpc; - drc_append_fixed_dispatcher(drc, newpc, loadpc); - pair->end = drc->cache_top; -} - - -/*------------------------------------------------------------------ - drc_append_set_sse_rounding -------------------------------------------------------------------*/ - -void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex) -{ - emit_ldmxcsr_m32(DRCTOP, MDRCISD(&drc->mxcsr_values[0], regindex, 4, 0)); // ldmxcsr [mxcsr_values + reg*4] - emit_stmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_curr)); // stmxcsr [mxcsr_curr] -} - - - -/*------------------------------------------------------------------ - drc_append_set_temp_sse_rounding -------------------------------------------------------------------*/ - -void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding) -{ - emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_values[rounding])); // ldmxcsr mxcsr_values[rounding] -} - - - -/*------------------------------------------------------------------ - drc_append_restore_sse_rounding -------------------------------------------------------------------*/ - -void drc_append_restore_sse_rounding(drc_core *drc) -{ - emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr] -} - - - -/*************************************************************************** - INTERNAL CODEGEN -***************************************************************************/ - -/*------------------------------------------------------------------ - append_entry_point -------------------------------------------------------------------*/ - -static void append_entry_point(drc_core *drc) -{ - int pushbytes = 8 * (6 + (REG_NV5 != REG_NONE) + (REG_NV6 != REG_NONE)); - - /* save non-volatile registers */ - emit_push_r64(DRCTOP, REG_DRC); // push drc - emit_push_r64(DRCTOP, REG_NV0); // push nv0 - emit_push_r64(DRCTOP, REG_NV1); // push nv1 - emit_push_r64(DRCTOP, REG_NV2); // push nv2 - emit_push_r64(DRCTOP, REG_NV3); // push nv3 - emit_push_r64(DRCTOP, REG_NV4); // push nv4 - if (REG_NV5 != REG_NONE) emit_push_r64(DRCTOP, REG_NV5); // push nv5 - if (REG_NV6 != REG_NONE) emit_push_r64(DRCTOP, REG_NV6); // push nv6 - - /* stack frame: - 0x40/0x48 bytes of scratch space/alignment - 0x20 bytes for register parameter spilling in Windows ABI - */ - emit_sub_r64_imm(DRCTOP, REG_RSP, 0x68 + (pushbytes % 16)); // sub rsp,0x68/0x70 - - /* parameter 1 is the baseptr; copy to RBP */ - emit_mov_r64_r64(DRCTOP, REG_DRC, REG_P1); // mov rbp,p1 - - /* update the MXCSR register */ - emit_stmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_save)); // stmxcsr [mxcsr_save] - emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr] - - /* continue performing entry generation duties */ - if (drc->cb_entrygen != NULL) - (*drc->cb_entrygen)(drc); // additional entry point duties - - /* reload the PC into P1 and dispatch */ - emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc] - drc_append_dispatcher(drc); // dispatch -} - - -/*------------------------------------------------------------------ - append_exit_point -------------------------------------------------------------------*/ - -static void append_exit_point(drc_core *drc) -{ - int pushbytes = 8 * (6 + (REG_NV5 != REG_NONE) + (REG_NV6 != REG_NONE)); - - /* on exit, P1 must contain the final PC */ - emit_mov_m32_r32(DRCTOP, MDRC(drc->pcptr), REG_P1); // mov [pc],p1 - - /* restore the MXCSR state */ - emit_ldmxcsr_m32(DRCTOP, MDRC(&drc->mxcsr_save)); // ldmxcsr [mxcsr_save] - - /* add 0x18 to RSP to get us back to the original stack pointer */ - emit_add_r64_imm(DRCTOP, REG_RSP, 0x68 + (pushbytes % 16)); // add rsp,0x68/0x70 - - /* save non-volatile registers */ - if (REG_NV6 != REG_NONE) emit_pop_r64(DRCTOP, REG_NV6); // pop nv6 - if (REG_NV5 != REG_NONE) emit_pop_r64(DRCTOP, REG_NV5); // pop nv5 - emit_pop_r64(DRCTOP, REG_NV4); // pop nv4 - emit_pop_r64(DRCTOP, REG_NV3); // pop nv3 - emit_pop_r64(DRCTOP, REG_NV2); // pop nv2 - emit_pop_r64(DRCTOP, REG_NV1); // pop nv1 - emit_pop_r64(DRCTOP, REG_NV0); // pop nv0 - emit_pop_r64(DRCTOP, REG_DRC); // pop drc - emit_ret(DRCTOP); // ret -} - - -/*------------------------------------------------------------------ - recompile_code -------------------------------------------------------------------*/ - -static void recompile_code(drc_core *drc) -{ - /* if we're above the danger line, flush the cache before recompiling */ - if (drc->cache_top >= drc->cache_danger) - drc_cache_reset(drc); - - /* call the recompile callback */ - (*drc->cb_recompile)(drc); -} - - -/*------------------------------------------------------------------ - append_recompile -------------------------------------------------------------------*/ - -static void append_recompile(drc_core *drc) -{ - /* on entry, P1 must contain the PC that needs recompilation */ - emit_mov_m32_r32(DRCTOP, MDRC(drc->pcptr), REG_P1); // mov [pc],p1 - emit_lea_r64_m64(DRCTOP, REG_P1, MDRC(drc)); // lea p1,drc - emit_call_m64(DRCTOP, MDRC(&drc->recompile_code)); // call recompile_code - emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc] - drc_append_dispatcher(drc); // dispatch -} - - -/*------------------------------------------------------------------ - append_flush -------------------------------------------------------------------*/ - -static void append_flush(drc_core *drc) -{ - /* on entry, P1 must contain the PC that needs recompilation */ - emit_mov_m32_r32(DRCTOP, MDRC(drc->pcptr), REG_P1); // mov [pc],p1 - emit_lea_r64_m64(DRCTOP, REG_P1, MDRC(drc)); // lea p1,drc - emit_call_m64(DRCTOP, MDRC(&drc->drc_cache_reset)); // call drc_cache_reset - emit_mov_r32_m32(DRCTOP, REG_P1, MDRC(drc->pcptr)); // mov p1,[pc] - drc_append_dispatcher(drc); // dispatch -} diff --git a/src/emu/cpu/x64drc.h b/src/emu/cpu/x64drc.h deleted file mode 100644 index 7a949949f60..00000000000 --- a/src/emu/cpu/x64drc.h +++ /dev/null @@ -1,223 +0,0 @@ -/*************************************************************************** - - x64drc.h - - x64 Dynamic recompiler support routines. - - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. - -***************************************************************************/ - -#pragma once - -#ifndef __X64DRC_H__ -#define __X64DRC_H__ - -#include "cpuintrf.h" -#include "x86emit.h" - - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -/* ABI-specific configuration */ -#define REG_DRC REG_RBP /* pointer to DRC base */ - -#ifdef X64_WINDOWS_ABI - -#define REG_P1 REG_RCX /* 1st function parameter */ -#define REG_P2 REG_RDX /* 2nd function parameter */ -#define REG_P3 REG_R8 /* 3rd function parameter */ -#define REG_P4 REG_R9 /* 4th function parameter */ -#define REG_V5 REG_R10 /* volatile register 5 */ -#define REG_V6 REG_R11 /* volatile register 6 */ - -#define NUM_NVREG 7 /* number of non-volatile registers */ -#define REG_NV0 REG_RBX /* non-volatile reg 0 */ -#define REG_NV1 REG_RDI /* non-volatile reg 1 */ -#define REG_NV2 REG_RSI /* non-volatile reg 2 */ -#define REG_NV3 REG_R12 /* non-volatile reg 3 */ -#define REG_NV4 REG_R13 /* non-volatile reg 4 */ -#define REG_NV5 REG_R14 /* non-volatile reg 5 */ -#define REG_NV6 REG_R15 /* non-volatile reg 6 */ - -#else - -#define REG_P1 REG_RDI /* 1st function parameter */ -#define REG_P2 REG_RSI /* 2nd function parameter */ -#define REG_P3 REG_RDX /* 3rd function parameter */ -#define REG_P4 REG_RCX /* 4th function parameter */ -#define REG_V5 REG_R10 /* volatile register 5 */ -#define REG_V6 REG_R11 /* volatile register 6 */ - -#define NUM_NVREG 5 /* number of non-volatile registers */ -#define REG_NV0 REG_RBX /* non-volatile reg 0 */ -#define REG_NV1 REG_R12 /* non-volatile reg 1 */ -#define REG_NV2 REG_R13 /* non-volatile reg 2 */ -#define REG_NV3 REG_R14 /* non-volatile reg 3 */ -#define REG_NV4 REG_R15 /* non-volatile reg 4 */ -#define REG_NV5 REG_NONE /* non-volatile reg 5 */ -#define REG_NV6 REG_NONE /* non-volatile reg 6 */ - -#endif - - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* PC and pointer pair */ -typedef struct _pc_ptr_pair pc_ptr_pair; -struct _pc_ptr_pair -{ - UINT32 pc; - x86code * target; - x86code * end; -}; - - -/* core interface structure for the drc common code */ -typedef struct _drc_core drc_core; -struct _drc_core -{ - /* cache parameters */ - x86code * cache_base; /* base pointer to the compiler cache */ - x86code * cache_top; /* current top of cache */ - x86code * cache_danger; /* high water mark for the end */ - x86code * cache_end; /* end of cache memory */ - size_t cache_size; /* cache allocated size */ - - /* hash table lookups */ - x86code *** lookup_l1; /* level 1 lookup */ - x86code ** lookup_l2_recompile; /* level 2 lookup populated with recompile pointers */ - UINT8 l1bits; /* number of bits in level 1 lookup */ - UINT8 l2bits; /* number of bits in level 2 lookup */ - UINT8 l1shift; /* shift to go from PC to level 1 lookup */ - UINT32 l2mask; /* mask to go from PC to level 2 lookup */ - UINT8 l2scale; /* scale to get from masked PC value to final level 2 lookup */ - - /* entry point for calling from C code */ - void (*entry_point)(void *); /* pointer to asm entry point */ - - /* base pointer for memory accesses */ - void * baseptr; /* pointer to base; all cache must be accessible from here */ - - /* internal subroutines generated in the cache */ - x86code * exit_point; /* exit out of the DRC engine */ - x86code * recompile; /* pointer to recompile jump point */ - x86code * dispatch; /* pointer to dispatch jump point */ - x86code * flush; /* pointer to flush jump point */ - - /* pointers to external C code */ - x86code * mame_debug_hook; /* pointer to mame_debug_hook function */ - x86code * recompile_code; /* pointer to recompile_code function */ - x86code * drc_cache_reset; /* pointer to drc_cache_reset function */ - - /* pointers to the PC */ - UINT32 * pcptr; /* pointer to where the PC is stored */ - - /* save areas for the MXCSR register */ - UINT32 mxcsr_curr; /* current SSE control word */ - UINT32 mxcsr_save; /* saved SSE control word */ - UINT32 mxcsr_values[4]; /* array of values for different modes */ - - /* internal lists of sequences and tentative branches */ - pc_ptr_pair * sequence_list; /* PC/pointer sets for the current instruction sequence */ - UINT32 sequence_count; /* number of instructions in the current sequence */ - UINT32 sequence_count_max; /* max number of instructions in the current sequence */ - pc_ptr_pair * tentative_list; /* PC/pointer sets for tentative branches */ - UINT32 tentative_count; /* number of tentative branches */ - UINT32 tentative_count_max; /* max number of tentative branches */ - - /* CPU-specific callbacks */ - void (*cb_reset)(struct _drc_core *drc); /* callback when the cache is reset */ - void (*cb_recompile)(struct _drc_core *drc); /* callback when code needs to be recompiled */ - void (*cb_entrygen)(struct _drc_core *drc); /* callback before generating the dispatcher on entry */ -}; - - -/* configuration structure for the drc common code */ -typedef struct _drc_config drc_config; -struct _drc_config -{ - void * cache_base; /* base of cache */ - UINT32 cache_size; /* size of cache */ - UINT32 max_instructions; /* maximum instructions per sequence */ - UINT8 address_bits; /* number of live address bits in the PC */ - UINT8 lsbs_to_ignore; /* number of LSBs to ignore on the PC */ - - void * baseptr; /* pointer to base; all cache must be accessible from here */ - UINT32 * pcptr; /* pointer to where the PC is stored */ - - void (*cb_reset)(drc_core *drc); /* callback when the cache is reset */ - void (*cb_recompile)(drc_core *drc); /* callback when code needs to be recompiled */ - void (*cb_entrygen)(drc_core *drc); /* callback before generating the dispatcher on entry */ -}; - - - -/*************************************************************************** - MACROS -***************************************************************************/ - -/* use this macro in emit_* instructions to make them shorter */ -#define DRCTOP &drc->cache_top - -/* memory references to DRC-relative data */ -#define MDRC(x) MBD(REG_DRC, drcrel32(drc->baseptr, (x))) -#define MDRCD(x, disp) MBD(REG_DRC, drcrel32(drc->baseptr, (x)) + (disp)) -#define MDRCISD(x, index, scale, disp) MBISD(REG_DRC, (index), (scale), drcrel32(drc->baseptr, (x)) + (disp)) - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* init/shutdown */ -drc_core *drc_init(UINT8 cpunum, drc_config *config); -void *drc_alloc(drc_core *drc, size_t amount); -void drc_cache_reset(drc_core *drc); -void drc_execute(drc_core *drc); -void drc_exit(drc_core *drc); - -/* code management */ -void drc_begin_sequence(drc_core *drc, UINT32 pc); -int drc_add_entry_point(drc_core *drc, UINT32 pc, int override); -void drc_end_sequence(drc_core *drc); -void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc); -x86code *drc_get_code_at_pc(drc_core *drc, UINT32 pc); -void drc_invalidate_code_range(drc_core *drc, UINT32 startpc, UINT32 endpc); - -/* standard appendages */ -void drc_append_dispatcher(drc_core *drc); -void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc, int loadpc); -void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc, int loadpc); -void drc_append_call_debugger(drc_core *drc); -void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex); -void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding); -void drc_append_restore_sse_rounding(drc_core *drc); - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -INLINE INT32 drcrel32(void *base, void *ptr) -{ - INT64 delta = (UINT8 *)ptr - (UINT8 *)base; - assert((INT32)delta == delta); - return (INT32)delta; -} - -INLINE void *drcrelptr(drc_core *drc, INT32 offset) -{ - return (UINT8 *)drc + offset; -} - -#endif /* __X64DRC_H__ */ diff --git a/src/emu/cpu/x86drc.c b/src/emu/cpu/x86drc.c deleted file mode 100644 index 03d3aa90f8e..00000000000 --- a/src/emu/cpu/x86drc.c +++ /dev/null @@ -1,767 +0,0 @@ -/*************************************************************************** - - x86drc.c - - x86 Dynamic recompiler support routines. - - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. - -***************************************************************************/ - -#include "debugger.h" -#include "deprecat.h" -#include "x86drc.h" - -#define LOG_DISPATCHES 0 -#define BREAK_ON_MODIFIED_CODE 0 - - - - -static const UINT16 fp_control[4] = { 0x023f, 0x063f, 0x0a3f, 0x0e3f }; -static const UINT32 sse_control[4] = { 0x9fc0, 0xbfc0, 0xdfc0, 0xffc0 }; - - -static void append_entry_point(drc_core *drc); -static void append_recompile(drc_core *drc); -static void append_flush(drc_core *drc); -static void append_out_of_cycles(drc_core *drc); - -#if LOG_DISPATCHES -static void log_dispatch(drc_core *drc); -#endif - - - -/*************************************************************************** - EXTERNAL INTERFACES -***************************************************************************/ - -/*------------------------------------------------- - drc_init - initialize the DRC core --------------------------------------------------*/ - -drc_core *drc_init(UINT8 cpunum, drc_config *config) -{ - int address_bits = config->address_bits; - int effective_address_bits = address_bits - config->lsbs_to_ignore; - UINT8 cache_allocated = FALSE; - drc_core *drc = NULL; - - /* allocate memory */ - if (config->cache_base == NULL) - { - config->cache_base = osd_alloc_executable(config->cache_size); - if (config->cache_base == NULL) - goto error; - cache_allocated = TRUE; - } - - /* the drc structure lives at the start of the cache */ - drc = (drc_core *)config->cache_base; - memset(drc, 0, sizeof(*drc)); - - /* copy in relevant data from the config */ - drc->pcptr = config->pcptr; - drc->icountptr = config->icountptr; - drc->esiptr = config->esiptr; - drc->cb_reset = config->cb_reset; - drc->cb_recompile = config->cb_recompile; - drc->cb_entrygen = config->cb_entrygen; - drc->uses_fp = config->uses_fp; - drc->uses_sse = config->uses_sse; - drc->pc_in_memory = config->pc_in_memory; - drc->icount_in_memory = config->icount_in_memory; - drc->fpcw_curr = fp_control[0]; - drc->mxcsr_curr = sse_control[0]; - - /* configure cache */ - drc->cache_base = (UINT8 *)config->cache_base + sizeof(*drc); - drc->cache_size = config->cache_size - sizeof(*drc); - drc->cache_end = drc->cache_base + drc->cache_size; - drc->cache_danger = drc->cache_end - 65536; - drc->cache_allocated = cache_allocated; - - /* compute shifts and masks */ - drc->l1bits = effective_address_bits/2; - drc->l2bits = effective_address_bits - drc->l1bits; - drc->l1shift = config->lsbs_to_ignore + drc->l2bits; - drc->l2mask = ((1 << drc->l2bits) - 1) << config->lsbs_to_ignore; - drc->l2scale = 4 >> config->lsbs_to_ignore; - - /* allocate lookup tables */ - drc->lookup_l1 = malloc(sizeof(*drc->lookup_l1) * (1 << drc->l1bits)); - drc->lookup_l2_recompile = malloc(sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); - if (drc->lookup_l1 == NULL || drc->lookup_l2_recompile == NULL) - goto error; - memset(drc->lookup_l1, 0, sizeof(*drc->lookup_l1) * (1 << drc->l1bits)); - memset(drc->lookup_l2_recompile, 0, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); - - /* allocate the sequence and tentative lists */ - drc->sequence_count_max = config->max_instructions; - drc->sequence_list = malloc(drc->sequence_count_max * sizeof(*drc->sequence_list)); - if (drc->sequence_list == NULL) - goto error; - - drc->tentative_count_max = config->max_instructions; - drc->tentative_list = malloc(drc->tentative_count_max * sizeof(*drc->tentative_list)); - if (!drc->tentative_list) - return NULL; - - return drc; - -error: - if (drc != NULL) - drc_exit(drc); - return NULL; -} - - -/*------------------------------------------------- - drc_alloc - allocate memory from the top of - the DRC cache --------------------------------------------------*/ - -void *drc_alloc(drc_core *drc, size_t amount) -{ - /* if we don't have enough space, reset the cache */ - if (drc->cache_top >= drc->cache_danger - amount) - drc_cache_reset(drc); - - /* if we still don't have enough space, fail */ - if (drc->cache_top >= drc->cache_danger - amount) - return NULL; - - /* adjust the end and danger values downward */ - drc->cache_end -= amount; - drc->cache_danger -= amount; - return drc->cache_end; -} - - -/*------------------------------------------------- - drc_cache_reset - reset the DRC cache --------------------------------------------------*/ - -void drc_cache_reset(drc_core *drc) -{ - int i; - - /* reset the cache and add the basics */ - drc->cache_top = drc->cache_base; - - /* append the core entry points to the fresh cache */ - drc->entry_point = (void (*)(void))(UINT32)drc->cache_top; - append_entry_point(drc); - drc->out_of_cycles = drc->cache_top; - append_out_of_cycles(drc); - - /* append an INT 3 before the recompile so that BREAK_ON_MODIFIED_CODE works */ - emit_int_3(DRCTOP); - drc->recompile = drc->cache_top; - append_recompile(drc); - drc->dispatch = drc->cache_top; - drc_append_dispatcher(drc); - drc->flush = drc->cache_top; - append_flush(drc); - - /* populate the recompile table */ - for (i = 0; i < (1 << drc->l2bits); i++) - drc->lookup_l2_recompile[i] = drc->recompile; - - /* reset all the l1 tables */ - for (i = 0; i < (1 << drc->l1bits); i++) - { - /* point NULL entries to the generic recompile table */ - if (drc->lookup_l1[i] == NULL) - drc->lookup_l1[i] = drc->lookup_l2_recompile; - - /* reset allocated tables to point all entries back to the recompiler */ - else if (drc->lookup_l1[i] != drc->lookup_l2_recompile) - memcpy(drc->lookup_l1[i], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); - } - - /* call back to the host */ - if (drc->cb_reset) - (*drc->cb_reset)(drc); -} - - -/*------------------------------------------------------------------ - drc_execute -------------------------------------------------------------------*/ - -void drc_execute(drc_core *drc) -{ - (*drc->entry_point)(); -} - - -/*------------------------------------------------------------------ - drc_exit -------------------------------------------------------------------*/ - -void drc_exit(drc_core *drc) -{ - int i; - - /* free all the l2 tables allocated */ - for (i = 0; i < (1 << drc->l1bits); i++) - if (drc->lookup_l1[i] != drc->lookup_l2_recompile) - free(drc->lookup_l1[i]); - - /* free the l1 table */ - if (drc->lookup_l1) - free(drc->lookup_l1); - - /* free the default l2 table */ - if (drc->lookup_l2_recompile) - free(drc->lookup_l2_recompile); - - /* free the lists */ - if (drc->sequence_list) - free(drc->sequence_list); - if (drc->tentative_list) - free(drc->tentative_list); - - /* and the drc itself */ - if (drc->cache_allocated) - osd_free_executable(drc, drc->cache_size + sizeof(*drc)); -} - - -/*------------------------------------------------------------------ - drc_begin_sequence -------------------------------------------------------------------*/ - -void drc_begin_sequence(drc_core *drc, UINT32 pc) -{ - UINT32 l1index = pc >> drc->l1shift; - UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / 4; - - /* reset the sequence and tentative counts */ - drc->sequence_count = 0; - drc->tentative_count = 0; - - /* allocate memory if necessary */ - if (drc->lookup_l1[l1index] == drc->lookup_l2_recompile) - { - /* create a new copy of the recompile table */ - drc->lookup_l1[l1index] = malloc_or_die(sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); - - memcpy(drc->lookup_l1[l1index], drc->lookup_l2_recompile, sizeof(*drc->lookup_l2_recompile) * (1 << drc->l2bits)); - } - - /* nuke any previous link to this instruction */ - if (drc->lookup_l1[l1index][l2index] != drc->recompile) - { - UINT8 *cache_save = drc->cache_top; - drc->cache_top = drc->lookup_l1[l1index][l2index]; - emit_jmp(DRCTOP, drc->dispatch); - drc->cache_top = cache_save; - } - - /* note the current location for this instruction */ - drc->lookup_l1[l1index][l2index] = drc->cache_top; -} - - -/*------------------------------------------------------------------ - drc_end_sequence -------------------------------------------------------------------*/ - -void drc_end_sequence(drc_core *drc) -{ - int i, j; - - /* fix up any internal links */ - for (i = 0; i < drc->tentative_count; i++) - for (j = 0; j < drc->sequence_count; j++) - if (drc->tentative_list[i].pc == drc->sequence_list[j].pc) - { - UINT8 *cache_save = drc->cache_top; - drc->cache_top = drc->tentative_list[i].target; - emit_jmp(DRCTOP, drc->sequence_list[j].target); - drc->cache_top = cache_save; - break; - } -} - - -/*------------------------------------------------------------------ - drc_register_code_at_cache_top -------------------------------------------------------------------*/ - -void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc) -{ - pc_ptr_pair *pair = &drc->sequence_list[drc->sequence_count++]; - assert_always(drc->sequence_count <= drc->sequence_count_max, "drc_register_code_at_cache_top: too many instructions!"); - - pair->target = drc->cache_top; - pair->pc = pc; -} - - -/*------------------------------------------------------------------ - drc_get_code_at_pc -------------------------------------------------------------------*/ - -void *drc_get_code_at_pc(drc_core *drc, UINT32 pc) -{ - UINT32 l1index = pc >> drc->l1shift; - UINT32 l2index = ((pc & drc->l2mask) * drc->l2scale) / 4; - return (drc->lookup_l1[l1index][l2index] != drc->recompile) ? drc->lookup_l1[l1index][l2index] : NULL; -} - - -/*------------------------------------------------------------------ - drc_append_verify_code -------------------------------------------------------------------*/ - -void drc_append_verify_code(drc_core *drc, void *code, UINT8 length) -{ -#if BREAK_ON_MODIFIED_CODE - x86code *recompile = drc->recompile - 1; -#else - x86code *recompile = drc->recompile; -#endif - - if (length > 8) - { - UINT32 *codeptr = code, sum = 0; - void *target; - int i; - - for (i = 0; i < length / 4; i++) - { - sum = (sum >> 1) | (sum << 31); - sum += *codeptr++; - } - - emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax - emit_mov_r32_imm(DRCTOP, REG_EBX, (FPTR)code); // mov ebx,code - emit_mov_r32_imm(DRCTOP, REG_ECX, length / 4); // mov ecx,length / 4 - target = drc->cache_top; // target: - emit_ror_r32_imm(DRCTOP, REG_EAX, 1); // ror eax,1 - emit_add_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, 0)); // add eax,[ebx] - emit_sub_r32_imm(DRCTOP, REG_ECX, 1); // sub ecx,1 - emit_lea_r32_m32(DRCTOP, REG_EBX, MBD(REG_EBX, 4)); // lea ebx,[ebx+4] - emit_jcc(DRCTOP, COND_NZ, target); // jnz target - emit_cmp_r32_imm(DRCTOP, REG_EAX, sum); // cmp eax,sum - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - } - else if (length >= 12) - { - emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 4), ((UINT32 *)code)[1]); // cmp [pc+4],opcode+4 - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 8), ((UINT32 *)code)[2]); // cmp [pc+8],opcode+8 - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - } - else if (length >= 8) - { - emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - emit_cmp_m32_imm(DRCTOP, MABS((UINT8 *)code + 4), ((UINT32 *)code)[1]); // cmp [pc+4],opcode+4 - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - } - else if (length >= 4) - { - emit_cmp_m32_imm(DRCTOP, MABS(code), *(UINT32 *)code); // cmp [pc],opcode - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - } - else if (length >= 2) - { - emit_cmp_m16_imm(DRCTOP, MABS(code), *(UINT16 *)code); // cmp [pc],opcode - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - } - else - { - emit_cmp_m8_imm(DRCTOP, MABS(code), *(UINT8 *)code); // cmp [pc],opcode - emit_jcc(DRCTOP, COND_NE, recompile); // jne recompile - } -} - - -/*------------------------------------------------------------------ - drc_append_call_debugger -------------------------------------------------------------------*/ - -void drc_append_call_debugger(drc_core *drc) -{ -#ifdef ENABLE_DEBUGGER - if (Machine->debug_mode) - { - emit_link link; - emit_cmp_m32_imm(DRCTOP, MABS(&Machine->debug_mode), 0); // cmp [Machine->debug_mode],0 - emit_jcc_short_link(DRCTOP, COND_E, &link); // je skip - emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // align stack - drc_append_save_call_restore(drc, (x86code *)mame_debug_hook, 12); // save volatiles - resolve_link(DRCTOP, &link); - } -#endif -} - - -/*------------------------------------------------------------------ - drc_append_save_volatiles -------------------------------------------------------------------*/ - -void drc_append_save_volatiles(drc_core *drc) -{ - if (drc->icountptr && !drc->icount_in_memory) - emit_mov_m32_r32(DRCTOP, MABS(drc->icountptr), REG_EBP); - if (drc->pcptr && !drc->pc_in_memory) - emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI); - if (drc->esiptr) - emit_mov_m32_r32(DRCTOP, MABS(drc->esiptr), REG_ESI); -} - - -/*------------------------------------------------------------------ - drc_append_restore_volatiles -------------------------------------------------------------------*/ - -void drc_append_restore_volatiles(drc_core *drc) -{ - if (drc->icountptr && !drc->icount_in_memory) - emit_mov_r32_m32(DRCTOP, REG_EBP, MABS(drc->icountptr)); - if (drc->pcptr && !drc->pc_in_memory) - emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(drc->pcptr)); - if (drc->esiptr) - emit_mov_r32_m32(DRCTOP, REG_ESI, MABS(drc->esiptr)); -} - - -/*------------------------------------------------------------------ - drc_append_save_call_restore -------------------------------------------------------------------*/ - -void drc_append_save_call_restore(drc_core *drc, x86code *target, UINT32 stackadj) -{ - drc_append_save_volatiles(drc); // save volatiles - emit_call(DRCTOP, target); // call target - drc_append_restore_volatiles(drc); // restore volatiles - if (stackadj) - emit_add_r32_imm(DRCTOP, REG_ESP, stackadj); // adjust stack -} - - -/*------------------------------------------------------------------ - drc_append_standard_epilogue -------------------------------------------------------------------*/ - -void drc_append_standard_epilogue(drc_core *drc, INT32 cycles, INT32 pcdelta, int allow_exit) -{ - if (pcdelta != 0 && drc->pc_in_memory) - emit_add_m32_imm(DRCTOP, MABS(drc->pcptr), pcdelta); // add [pc],pcdelta - if (cycles != 0) - { - if (drc->icount_in_memory) - emit_sub_m32_imm(DRCTOP, MABS(drc->icountptr), cycles); // sub [icount],cycles - else - emit_sub_r32_imm(DRCTOP, REG_EBP, cycles); // sub ebp,cycles - } - if (pcdelta != 0 && !drc->pc_in_memory) - emit_lea_r32_m32(DRCTOP, REG_EDI, MBD(REG_EDI, pcdelta)); // lea edi,[edi+pcdelta] - if (allow_exit && cycles != 0) - emit_jcc(DRCTOP, COND_S, drc->out_of_cycles); // js out_of_cycles -} - - -/*------------------------------------------------------------------ - drc_append_dispatcher -------------------------------------------------------------------*/ - -void drc_append_dispatcher(drc_core *drc) -{ -#if LOG_DISPATCHES - emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack - emit_push_imm(DRCTOP, drc); // push drc - drc_append_save_call_restore(drc, (x86code *)log_dispatch, 12); // call log_dispatch -#endif - if (drc->pc_in_memory) - emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(drc->pcptr)); // mov edi,[pc] - emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi - emit_shr_r32_imm(DRCTOP, REG_EAX, drc->l1shift); // shr eax,l1shift - emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EDI); // mov edx,edi - emit_mov_r32_m32(DRCTOP, REG_EAX, MISD(REG_EAX, 4, (FPTR)drc->lookup_l1)); // mov eax,[eax*4 + l1lookup] - emit_and_r32_imm(DRCTOP, REG_EDX, drc->l2mask); // and edx,l2mask - emit_jmp_m32(DRCTOP, MBISD(REG_EAX, REG_EDX, drc->l2scale, 0)); // jmp [eax+edx*l2scale] -} - - -/*------------------------------------------------------------------ - drc_append_fixed_dispatcher -------------------------------------------------------------------*/ - -void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc) -{ - x86code **base = drc->lookup_l1[newpc >> drc->l1shift]; - if (base == drc->lookup_l2_recompile) - { - emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(&drc->lookup_l1[newpc >> drc->l1shift])); - // mov eax,[(newpc >> l1shift)*4 + l1lookup] - emit_jmp_m32(DRCTOP, MBD(REG_EAX, (newpc & drc->l2mask) * drc->l2scale)); - // jmp [eax+(newpc & l2mask)*l2scale] - } - else - emit_jmp_m32(DRCTOP, MABS((UINT8 *)base + (newpc & drc->l2mask) * drc->l2scale)); - // jmp [eax+(newpc & l2mask)*l2scale] -} - - -/*------------------------------------------------------------------ - drc_append_tentative_fixed_dispatcher -------------------------------------------------------------------*/ - -void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc) -{ - pc_ptr_pair *pair = &drc->tentative_list[drc->tentative_count++]; - assert_always(drc->tentative_count <= drc->tentative_count_max, "drc_append_tentative_fixed_dispatcher: too many tentative branches!"); - - pair->target = drc->cache_top; - pair->pc = newpc; - drc_append_fixed_dispatcher(drc, newpc); -} - - -/*------------------------------------------------------------------ - drc_append_set_fp_rounding -------------------------------------------------------------------*/ - -void drc_append_set_fp_rounding(drc_core *drc, UINT8 regindex) -{ - emit_fldcw_m16(DRCTOP, MISD(regindex, 2, (INT32)&fp_control[0])); // fldcw [fp_control + reg*2] - emit_fstcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fnstcw [fpcw_curr] -} - - - -/*------------------------------------------------------------------ - drc_append_set_temp_fp_rounding -------------------------------------------------------------------*/ - -void drc_append_set_temp_fp_rounding(drc_core *drc, UINT8 rounding) -{ - emit_fldcw_m16(DRCTOP, MABS(&fp_control[rounding])); // fldcw [fp_control] -} - - - -/*------------------------------------------------------------------ - drc_append_restore_fp_rounding -------------------------------------------------------------------*/ - -void drc_append_restore_fp_rounding(drc_core *drc) -{ - emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fldcw [fpcw_curr] -} - - - -/*------------------------------------------------------------------ - drc_append_set_sse_rounding -------------------------------------------------------------------*/ - -void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex) -{ - emit_ldmxcsr_m32(DRCTOP, MISD(regindex, 4, (INT32)&sse_control[0])); // ldmxcsr [sse_control + reg*2] - emit_stmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // stmxcsr [mxcsr_curr] -} - - - -/*------------------------------------------------------------------ - drc_append_set_temp_sse_rounding -------------------------------------------------------------------*/ - -void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding) -{ - emit_ldmxcsr_m32(DRCTOP, MABS(&sse_control[rounding])); // ldmxcsr [sse_control] -} - - - -/*------------------------------------------------------------------ - drc_append_restore_sse_rounding -------------------------------------------------------------------*/ - -void drc_append_restore_sse_rounding(drc_core *drc) -{ - emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr] -} - - - -/*------------------------------------------------------------------ - drc_dasm - - An attempt to make a disassembler for DRC code; currently limited - by the functionality of DasmI386 -------------------------------------------------------------------*/ - -void drc_dasm(FILE *f, const void *begin, const void *end) -{ - extern int i386_dasm_one(char *buffer, UINT32 eip, UINT8 *oprom, int mode); - - char buffer[256]; - const UINT8 *begin_ptr = (const UINT8 *) begin; - const UINT8 *end_ptr = (const UINT8 *) end; - UINT32 pc = (UINT32) begin; - int length; - - while(begin_ptr < end_ptr) - { -#if defined(ENABLE_DEBUGGER) && HAS_I386 - length = i386_dasm_one(buffer, pc, (UINT8 *) begin_ptr, 32) & DASMFLAG_LENGTHMASK; -#else - sprintf(buffer, "%02X", *begin_ptr); - length = 1; -#endif - - fprintf(f, "%08X:\t%s\n", (unsigned) pc, buffer); - begin_ptr += length; - pc += length; - } -} - - - - -/*************************************************************************** - INTERNAL CODEGEN -***************************************************************************/ - -/*------------------------------------------------------------------ - append_entry_point -------------------------------------------------------------------*/ - -static void append_entry_point(drc_core *drc) -{ - emit_pushad(DRCTOP); // pushad - if (drc->uses_fp) - { - emit_fstcw_m16(DRCTOP, MABS(&drc->fpcw_save)); // fstcw [fpcw_save] - emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_curr)); // fldcw [fpcw_curr] - } - if (drc->uses_sse) - { - emit_stmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_save)); // stmxcsr [mxcsr_save] - emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_curr)); // ldmxcsr [mxcsr_curr] - } - drc_append_restore_volatiles(drc); // load volatiles - if (drc->cb_entrygen) - (*drc->cb_entrygen)(drc); // additional entry point duties - drc_append_dispatcher(drc); // dispatch -} - - -/*------------------------------------------------------------------ - recompile_code -------------------------------------------------------------------*/ - -static void recompile_code(drc_core *drc) -{ - if (drc->cache_top >= drc->cache_danger) - drc_cache_reset(drc); - (*drc->cb_recompile)(drc); -} - - -/*------------------------------------------------------------------ - append_recompile -------------------------------------------------------------------*/ - -static void append_recompile(drc_core *drc) -{ - emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack - emit_push_imm(DRCTOP, (FPTR)drc); // push drc - drc_append_save_call_restore(drc, (x86code *)recompile_code, 12); // call recompile_code - drc_append_dispatcher(drc); // dispatch -} - - -/*------------------------------------------------------------------ - append_flush -------------------------------------------------------------------*/ - -static void append_flush(drc_core *drc) -{ - emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // align stack - emit_push_imm(DRCTOP, (FPTR)drc); // push drc - drc_append_save_call_restore(drc, (x86code *)drc_cache_reset, 12); // call drc_cache_reset - drc_append_dispatcher(drc); // dispatch -} - - -/*------------------------------------------------------------------ - append_out_of_cycles -------------------------------------------------------------------*/ - -static void append_out_of_cycles(drc_core *drc) -{ - drc_append_save_volatiles(drc); // save volatiles - if (drc->uses_fp) - { - emit_fclex(DRCTOP); // fnclex - emit_fldcw_m16(DRCTOP, MABS(&drc->fpcw_save)); // fldcw [fpcw_save] - } - if (drc->uses_sse) - emit_ldmxcsr_m32(DRCTOP, MABS(&drc->mxcsr_save)); // ldmxcsr [mxcsr_save] - emit_popad(DRCTOP); // popad - emit_ret(DRCTOP); // ret -} - - - -/*------------------------------------------------------------------ - drc_x86_get_features() -------------------------------------------------------------------*/ -UINT32 drc_x86_get_features(void) -{ - UINT32 features = 0; -#ifdef _MSC_VER - __asm - { - mov eax, 1 - xor ebx, ebx - xor ecx, ecx - xor edx, edx - __asm _emit 0Fh __asm _emit 0A2h // cpuid - mov features, edx - } -#else /* !_MSC_VER */ - __asm__ - ( - "pushl %%ebx ; " - "movl $1,%%eax ; " - "xorl %%ebx,%%ebx ; " - "xorl %%ecx,%%ecx ; " - "xorl %%edx,%%edx ; " - "cpuid ; " - "movl %%edx,%0 ; " - "popl %%ebx ; " - : "=&a" (features) /* result has to go in eax */ - : /* no inputs */ - : "%ecx", "%edx" /* clobbers ebx, ecx and edx */ - ); -#endif /* MSC_VER */ - return features; -} - - - -/*------------------------------------------------------------------ - log_dispatch -------------------------------------------------------------------*/ - -#if LOG_DISPATCHES -static void log_dispatch(drc_core *drc) -{ - if (input_code_pressed(KEYCODE_D)) - logerror("Disp:%08X\n", *drc->pcptr); -} -#endif diff --git a/src/emu/cpu/x86drc.h b/src/emu/cpu/x86drc.h deleted file mode 100644 index b0b670fee65..00000000000 --- a/src/emu/cpu/x86drc.h +++ /dev/null @@ -1,194 +0,0 @@ -/*************************************************************************** - - x86drc.h - - x86 Dynamic recompiler support routines. - - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. - -***************************************************************************/ - -#pragma once - -#ifndef __X86DRC_H__ -#define __X86DRC_H__ - -#include "cpuintrf.h" -#include "x86emit.h" - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* PC and pointer pair */ -typedef struct _pc_ptr_pair pc_ptr_pair; -struct _pc_ptr_pair -{ - UINT32 pc; - x86code * target; -}; - - -/* core interface structure for the drc common code */ -typedef struct _drc_core drc_core; -struct _drc_core -{ - UINT8 * cache_base; /* base pointer to the compiler cache */ - UINT8 * cache_top; /* current top of cache */ - UINT8 * cache_danger; /* high water mark for the end */ - UINT8 * cache_end; /* end of cache memory */ - size_t cache_size; /* cache allocated size */ - UINT8 cache_allocated; /* did the DRC core allocate the cache? */ - - x86code *** lookup_l1; /* level 1 lookup */ - x86code ** lookup_l2_recompile; /* level 2 lookup populated with recompile pointers */ - UINT8 l1bits; /* number of bits in level 1 lookup */ - UINT8 l2bits; /* number of bits in level 2 lookup */ - UINT8 l1shift; /* shift to go from PC to level 1 lookup */ - UINT32 l2mask; /* mask to go from PC to level 2 lookup */ - UINT8 l2scale; /* scale to get from masked PC value to final level 2 lookup */ - - void (*entry_point)(void); /* pointer to asm entry point */ - x86code * out_of_cycles; /* pointer to out of cycles jump point */ - x86code * recompile; /* pointer to recompile jump point */ - x86code * dispatch; /* pointer to dispatch jump point */ - x86code * flush; /* pointer to flush jump point */ - - UINT32 * pcptr; /* pointer to where the PC is stored */ - UINT32 * icountptr; /* pointer to where the icount is stored */ - UINT32 * esiptr; /* pointer to where the volatile data in ESI is stored */ - UINT8 pc_in_memory; /* true if the PC is stored in memory */ - UINT8 icount_in_memory; /* true if the icount is stored in memory */ - - UINT8 uses_fp; /* true if we need the FP unit */ - UINT8 uses_sse; /* true if we need the SSE unit */ - UINT16 fpcw_curr; /* current FPU control word */ - UINT32 mxcsr_curr; /* current SSE control word */ - UINT16 fpcw_save; /* saved FPU control word */ - UINT32 mxcsr_save; /* saved SSE control word */ - - pc_ptr_pair *sequence_list; /* PC/pointer sets for the current instruction sequence */ - UINT32 sequence_count; /* number of instructions in the current sequence */ - UINT32 sequence_count_max; /* max number of instructions in the current sequence */ - pc_ptr_pair *tentative_list; /* PC/pointer sets for tentative branches */ - UINT32 tentative_count; /* number of tentative branches */ - UINT32 tentative_count_max; /* max number of tentative branches */ - - void (*cb_reset)(struct _drc_core *drc); /* callback when the cache is reset */ - void (*cb_recompile)(struct _drc_core *drc); /* callback when code needs to be recompiled */ - void (*cb_entrygen)(struct _drc_core *drc); /* callback before generating the dispatcher on entry */ -}; - - -/* configuration structure for the drc common code */ -typedef struct _drc_config drc_config; -struct _drc_config -{ - UINT8 * cache_base; /* base pointer to the compiler cache */ - UINT32 cache_size; /* size of cache to allocate */ - UINT32 max_instructions; /* maximum instructions per sequence */ - UINT8 address_bits; /* number of live address bits in the PC */ - UINT8 lsbs_to_ignore; /* number of LSBs to ignore on the PC */ - UINT8 uses_fp; /* true if we need the FP unit */ - UINT8 uses_sse; /* true if we need the SSE unit */ - UINT8 pc_in_memory; /* true if the PC is stored in memory */ - UINT8 icount_in_memory; /* true if the icount is stored in memory */ - - UINT32 * pcptr; /* pointer to where the PC is stored */ - UINT32 * icountptr; /* pointer to where the icount is stored */ - UINT32 * esiptr; /* pointer to where the volatile data in ESI is stored */ - - void (*cb_reset)(drc_core *drc); /* callback when the cache is reset */ - void (*cb_recompile)(drc_core *drc); /* callback when code needs to be recompiled */ - void (*cb_entrygen)(drc_core *drc); /* callback before generating the dispatcher on entry */ -}; - - -/* structure to hold link data to be filled in later */ -typedef struct _link_info link_info; -struct _link_info -{ - UINT8 size; - UINT8 * target; -}; - - - -/*************************************************************************** - MACROS -***************************************************************************/ - -/* use this macro in emit_* instructions to make them shorter */ -#define DRCTOP &drc->cache_top - - - -/*************************************************************************** - HELPER MACROS -***************************************************************************/ - -/* useful macros for accessing hi/lo portions of 64-bit values */ -#define LO(x) (&(((UINT32 *)(UINT32)(x))[0])) -#define HI(x) (&(((UINT32 *)(UINT32)(x))[1])) - - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -/* features */ -#define CPUID_FEATURES_MMX (1 << 23) -#define CPUID_FEATURES_SSE (1 << 26) -#define CPUID_FEATURES_SSE2 (1 << 25) -#define CPUID_FEATURES_CMOV (1 << 15) -#define CPUID_FEATURES_TSC (1 << 4) - - - -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* init/shutdown */ -drc_core *drc_init(UINT8 cpunum, drc_config *config); -void *drc_alloc(drc_core *drc, size_t amount); -void drc_cache_reset(drc_core *drc); -void drc_execute(drc_core *drc); -void drc_exit(drc_core *drc); - -/* code management */ -void drc_begin_sequence(drc_core *drc, UINT32 pc); -void drc_end_sequence(drc_core *drc); -void drc_register_code_at_cache_top(drc_core *drc, UINT32 pc); -void *drc_get_code_at_pc(drc_core *drc, UINT32 pc); - -/* standard appendages */ -void drc_append_dispatcher(drc_core *drc); -void drc_append_fixed_dispatcher(drc_core *drc, UINT32 newpc); -void drc_append_tentative_fixed_dispatcher(drc_core *drc, UINT32 newpc); -void drc_append_call_debugger(drc_core *drc); -void drc_append_standard_epilogue(drc_core *drc, INT32 cycles, INT32 pcdelta, int allow_exit); -void drc_append_save_volatiles(drc_core *drc); -void drc_append_restore_volatiles(drc_core *drc); -void drc_append_save_call_restore(drc_core *drc, x86code *target, UINT32 stackadj); -void drc_append_verify_code(drc_core *drc, void *code, UINT8 length); - -void drc_append_set_fp_rounding(drc_core *drc, UINT8 regindex); -void drc_append_set_temp_fp_rounding(drc_core *drc, UINT8 rounding); -void drc_append_restore_fp_rounding(drc_core *drc); - -void drc_append_set_sse_rounding(drc_core *drc, UINT8 regindex); -void drc_append_set_temp_sse_rounding(drc_core *drc, UINT8 rounding); -void drc_append_restore_sse_rounding(drc_core *drc); - -/* disassembling drc code */ -void drc_dasm(FILE *f, const void *begin, const void *end); - -/* x86 CPU features */ -UINT32 drc_x86_get_features(void); - - -#endif /* __X86DRC_H__ */ diff --git a/src/emu/cpuexec.h b/src/emu/cpuexec.h index fe7a64f8964..dbc608f391e 100644 --- a/src/emu/cpuexec.h +++ b/src/emu/cpuexec.h @@ -200,10 +200,13 @@ enum _cpu_type CPU_V810, CPU_M37702, CPU_M37710, - CPU_PPC403, + CPU_PPC403GA, + CPU_PPC403GCX, CPU_PPC601, CPU_PPC602, CPU_PPC603, + CPU_PPC603E, + CPU_PPC603R, CPU_PPC604, CPU_MPC8240, CPU_SE3208, diff --git a/src/emu/cpuintrf.c b/src/emu/cpuintrf.c index 6eb80089ed6..dd5094db184 100644 --- a/src/emu/cpuintrf.c +++ b/src/emu/cpuintrf.c @@ -172,10 +172,13 @@ void h8_3044_get_info(UINT32 state, cpuinfo *info); void v810_get_info(UINT32 state, cpuinfo *info); void m37702_get_info(UINT32 state, cpuinfo *info); void m37710_get_info(UINT32 state, cpuinfo *info); -void ppc403_get_info(UINT32 state, cpuinfo *info); +void ppc403ga_get_info(UINT32 state, cpuinfo *info); +void ppc403gcx_get_info(UINT32 state, cpuinfo *info); void ppc601_get_info(UINT32 state, cpuinfo *info); void ppc602_get_info(UINT32 state, cpuinfo *info); void ppc603_get_info(UINT32 state, cpuinfo *info); +void ppc603e_get_info(UINT32 state, cpuinfo *info); +void ppc603r_get_info(UINT32 state, cpuinfo *info); void ppc604_get_info(UINT32 state, cpuinfo *info); void mpc8240_get_info(UINT32 state, cpuinfo *info); void SE3208_get_info(UINT32 state, cpuinfo *info); @@ -709,8 +712,11 @@ static const struct #if (HAS_M37710) { CPU_M37710, m37710_get_info }, #endif -#if (HAS_PPC403) - { CPU_PPC403, ppc403_get_info }, +#if (HAS_PPC403GA) + { CPU_PPC403GA, ppc403ga_get_info }, +#endif +#if (HAS_PPC403GCX) + { CPU_PPC403GCX, ppc403gcx_get_info }, #endif #if (HAS_PPC601) { CPU_PPC601, ppc601_get_info }, @@ -721,6 +727,12 @@ static const struct #if (HAS_PPC603) { CPU_PPC603, ppc603_get_info }, #endif +#if (HAS_PPC603E) + { CPU_PPC603E, ppc603e_get_info }, +#endif +#if (HAS_PPC603R) + { CPU_PPC603R, ppc603r_get_info }, +#endif #if (HAS_PPC604) { CPU_PPC604, ppc604_get_info }, #endif diff --git a/src/emu/memory.c b/src/emu/memory.c index 2eb23638e5a..efb2d615d7a 100644 --- a/src/emu/memory.c +++ b/src/emu/memory.c @@ -3164,7 +3164,7 @@ static WRITE32_HANDLER( stub_write8_from_32 ) while (subunits-- != 0) { int shift = *subshift++; - if ((UINT8)(mem_mask >> shift) != 0xff) + if ((UINT8)(mem_mask >> shift) != 0) (*handler->subhandler.write.mhandler8)(handler->subobject, offset, data >> shift); offset++; } diff --git a/src/mame/drivers/firebeat.c b/src/mame/drivers/firebeat.c index 468d23ae0ce..026a9e648f9 100644 --- a/src/mame/drivers/firebeat.c +++ b/src/mame/drivers/firebeat.c @@ -1985,16 +1985,10 @@ static MACHINE_RESET( firebeat ) cdda_set_cdrom(0, cd); } -static const ppc_config firebeat_ppc_cfg = -{ - PPC_MODEL_403GCX -}; - static MACHINE_DRIVER_START(firebeat) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 66000000) - MDRV_CPU_CONFIG(firebeat_ppc_cfg) + MDRV_CPU_ADD(PPC403GCX, 66000000) MDRV_CPU_PROGRAM_MAP(firebeat_map, 0) MDRV_CPU_VBLANK_INT("main", firebeat_interrupt) @@ -2032,8 +2026,7 @@ MACHINE_DRIVER_END static MACHINE_DRIVER_START(firebeat2) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 66000000) - MDRV_CPU_CONFIG(firebeat_ppc_cfg) + MDRV_CPU_ADD(PPC403GCX, 66000000) MDRV_CPU_PROGRAM_MAP(firebeat_map, 0) MDRV_CPU_VBLANK_INT("left", firebeat_interrupt) @@ -2232,9 +2225,7 @@ static void security_w(UINT8 data) { int r = ibutton_w(data); if (r >= 0) - { - ppc403_spu_rx(r & 0xff); - } + cpunum_set_info_int(0, CPUINFO_INT_PPC_RX_DATA, r & 0xff); } /*****************************************************************************/ @@ -2269,7 +2260,7 @@ static void init_firebeat(running_machine *machine) cur_cab_data = cab_data; - ppc403_install_spu_tx_handler(security_w); + cpunum_set_info_fct(0, CPUINFO_PTR_SPU_TX_HANDLER, (genf *)security_w); set_ibutton(rom); diff --git a/src/mame/drivers/gticlub.c b/src/mame/drivers/gticlub.c index b7c9b5c27cc..7203af4b0ce 100644 --- a/src/mame/drivers/gticlub.c +++ b/src/mame/drivers/gticlub.c @@ -366,9 +366,9 @@ static WRITE32_HANDLER( sysreg_w ) } /* Konami K056230 (LANC) */ -static UINT8 K056230_r(int reg) +READ8_HANDLER( K056230_r ) { - switch (reg) + switch (offset) { case 0: // Status register { @@ -376,14 +376,19 @@ static UINT8 K056230_r(int reg) } } -// mame_printf_debug("K056230_r: %d at %08X\n", reg, activecpu_get_pc()); +// mame_printf_debug("K056230_r: %d at %08X\n", offset, activecpu_get_pc()); return 0; } -static void K056230_w(int reg, UINT8 data) +TIMER_CALLBACK( network_irq_gen ) { - switch (reg) + cpunum_set_input_line(Machine, 0, INPUT_LINE_IRQ2, ASSERT_LINE); +} + +WRITE8_HANDLER( K056230_w ) +{ + switch (offset) { case 0: // Mode register { @@ -396,9 +401,12 @@ static void K056230_w(int reg, UINT8 data) // Thunder Hurricane breaks otherwise... if (mame_stricmp(Machine->gamedrv->name, "thunderh") != 0) { - cpunum_set_input_line(Machine, 0, INPUT_LINE_IRQ2, ASSERT_LINE); +// timer_set(ATTOTIME_IN_MSEC(1), NULL, 0, network_irq_gen); +// cpunum_set_input_line(Machine, 0, INPUT_LINE_IRQ2, ASSERT_LINE); } } + else + cpunum_set_input_line(Machine, 0, INPUT_LINE_IRQ2, CLEAR_LINE); break; } case 2: // Sub ID register @@ -406,54 +414,7 @@ static void K056230_w(int reg, UINT8 data) break; } } -// mame_printf_debug("K056230_w: %d, %02X at %08X\n", reg, data, activecpu_get_pc()); -} - -READ32_HANDLER( lanc_r ) -{ - UINT32 r = 0; - int reg = offset * 4; - - if (ACCESSING_BITS_24_31) - { - r |= K056230_r(reg+0) << 24; - } - if (ACCESSING_BITS_16_23) - { - r |= K056230_r(reg+1) << 16; - } - if (ACCESSING_BITS_8_15) - { - r |= K056230_r(reg+2) << 8; - } - if (ACCESSING_BITS_0_7) - { - r |= K056230_r(reg+3) << 0; - } - - return r; -} - -WRITE32_HANDLER( lanc_w ) -{ - int reg = offset * 4; - - if (ACCESSING_BITS_24_31) - { - K056230_w(reg+0, (data >> 24) & 0xff); - } - if (ACCESSING_BITS_16_23) - { - K056230_w(reg+1, (data >> 16) & 0xff); - } - if (ACCESSING_BITS_8_15) - { - K056230_w(reg+2, (data >> 8) & 0xff); - } - if (ACCESSING_BITS_0_7) - { - K056230_w(reg+3, (data >> 0) & 0xff); - } +// mame_printf_debug("K056230_w: %d, %02X at %08X\n", offset, data, activecpu_get_pc()); } static UINT32 lanc_ram[0x2000/4]; @@ -482,7 +443,7 @@ static ADDRESS_MAP_START( gticlub_map, ADDRESS_SPACE_PROGRAM, 32 ) AM_RANGE(0x78080000, 0x7808000f) AM_MIRROR(0x80000000) AM_READWRITE(K001006_1_r, K001006_1_w) AM_RANGE(0x780c0000, 0x780c0003) AM_MIRROR(0x80000000) AM_READWRITE(cgboard_dsp_comm_r_ppc, cgboard_dsp_comm_w_ppc) AM_RANGE(0x7e000000, 0x7e003fff) AM_MIRROR(0x80000000) AM_READWRITE(sysreg_r, sysreg_w) - AM_RANGE(0x7e008000, 0x7e009fff) AM_MIRROR(0x80000000) AM_READWRITE(lanc_r, lanc_w) + AM_RANGE(0x7e008000, 0x7e009fff) AM_MIRROR(0x80000000) AM_READWRITE8(K056230_r, K056230_w, 0xffffffff) AM_RANGE(0x7e00a000, 0x7e00bfff) AM_MIRROR(0x80000000) AM_READWRITE(lanc_ram_r, lanc_ram_w) AM_RANGE(0x7e00c000, 0x7e00c007) AM_MIRROR(0x80000000) AM_WRITE(K056800_host_w) AM_RANGE(0x7e00c000, 0x7e00c007) AM_MIRROR(0x80000000) AM_READ(K056800_host_r) // Hang Pilot @@ -747,11 +708,6 @@ static INTERRUPT_GEN( gticlub_vblank ) } -static const ppc_config gticlub_ppc_cfg = -{ - PPC_MODEL_403GA -}; - static const sharc_config sharc_cfg = { BOOT_MODE_EPROM @@ -770,8 +726,7 @@ static MACHINE_RESET( gticlub ) static MACHINE_DRIVER_START( gticlub ) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 64000000/2) /* PowerPC 403GA 32MHz */ - MDRV_CPU_CONFIG(gticlub_ppc_cfg) + MDRV_CPU_ADD(PPC403GA, 64000000/2) /* PowerPC 403GA 32MHz */ MDRV_CPU_PROGRAM_MAP(gticlub_map, 0) MDRV_CPU_VBLANK_INT("main", gticlub_vblank) @@ -816,8 +771,7 @@ static MACHINE_RESET( hangplt ) static MACHINE_DRIVER_START( hangplt ) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 64000000/2) /* PowerPC 403GA 32MHz */ - MDRV_CPU_CONFIG(gticlub_ppc_cfg) + MDRV_CPU_ADD(PPC403GA, 64000000/2) /* PowerPC 403GA 32MHz */ MDRV_CPU_PROGRAM_MAP(gticlub_map, 0) MDRV_CPU_ADD(M68000, 64000000/4) /* 16MHz */ @@ -1043,7 +997,7 @@ static DRIVER_INIT(slrasslt) DRIVER_INIT_CALL(gticlub); // enable self-modifying code checks - cpunum_set_info_int(0, CPUINFO_INT_PPC_DRC_OPTIONS, PPCDRC_OPTIONS_CHECK_SELFMOD_CODE); + cpunum_set_info_int(0, CPUINFO_INT_PPC_DRC_OPTIONS, PPCDRC_STRICT_VERIFY); } /*************************************************************************/ diff --git a/src/mame/drivers/hornet.c b/src/mame/drivers/hornet.c index 4ca6c4ce5d9..6feaaf2d6ac 100644 --- a/src/mame/drivers/hornet.c +++ b/src/mame/drivers/hornet.c @@ -683,71 +683,52 @@ static VIDEO_UPDATE( hornet_2board ) } /*****************************************************************************/ +static UINT32 *workram; -static READ32_HANDLER( sysreg_r ) +static READ8_HANDLER( sysreg_r ) { - UINT32 r = 0; - if (offset == 0) - { - if (ACCESSING_BITS_24_31) - { - //printf("read sysreg 0\n"); - r |= input_port_read_indexed(machine, 0) << 24; - } - if (ACCESSING_BITS_16_23) - { - r |= input_port_read_indexed(machine, 1) << 16; - } - if (ACCESSING_BITS_8_15) - { - r |= input_port_read_indexed(machine, 2) << 8; - } - if (ACCESSING_BITS_0_7) - { - r |= 0xf7; - } - } - else if (offset == 1) + UINT8 r = 0; + + switch (offset) { - if (ACCESSING_BITS_24_31) - { - r |= input_port_read_indexed(machine, 3) << 24; - } + case 0: + case 1: + case 2: + r = input_port_read_indexed(machine, offset); + break; + + case 3: + r = 0xf7; + break; + + case 4: + r = input_port_read_indexed(machine, 3); + break; } return r; } -static WRITE32_HANDLER( sysreg_w ) +static WRITE8_HANDLER( sysreg_w ) { - if( offset == 0 ) { - if (ACCESSING_BITS_24_31) - { - led_reg0 = (data >> 24) & 0xff; - } - if (ACCESSING_BITS_16_23) - { - led_reg1 = (data >> 16) & 0xff; - } - return; - } - if( offset == 1 ) + switch (offset) { - if (ACCESSING_BITS_24_31) - { - } - if (ACCESSING_BITS_0_7) - { + case 0: + led_reg0 = data; + break; + + case 1: + led_reg1 = data; + break; + + case 7: if (data & 0x80) /* CG Board 1 IRQ Ack */ - { cpunum_set_input_line(machine, 0, INPUT_LINE_IRQ1, CLEAR_LINE); - } + if (data & 0x40) /* CG Board 0 IRQ Ack */ - { cpunum_set_input_line(machine, 0, INPUT_LINE_IRQ0, CLEAR_LINE); - } + set_cgboard_id((data >> 4) & 0x3); - } - return; + break; } } @@ -778,14 +759,14 @@ static READ32_HANDLER( comm0_unk_r ) /*****************************************************************************/ static ADDRESS_MAP_START( hornet_map, ADDRESS_SPACE_PROGRAM, 32 ) - AM_RANGE(0x00000000, 0x003fffff) AM_MIRROR(0x80000000) AM_RAM /* Work RAM */ + AM_RANGE(0x00000000, 0x003fffff) AM_MIRROR(0x80000000) AM_RAM AM_BASE(&workram) /* Work RAM */ AM_RANGE(0x74000000, 0x740000ff) AM_MIRROR(0x80000000) AM_READWRITE(K037122_reg_r, K037122_reg_w) AM_RANGE(0x74020000, 0x7403ffff) AM_MIRROR(0x80000000) AM_READWRITE(K037122_sram_r, K037122_sram_w) AM_RANGE(0x74040000, 0x7407ffff) AM_MIRROR(0x80000000) AM_READWRITE(K037122_char_r, K037122_char_w) AM_RANGE(0x78000000, 0x7800ffff) AM_MIRROR(0x80000000) AM_READWRITE(cgboard_dsp_shared_r_ppc, cgboard_dsp_shared_w_ppc) AM_RANGE(0x780c0000, 0x780c0003) AM_MIRROR(0x80000000) AM_READWRITE(cgboard_dsp_comm_r_ppc, cgboard_dsp_comm_w_ppc) - AM_RANGE(0x7d000000, 0x7d00ffff) AM_MIRROR(0x80000000) AM_READ(sysreg_r) - AM_RANGE(0x7d010000, 0x7d01ffff) AM_MIRROR(0x80000000) AM_WRITE(sysreg_w) + AM_RANGE(0x7d000000, 0x7d00ffff) AM_MIRROR(0x80000000) AM_READ8(sysreg_r, 0xffffffff) + AM_RANGE(0x7d010000, 0x7d01ffff) AM_MIRROR(0x80000000) AM_WRITE8(sysreg_w, 0xffffffff) AM_RANGE(0x7d020000, 0x7d021fff) AM_MIRROR(0x80000000) AM_READWRITE(timekeeper_0_32be_r, timekeeper_0_32be_w) /* M48T58Y RTC/NVRAM */ AM_RANGE(0x7d030000, 0x7d030007) AM_MIRROR(0x80000000) AM_READWRITE(K056800_host_r, K056800_host_w) AM_RANGE(0x7d042000, 0x7d043fff) AM_MIRROR(0x80000000) AM_RAM /* COMM BOARD 0 */ @@ -963,11 +944,6 @@ static const struct RF5C400interface rf5c400_interface = REGION_SOUND1 }; -static const ppc_config hornet_ppc_cfg = -{ - PPC_MODEL_403GA -}; - static sharc_config sharc_cfg = { BOOT_MODE_EPROM @@ -983,6 +959,19 @@ static sharc_config sharc_cfg = */ +static MACHINE_START( hornet ) +{ + /* set conservative DRC options */ + cpunum_set_info_int(0, CPUINFO_INT_PPC_DRC_OPTIONS, PPCDRC_COMPATIBLE_OPTIONS); + + /* configure fast RAM regions for DRC */ + cpunum_set_info_int(0, CPUINFO_INT_PPC_FASTRAM_SELECT, 0); + cpunum_set_info_int(0, CPUINFO_INT_PPC_FASTRAM_START, 0x80000000); + cpunum_set_info_int(0, CPUINFO_INT_PPC_FASTRAM_END, 0x803fffff); + cpunum_set_info_ptr(0, CPUINFO_PTR_PPC_FASTRAM_BASE, workram); + cpunum_set_info_int(0, CPUINFO_INT_PPC_FASTRAM_READONLY, 0); +} + static MACHINE_RESET( hornet ) { if (memory_region(REGION_USER3)) @@ -996,8 +985,7 @@ static MACHINE_RESET( hornet ) static MACHINE_DRIVER_START( hornet ) /* basic machine hardware */ - MDRV_CPU_ADD_TAG("main", PPC403, 64000000/2) /* PowerPC 403GA 32MHz */ - MDRV_CPU_CONFIG(hornet_ppc_cfg) + MDRV_CPU_ADD_TAG("main", PPC403GA, 64000000/2) /* PowerPC 403GA 32MHz */ MDRV_CPU_PROGRAM_MAP(hornet_map, 0) MDRV_CPU_ADD(M68000, 64000000/4) /* 16MHz */ @@ -1009,6 +997,7 @@ static MACHINE_DRIVER_START( hornet ) MDRV_INTERLEAVE(100) + MDRV_MACHINE_START( hornet ) MDRV_MACHINE_RESET( hornet ) MDRV_NVRAM_HANDLER( timekeeper_0 ) @@ -1079,25 +1068,34 @@ MACHINE_DRIVER_END /*****************************************************************************/ +static void jamma_jvs_cmd_exec(void); + static UINT8 jvs_rdata[1024]; static UINT8 jvs_sdata[1024]; static int jvs_rdata_ptr = 0; static int jvs_sdata_ptr = 0; +static int jvs_rdata_count = 0; -static UINT8 jamma_jvs_r(void) +static int jamma_jvs_r(UINT8 *data) { - UINT8 r; - r = jvs_rdata[jvs_rdata_ptr]; - jvs_rdata_ptr++; - - return r; + if (jvs_rdata_ptr < jvs_rdata_count) + { + *data = jvs_rdata[jvs_rdata_ptr++]; + return TRUE; + } + return FALSE; } static void jamma_jvs_w(UINT8 data) { + if (jvs_sdata_ptr == 0 && data != 0xe0) + return; jvs_sdata[jvs_sdata_ptr] = data; jvs_sdata_ptr++; + + if (jvs_sdata_ptr >= 3 && jvs_sdata_ptr >= 3 + jvs_sdata[2]) + jamma_jvs_cmd_exec(); } static int jvs_encode_data(UINT8 *in, UINT8 *out, int length) @@ -1160,13 +1158,7 @@ static void jamma_jvs_cmd_exec(void) sync = jvs_sdata[0]; node = jvs_sdata[1]; byte_num = jvs_sdata[2]; - - if (sync != 0xe0) - { - printf("jamma_jvs_cmd_exec: SYNC byte not found! (%02X)\n", sync); - return; - } - + length = jvs_decode_data(&jvs_sdata[3], data, byte_num-1); /* @@ -1231,6 +1223,7 @@ static void jamma_jvs_cmd_exec(void) // write sum jvs_rdata[3+length] = (UINT8)(sum-1); + jvs_rdata_count = length + 4; jvs_rdata_ptr = 0; jvs_sdata_ptr = 0; } @@ -1238,30 +1231,6 @@ static void jamma_jvs_cmd_exec(void) /*****************************************************************************/ -static UINT8 jamma_rdata[1024]; -static void jamma_r(int length) -{ - int i; -// printf("jamma_r %d\n", length); - for (i=0; i < length; i++) - { - jamma_rdata[i] = jamma_jvs_r(); - } -} - -static UINT8 jamma_wdata[1024]; -static void jamma_w(int length) -{ - int i; -// printf("jamma_w %d\n", length); - for (i=0; i < length; i++) - { - jamma_jvs_w(jamma_wdata[i]); - } - - jamma_jvs_cmd_exec(); -} - static void sound_irq_callback(running_machine *machine, int irq) { if (irq == 0) @@ -1283,8 +1252,8 @@ static void init_hornet(running_machine *machine) timekeeper_init(0, TIMEKEEPER_M48T58, backup_ram); - ppc403_install_spu_tx_dma_handler(jamma_w, jamma_wdata); - ppc403_install_spu_rx_dma_handler(jamma_r, jamma_rdata); + cpunum_set_info_fct(0, CPUINFO_PTR_SPU_TX_HANDLER, (genf *)jamma_jvs_w); + cpunum_set_info_fct(0, CPUINFO_PTR_SPU_RX_HANDLER, (genf *)jamma_jvs_r); } static void init_hornet_2board(running_machine *machine) @@ -1301,8 +1270,8 @@ static void init_hornet_2board(running_machine *machine) timekeeper_init(0, TIMEKEEPER_M48T58, backup_ram); - ppc403_install_spu_tx_dma_handler(jamma_w, jamma_wdata); - ppc403_install_spu_rx_dma_handler(jamma_r, jamma_rdata); + cpunum_set_info_fct(0, CPUINFO_PTR_SPU_TX_HANDLER, (genf *)jamma_jvs_w); + cpunum_set_info_fct(0, CPUINFO_PTR_SPU_RX_HANDLER, (genf *)jamma_jvs_r); } static DRIVER_INIT(gradius4) diff --git a/src/mame/drivers/konamim2.c b/src/mame/drivers/konamim2.c index faae530985e..250d506e764 100644 --- a/src/mame/drivers/konamim2.c +++ b/src/mame/drivers/konamim2.c @@ -1110,11 +1110,9 @@ static INPUT_PORTS_START( m2 ) INPUT_PORTS_END -static const ppc_config ppc602_config = +static const powerpc_config ppc602_config = { - PPC_MODEL_602, - 0x20, /* Multiplier 2, Bus = 33MHz, Core = 66MHz */ - BUS_FREQUENCY_33MHZ + 33000000 /* Multiplier 2, Bus = 33MHz, Core = 66MHz */ }; static INTERRUPT_GEN(m2) diff --git a/src/mame/drivers/model3.c b/src/mame/drivers/model3.c index f5dd28a07d3..7aab404c588 100644 --- a/src/mame/drivers/model3.c +++ b/src/mame/drivers/model3.c @@ -365,8 +365,10 @@ ALL VROM ROMs are 16M MASK #include "machine/53c810.h" #include "sound/scsp.h" -static int model3_irq_enable; -int model3_irq_state; +static UINT8 irq_enable; +static UINT8 irq_state; +static UINT8 scsi_irq_state; + int model3_step; UINT32 *model3_vrom; @@ -412,6 +414,25 @@ static void real3d_dma_callback(UINT32 src, UINT32 dst, int length, int byteswap static UINT16 *model3_soundram; + +static void update_irq_state(running_machine *machine) +{ + if ((irq_enable & irq_state) || scsi_irq_state) + cpunum_set_input_line(machine, 0, PPC_IRQ, ASSERT_LINE); + else + cpunum_set_input_line(machine, 0, PPC_IRQ, CLEAR_LINE); +} + +void model3_set_irq_line(running_machine *machine, UINT8 bit, int state) +{ + if (state != CLEAR_LINE) + irq_state |= bit; + else + irq_state &= ~bit; + update_irq_state(machine); +} + + #define BYTE_REVERSE32(x) (((x >> 24) & 0xff) | \ ((x >> 8) & 0xff00) | \ ((x << 8) & 0xff0000) | \ @@ -789,15 +810,9 @@ static UINT32 scsi_fetch(UINT32 dsp) static void scsi_irq_callback(running_machine *machine, int state) { - if (state) - { - model3_irq_state |= model3_irq_enable & ~0x60; /* FIXME: enable only SCSI interrupt */ - cpunum_set_input_line(machine, 0, INPUT_LINE_IRQ1, ASSERT_LINE); - } - else - { - cpunum_set_input_line(machine, 0, INPUT_LINE_IRQ1, CLEAR_LINE); - } + scsi_irq_state = state; +// model3_irq_state |= irq_enable & ~0x60; /* FIXME: enable only SCSI interrupt */ + update_irq_state(machine); } /*****************************************************************************/ @@ -1244,12 +1259,12 @@ static READ64_HANDLER( model3_sys_r ) } else if (ACCESSING_BITS_24_31) { - return (model3_irq_enable<<24); + return (irq_enable<<24); } else logerror("m3_sys: Unk sys_r @ 0x10: mask = %x\n", (UINT32)mem_mask); break; case 0x18/8: - return (UINT64)model3_irq_state<<56 | 0xff000000; + return (UINT64)irq_state<<56 | 0xff000000; break; } @@ -1264,7 +1279,7 @@ static WRITE64_HANDLER( model3_sys_w ) case 0x10/8: if (ACCESSING_BITS_24_31) { - model3_irq_enable = (data>>24)&0xff; + irq_enable = (data>>24)&0xff; } else logerror("m3_sys: unknown mask on IRQen write\n"); break; @@ -1328,7 +1343,7 @@ static READ64_HANDLER(model3_sound_r) static WRITE64_HANDLER(model3_sound_w) { - model3_irq_state &= ~0x40; + model3_set_irq_line(machine, 0x40, CLEAR_LINE); // serial configuration writes if ((mem_mask == U64(0xff00000000000000)) && (offset == 0)) @@ -1598,8 +1613,8 @@ static INPUT_PORTS_START( scud ) PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) /* View Button 2 */ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON3 ) /* View Button 3 */ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON4 ) /* View Button 4 */ - PORT_BIT( 0x50, IP_ACTIVE_LOW, IPT_BUTTON5 ) /* Shift 1 */ - PORT_BIT( 0x60, IP_ACTIVE_LOW, IPT_BUTTON6 ) /* Shift 2 */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON5 ) /* Shift 1 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON6 ) /* Shift 2 */ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON7 ) /* Shift 3 */ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON8 ) /* Shift 4 */ @@ -1692,8 +1707,8 @@ static INPUT_PORTS_START( daytona2 ) PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) /* View Button 2 */ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON3 ) /* View Button 3 */ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON4 ) /* View Button 4 */ - PORT_BIT( 0x50, IP_ACTIVE_LOW, IPT_BUTTON5 ) /* Shift 1 */ - PORT_BIT( 0x60, IP_ACTIVE_LOW, IPT_BUTTON6 ) /* Shift 2 */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON5 ) /* Shift 1 */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON6 ) /* Shift 2 */ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON7 ) /* Shift 3 */ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON8 ) /* Shift 4 */ @@ -1743,8 +1758,8 @@ static INPUT_PORTS_START( eca ) PORT_START PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) /* View Change */ PORT_BIT( 0x0e, IP_ACTIVE_LOW, IPT_UNUSED ) - PORT_BIT( 0x50, IP_ACTIVE_LOW, IPT_BUTTON2 ) /* Shift Up */ - PORT_BIT( 0x60, IP_ACTIVE_LOW, IPT_BUTTON3 ) /* Shift Down */ + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) /* Shift Up */ + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON3 ) /* Shift Down */ PORT_START PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED ) @@ -4043,52 +4058,48 @@ static const struct SCSPinterface scsp2_interface = /* IRQs */ /* - 0x80: Unused ? + 0x80: Unknown (no clearing logic in scud) 0x40: SCSP - 0x20: Unused ? + 0x20: Unknown (no clearing logic in scud) 0x10: Network - 0x08: V-blank end ? - 0x04: ??? - 0x02: V-blank start - 0x01: Unused ? + 0x08: Video (unknown -- has callback hook in scud) + 0x04: Video (unknown -- has callback hook in scud) + 0x02: Video (VBLANK start?) + 0x01: Video (unused?) */ static int model3_vblank = 0; static INTERRUPT_GEN(model3_interrupt) { if (model3_vblank == 0) { - model3_irq_state = 0x42; + model3_set_irq_line(machine, 0x42, ASSERT_LINE); } else { - model3_irq_state = 0x0d; + model3_set_irq_line(machine, 0x0d, ASSERT_LINE); } - cpunum_set_input_line(machine, 0, INPUT_LINE_IRQ1, ASSERT_LINE); model3_vblank++; model3_vblank &= 1; } -static const ppc_config model3_10 = +static const powerpc_config model3_10 = { - PPC_MODEL_603E, /* 603e, Stretch, 1.3 */ - 0x10, /* Multiplier 1, Bus = 66MHz, Core = 66MHz */ - BUS_FREQUENCY_66MHZ + /* 603e, Stretch, 1.3 */ + 66000000 /* Multiplier 1, Bus = 66MHz, Core = 66MHz */ }; -static const ppc_config model3_15 = +static const powerpc_config model3_15 = { - PPC_MODEL_603E, /* 603e, Stretch, 1.3 */ - 0x15, /* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */ - BUS_FREQUENCY_66MHZ + /* 603e, Stretch, 1.3 */ + 66000000 /* Multiplier 1.5, Bus = 66MHz, Core = 100MHz */ }; -static const ppc_config model3_2x = +static const powerpc_config model3_2x = { - PPC_MODEL_603R, /* 603e-PID7t, Goldeneye, 2.1 */ - 0x25, /* Multiplier 2.5, Bus = 66MHz, Core = 166MHz */ - BUS_FREQUENCY_66MHZ + /* 603e-PID7t, Goldeneye, 2.1 */ + 66000000 /* Multiplier 2.5, Bus = 66MHz, Core = 166MHz */ }; static MACHINE_DRIVER_START( model3_10 ) - MDRV_CPU_ADD(PPC603, 66000000) + MDRV_CPU_ADD(PPC603E, 66000000) MDRV_CPU_CONFIG(model3_10) MDRV_CPU_PROGRAM_MAP(model3_mem, 0) MDRV_CPU_VBLANK_INT_HACK(model3_interrupt,2) @@ -4128,7 +4139,7 @@ static MACHINE_DRIVER_START( model3_10 ) MACHINE_DRIVER_END static MACHINE_DRIVER_START( model3_15 ) - MDRV_CPU_ADD(PPC603, 100000000) + MDRV_CPU_ADD(PPC603E, 100000000) MDRV_CPU_CONFIG(model3_15) MDRV_CPU_PROGRAM_MAP(model3_mem, 0) MDRV_CPU_VBLANK_INT_HACK(model3_interrupt,2) @@ -4166,7 +4177,7 @@ static MACHINE_DRIVER_START( model3_15 ) MACHINE_DRIVER_END static MACHINE_DRIVER_START( model3_20 ) - MDRV_CPU_ADD(PPC603, 166000000) + MDRV_CPU_ADD(PPC603R, 166000000) MDRV_CPU_CONFIG(model3_2x) MDRV_CPU_PROGRAM_MAP(model3_mem, 0) MDRV_CPU_VBLANK_INT_HACK(model3_interrupt,2) @@ -4203,7 +4214,7 @@ static MACHINE_DRIVER_START( model3_20 ) MACHINE_DRIVER_END static MACHINE_DRIVER_START( model3_21 ) - MDRV_CPU_ADD(PPC603, 166000000) + MDRV_CPU_ADD(PPC603R, 166000000) MDRV_CPU_CONFIG(model3_2x) MDRV_CPU_PROGRAM_MAP(model3_mem, 0) MDRV_CPU_VBLANK_INT_HACK(model3_interrupt,2) diff --git a/src/mame/drivers/nwk-tr.c b/src/mame/drivers/nwk-tr.c index 4926f6819c7..ea45b373d18 100644 --- a/src/mame/drivers/nwk-tr.c +++ b/src/mame/drivers/nwk-tr.c @@ -881,11 +881,6 @@ static const struct RF5C400interface rf5c400_interface = REGION_SOUND1 }; -static const ppc_config nwktr_ppc_cfg = -{ - PPC_MODEL_403GA -}; - static const sharc_config sharc_cfg = { BOOT_MODE_EPROM @@ -899,8 +894,7 @@ static MACHINE_RESET( nwktr ) static MACHINE_DRIVER_START( nwktr ) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 64000000/2) /* PowerPC 403GA 32MHz */ - MDRV_CPU_CONFIG(nwktr_ppc_cfg) + MDRV_CPU_ADD(PPC403GA, 64000000/2) /* PowerPC 403GA 32MHz */ MDRV_CPU_PROGRAM_MAP(nwktr_map, 0) MDRV_CPU_ADD(M68000, 64000000/4) /* 16MHz */ @@ -938,30 +932,6 @@ MACHINE_DRIVER_END /*****************************************************************************/ -static UINT8 jamma_rdata[1024]; -static void jamma_r(int length) -{ - int i; - //printf("jamma_r %d\n", length); - for (i=0; i < length; i++) - { - jamma_rdata[i] = 0; - } -} - -static UINT8 jamma_wdata[1024]; -static void jamma_w(int length) -{ - int i; - //printf("jamma_w %d\n", length); - for (i=0; i < length; i++) - { - //jamma_jvs_w(jamma_wdata[i]); - } - - //jamma_jvs_cmd_exec(); -} - static void sound_irq_callback(running_machine *machine, int irq) { if (irq == 0) @@ -981,8 +951,8 @@ static DRIVER_INIT( nwktr ) K056800_init(sound_irq_callback); K033906_init(); - ppc403_install_spu_tx_dma_handler(jamma_w, jamma_wdata); - ppc403_install_spu_rx_dma_handler(jamma_r, jamma_rdata); +// cpunum_set_info_fct(0, CPUINFO_PTR_SPU_TX_HANDLER, (genf *)jamma_jvs_w); +// cpunum_set_info_fct(0, CPUINFO_PTR_SPU_RX_HANDLER, (genf *)jamma_jvs_r); adc1213x_init(0, adc12138_input_callback); } diff --git a/src/mame/drivers/ultrsprt.c b/src/mame/drivers/ultrsprt.c index 0d74092b3f2..016cd522ee2 100644 --- a/src/mame/drivers/ultrsprt.c +++ b/src/mame/drivers/ultrsprt.c @@ -207,11 +207,6 @@ static NVRAM_HANDLER(ultrsprt) eeprom_handler(file, read_or_write); } -static const ppc_config ultrsprt_ppc_cfg = -{ - PPC_MODEL_403GA -}; - static const struct K054539interface k054539_interface = { REGION_SOUND1 @@ -225,8 +220,7 @@ static INTERRUPT_GEN( ultrsprt_vblank ) static MACHINE_DRIVER_START( ultrsprt ) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 25000000) /* PowerPC 403GA 25MHz */ - MDRV_CPU_CONFIG(ultrsprt_ppc_cfg) + MDRV_CPU_ADD(PPC403GA, 25000000) /* PowerPC 403GA 25MHz */ MDRV_CPU_PROGRAM_MAP(ultrsprt_map, 0) MDRV_CPU_VBLANK_INT("main", ultrsprt_vblank) diff --git a/src/mame/drivers/viper.c b/src/mame/drivers/viper.c index 27fee538f0f..99d82c41266 100644 --- a/src/mame/drivers/viper.c +++ b/src/mame/drivers/viper.c @@ -611,11 +611,9 @@ ADDRESS_MAP_END -static const ppc_config viper_ppc_cfg = +static const powerpc_config viper_ppc_cfg = { - PPC_MODEL_MPC8240, - 0x30, - BUS_FREQUENCY_66MHZ + 66000000 }; static INTERRUPT_GEN(viper_vblank) diff --git a/src/mame/drivers/zr107.c b/src/mame/drivers/zr107.c index a4a9cd4a47f..7ccc3f30823 100644 --- a/src/mame/drivers/zr107.c +++ b/src/mame/drivers/zr107.c @@ -56,8 +56,8 @@ static UINT8 led_reg0 = 0x7f, led_reg1 = 0x7f; // defined in drivers/gticlub.c -extern READ32_HANDLER(lanc_r); -extern WRITE32_HANDLER(lanc_w); +extern READ8_HANDLER(K056230_r); +extern WRITE8_HANDLER(K056230_w); extern READ32_HANDLER(lanc_ram_r); extern WRITE32_HANDLER(lanc_ram_w); @@ -312,7 +312,7 @@ static ADDRESS_MAP_START( zr107_map, ADDRESS_SPACE_PROGRAM, 32 ) AM_RANGE(0x78040000, 0x7804000f) AM_MIRROR(0x80000000) AM_READWRITE(K001006_0_r, K001006_0_w) AM_RANGE(0x780c0000, 0x780c0007) AM_MIRROR(0x80000000) AM_READWRITE(cgboard_dsp_comm_r_ppc, cgboard_dsp_comm_w_ppc) AM_RANGE(0x7e000000, 0x7e003fff) AM_MIRROR(0x80000000) AM_READWRITE(sysreg_r, sysreg_w) - AM_RANGE(0x7e008000, 0x7e009fff) AM_MIRROR(0x80000000) AM_READWRITE(lanc_r, lanc_w) /* LANC registers */ + AM_RANGE(0x7e008000, 0x7e009fff) AM_MIRROR(0x80000000) AM_READWRITE8(K056230_r, K056230_w, 0xffffffff) /* LANC registers */ AM_RANGE(0x7e00a000, 0x7e00bfff) AM_MIRROR(0x80000000) AM_READWRITE(lanc_ram_r, lanc_ram_w) /* LANC Buffer RAM (27E) */ AM_RANGE(0x7e00c000, 0x7e00c007) AM_MIRROR(0x80000000) AM_WRITE(K056800_host_w) AM_RANGE(0x7e00c008, 0x7e00c00f) AM_MIRROR(0x80000000) AM_READ(K056800_host_r) @@ -340,7 +340,7 @@ static ADDRESS_MAP_START( jetwave_map, ADDRESS_SPACE_PROGRAM, 32 ) AM_RANGE(0x78080000, 0x7808000f) AM_MIRROR(0x80000000) AM_READWRITE(K001006_1_r, K001006_1_w) AM_RANGE(0x780c0000, 0x780c0007) AM_MIRROR(0x80000000) AM_READWRITE(cgboard_dsp_comm_r_ppc, cgboard_dsp_comm_w_ppc) AM_RANGE(0x7e000000, 0x7e003fff) AM_MIRROR(0x80000000) AM_READWRITE(sysreg_r, sysreg_w) - AM_RANGE(0x7e008000, 0x7e009fff) AM_MIRROR(0x80000000) AM_READWRITE(lanc_r, lanc_w) /* LANC registers */ + AM_RANGE(0x7e008000, 0x7e009fff) AM_MIRROR(0x80000000) AM_READWRITE8(K056230_r, K056230_w, 0xffffffff) /* LANC registers */ AM_RANGE(0x7e00a000, 0x7e00bfff) AM_MIRROR(0x80000000) AM_READWRITE(lanc_ram_r, lanc_ram_w) /* LANC Buffer RAM (27E) */ AM_RANGE(0x7e00c000, 0x7e00c007) AM_MIRROR(0x80000000) AM_WRITE(K056800_host_w) AM_RANGE(0x7e00c008, 0x7e00c00f) AM_MIRROR(0x80000000) AM_READ(K056800_host_r) @@ -541,11 +541,6 @@ static INPUT_PORTS_START( jetwave ) INPUT_PORTS_END -static const ppc_config zr107_ppc_cfg = -{ - PPC_MODEL_403GA -}; - static sharc_config sharc_cfg = { BOOT_MODE_EPROM @@ -570,8 +565,7 @@ static MACHINE_RESET( zr107 ) static MACHINE_DRIVER_START( zr107 ) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 64000000/2) /* PowerPC 403GA 32MHz */ - MDRV_CPU_CONFIG(zr107_ppc_cfg) + MDRV_CPU_ADD(PPC403GA, 64000000/2) /* PowerPC 403GA 32MHz */ MDRV_CPU_PROGRAM_MAP(zr107_map, 0) MDRV_CPU_VBLANK_INT("main", zr107_vblank) @@ -615,8 +609,7 @@ MACHINE_DRIVER_END static MACHINE_DRIVER_START( jetwave ) /* basic machine hardware */ - MDRV_CPU_ADD(PPC403, 64000000/2) /* PowerPC 403GA 32MHz */ - MDRV_CPU_CONFIG(zr107_ppc_cfg) + MDRV_CPU_ADD(PPC403GA, 64000000/2) /* PowerPC 403GA 32MHz */ MDRV_CPU_PROGRAM_MAP(jetwave_map, 0) MDRV_CPU_VBLANK_INT("main", zr107_vblank) diff --git a/src/mame/mame.mak b/src/mame/mame.mak index fb3e4f7e934..a8d38ef8e71 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -168,10 +168,13 @@ CPUS += H83002 CPUS += V810 CPUS += M37702 CPUS += M37710 -CPUS += PPC403 +CPUS += PPC403GA +CPUS += PPC403GCX CPUS += PPC601 CPUS += PPC602 CPUS += PPC603 +CPUS += PPC603E +CPUS += PPC603R CPUS += MPC8240 CPUS += SE3208 CPUS += MC68HC11 diff --git a/src/mame/video/konamiic.c b/src/mame/video/konamiic.c index aea429466e4..8e1383ad759 100644 --- a/src/mame/video/konamiic.c +++ b/src/mame/video/konamiic.c @@ -5367,18 +5367,18 @@ static int K056832_rom_half; // locally cached values static int K056832_LayerAssociatedWithPage[K056832_PAGE_COUNT]; -static int K056832_LayerOffset[4][2]; -static int K056832_LSRAMPage[4][2]; -static INT32 K056832_X[4]; // 0..3 left -static INT32 K056832_Y[4]; // 0..3 top -static INT32 K056832_W[4]; // 0..3 width -> 1..4 pages -static INT32 K056832_H[4]; // 0..3 height -> 1..4 pages -static INT32 K056832_dx[4]; // scroll -static INT32 K056832_dy[4]; // scroll +static int K056832_LayerOffset[8][2]; +static int K056832_LSRAMPage[8][2]; +static INT32 K056832_X[8]; // 0..3 left +static INT32 K056832_Y[8]; // 0..3 top +static INT32 K056832_W[8]; // 0..3 width -> 1..4 pages +static INT32 K056832_H[8]; // 0..3 height -> 1..4 pages +static INT32 K056832_dx[8]; // scroll +static INT32 K056832_dy[8]; // scroll static UINT32 K056832_LineDirty[K056832_PAGE_COUNT][8]; static UINT8 K056832_AllLinesDirty[K056832_PAGE_COUNT]; static UINT8 K056832_PageTileMode[K056832_PAGE_COUNT]; -static UINT8 K056832_LayerTileMode[4]; +static UINT8 K056832_LayerTileMode[8]; static int K056832_DefaultLayerAssociation; static int K056832_LayerAssociation; static int K056832_ActiveLayer; diff --git a/src/mame/video/model3.c b/src/mame/video/model3.c index ecae1198906..301956649b0 100644 --- a/src/mame/video/model3.c +++ b/src/mame/video/model3.c @@ -75,7 +75,8 @@ static void draw_viewport(int pri, UINT32 address); /*****************************************************************************/ -extern int model3_irq_state; +/* in drivers/model3.c */ +void model3_set_irq_line(running_machine *machine, UINT8 bit, int state); extern int model3_step; @@ -476,7 +477,7 @@ WRITE64_HANDLER(model3_vid_reg_w) { case 0x00/8: logerror("vid_reg0: %08X%08X\n", (UINT32)(data>>32),(UINT32)(data)); vid_reg0 = data; break; case 0x08/8: break; /* ??? */ - case 0x10/8: model3_irq_state &= ~(data >> 56); break; /* VBL IRQ Ack */ + case 0x10/8: model3_set_irq_line(machine, (data >> 56) & 0x0f, CLEAR_LINE); break; /* VBL IRQ Ack */ case 0x20/8: model3_layer_enable = (data >> 52); break; |