Added code generation for MMX instructions

This commit is contained in:
TomW 2016-02-24 20:55:48 +00:00
commit 4011a246ff
9 changed files with 1020 additions and 8 deletions

View file

@ -160,6 +160,7 @@ extern uint32_t op_old_pc;
extern int codegen_flags_changed;
extern int codegen_fpu_entered;
extern int codegen_mmx_entered;
extern int codegen_fpu_loaded_iq[8];
extern int codegen_reg_loaded[8];

View file

@ -19,6 +19,7 @@
#include "codegen_ops_jump.h"
#include "codegen_ops_logic.h"
#include "codegen_ops_misc.h"
#include "codegen_ops_mmx.h"
#include "codegen_ops_mov.h"
#include "codegen_ops_shift.h"
#include "codegen_ops_stack.h"
@ -83,7 +84,7 @@ RecompOpFn recomp_opcodes_0f[512] =
/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*80*/ ropJO_w, ropJNO_w, ropJB_w, ropJNB_w, ropJE_w, ropJNE_w, ropJBE_w, ropJNBE_w, ropJS_w, ropJNS_w, ropJP_w, ropJNP_w, ropJL_w, ropJNL_w, ropJLE_w, ropJNLE_w,
/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -104,8 +105,8 @@ RecompOpFn recomp_opcodes_0f[512] =
/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_mm_l, ropMOVQ_mm_q,
/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_l_mm, ropMOVQ_q_mm,
/*80*/ ropJO_l, ropJNO_l, ropJB_l, ropJNB_l, ropJE_l, ropJNE_l, ropJBE_l, ropJNBE_l, ropJS_l, ropJNS_l, ropJP_l, ropJNP_l, ropJL_l, ropJNL_l, ropJLE_l, ropJNLE_l,
/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@ -113,9 +114,9 @@ RecompOpFn recomp_opcodes_0f[512] =
/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_l_b, ropMOVZX_l_w, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_l_b, ropMOVSX_l_w,
/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/*d0*/ NULL, ropPSRLW, ropPSRLD, ropPSRLQ, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN,
/*e0*/ NULL, ropPSRAW, ropPSRAD, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR,
/*f0*/ NULL, ropPSLLW, ropPSLLD, ropPSLLQ, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL,
};

277
src/codegen_ops_mmx.h Normal file
View file

@ -0,0 +1,277 @@
static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
int host_reg1, host_reg2;
MMX_ENTER();
LOAD_MMX_Q((fetchdat >> 3) & 7, &host_reg1, &host_reg2);
if ((fetchdat & 0xc0) == 0xc0)
{
STORE_MMX_Q(fetchdat & 7, host_reg1, host_reg2);
}
else
{
x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);
STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
CHECK_SEG_WRITE(target_seg);
CHECK_SEG_LIMITS(target_seg, 7);
MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2);
}
return op_pc + 1;
}
static uint32_t ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
MMX_ENTER();
if ((fetchdat & 0xc0) == 0xc0)
{
int host_reg1, host_reg2;
LOAD_MMX_Q(fetchdat & 7, &host_reg1, &host_reg2);
STORE_MMX_Q((fetchdat >> 3) & 7, host_reg1, host_reg2);
}
else
{
x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);
STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
CHECK_SEG_READ(target_seg);
MEM_LOAD_ADDR_EA_Q(target_seg);
STORE_MMX_Q((fetchdat >> 3) & 7, LOAD_Q_REG_1, LOAD_Q_REG_2);
}
return op_pc + 1;
}
static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
int host_reg;
MMX_ENTER();
host_reg = LOAD_MMX_D((fetchdat >> 3) & 7);
if ((fetchdat & 0xc0) == 0xc0)
{
STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7);
}
else
{
x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);
STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
CHECK_SEG_WRITE(target_seg);
CHECK_SEG_LIMITS(target_seg, 3);
MEM_STORE_ADDR_EA_L(target_seg, host_reg);
}
return op_pc + 1;
}
static uint32_t ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
MMX_ENTER();
if ((fetchdat & 0xc0) == 0xc0)
{
int host_reg = LOAD_REG_L(fetchdat & 7);
STORE_MMX_LQ((fetchdat >> 3) & 7, host_reg);
}
else
{
x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32);
STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc);
CHECK_SEG_READ(target_seg);
MEM_LOAD_ADDR_EA_L(target_seg);
STORE_MMX_LQ((fetchdat >> 3) & 7, 0);
}
return op_pc + 1;
}
#define MMX_OP(name, func) \
static uint32_t name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \
{ \
int src_reg1, src_reg2; \
int xmm_src, xmm_dst; \
\
MMX_ENTER(); \
\
if ((fetchdat & 0xc0) == 0xc0) \
{ \
xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \
} \
else \
{ \
x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \
\
STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \
\
CHECK_SEG_READ(target_seg); \
\
MEM_LOAD_ADDR_EA_Q(target_seg); \
src_reg1 = LOAD_Q_REG_1; \
src_reg2 = LOAD_Q_REG_2; \
xmm_src = LOAD_INT_TO_MMX(src_reg1, src_reg2); \
} \
xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \
func(xmm_dst, xmm_src); \
STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \
\
return op_pc + 1; \
}
MMX_OP(ropPAND, MMX_AND)
MMX_OP(ropPANDN, MMX_ANDN)
MMX_OP(ropPOR, MMX_OR)
MMX_OP(ropPXOR, MMX_XOR)
MMX_OP(ropPADDB, MMX_ADDB)
MMX_OP(ropPADDW, MMX_ADDW)
MMX_OP(ropPADDD, MMX_ADDD)
MMX_OP(ropPADDSB, MMX_ADDSB)
MMX_OP(ropPADDSW, MMX_ADDSW)
MMX_OP(ropPADDUSB, MMX_ADDUSB)
MMX_OP(ropPADDUSW, MMX_ADDUSW)
MMX_OP(ropPSUBB, MMX_SUBB)
MMX_OP(ropPSUBW, MMX_SUBW)
MMX_OP(ropPSUBD, MMX_SUBD)
MMX_OP(ropPSUBSB, MMX_SUBSB)
MMX_OP(ropPSUBSW, MMX_SUBSW)
MMX_OP(ropPSUBUSB, MMX_SUBUSB)
MMX_OP(ropPSUBUSW, MMX_SUBUSW)
MMX_OP(ropPUNPCKLBW, MMX_PUNPCKLBW);
MMX_OP(ropPUNPCKLWD, MMX_PUNPCKLWD);
MMX_OP(ropPUNPCKLDQ, MMX_PUNPCKLDQ);
MMX_OP(ropPACKSSWB, MMX_PACKSSWB);
MMX_OP(ropPCMPGTB, MMX_PCMPGTB);
MMX_OP(ropPCMPGTW, MMX_PCMPGTW);
MMX_OP(ropPCMPGTD, MMX_PCMPGTD);
MMX_OP(ropPACKUSWB, MMX_PACKUSWB);
MMX_OP(ropPUNPCKHBW, MMX_PUNPCKHBW);
MMX_OP(ropPUNPCKHWD, MMX_PUNPCKHWD);
MMX_OP(ropPUNPCKHDQ, MMX_PUNPCKHDQ);
MMX_OP(ropPACKSSDW, MMX_PACKSSDW);
MMX_OP(ropPCMPEQB, MMX_PCMPEQB);
MMX_OP(ropPCMPEQW, MMX_PCMPEQW);
MMX_OP(ropPCMPEQD, MMX_PCMPEQD);
MMX_OP(ropPSRLW, MMX_PSRLW)
MMX_OP(ropPSRLD, MMX_PSRLD)
MMX_OP(ropPSRLQ, MMX_PSRLQ)
MMX_OP(ropPSRAW, MMX_PSRAW)
MMX_OP(ropPSRAD, MMX_PSRAD)
MMX_OP(ropPSLLW, MMX_PSLLW)
MMX_OP(ropPSLLD, MMX_PSLLD)
MMX_OP(ropPSLLQ, MMX_PSLLQ)
MMX_OP(ropPMULLW, MMX_PMULLW);
MMX_OP(ropPMULHW, MMX_PMULHW);
MMX_OP(ropPMADDWD, MMX_PMADDWD);
static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
int xmm_dst;
if ((fetchdat & 0xc0) != 0xc0)
return 0;
if ((fetchdat & 0x08) || !(fetchdat & 0x30))
return 0;
MMX_ENTER();
xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7);
switch (fetchdat & 0x38)
{
case 0x10: /*PSRLW*/
MMX_PSRLW_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
case 0x20: /*PSRAW*/
MMX_PSRAW_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
case 0x30: /*PSLLW*/
MMX_PSLLW_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
}
STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst);
return op_pc + 2;
}
static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
int xmm_dst;
if ((fetchdat & 0xc0) != 0xc0)
return 0;
if ((fetchdat & 0x08) || !(fetchdat & 0x30))
return 0;
MMX_ENTER();
xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7);
switch (fetchdat & 0x38)
{
case 0x10: /*PSRLD*/
MMX_PSRLD_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
case 0x20: /*PSRAD*/
MMX_PSRAD_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
case 0x30: /*PSLLD*/
MMX_PSLLD_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
}
STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst);
return op_pc + 2;
}
static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
int xmm_dst;
if ((fetchdat & 0xc0) != 0xc0)
return 0;
if ((fetchdat & 0x08) || !(fetchdat & 0x30))
return 0;
MMX_ENTER();
xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7);
switch (fetchdat & 0x38)
{
case 0x10: /*PSRLQ*/
MMX_PSRLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
case 0x20: /*PSRAQ*/
MMX_PSRAQ_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
case 0x30: /*PSLLQ*/
MMX_PSLLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff);
break;
}
STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst);
return op_pc + 2;
}
static uint32_t ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block)
{
codegen_mmx_entered = 0;
return 0;
}

View file

@ -2,6 +2,21 @@
R8-R15 - emulated registers
*/
#define HOST_REG_XMM_START 0
#define HOST_REG_XMM_END 7
static inline int find_host_xmm_reg()
{
int c;
for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++)
{
if (host_reg_xmm_mapping[c] == -1)
break;
}
if (c == HOST_REG_XMM_END)
fatal("Out of host XMM regs!\n");
return c;
}
static void call(codeblock_t *block, uintptr_t func)
{
uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5];
@ -4347,3 +4362,349 @@ static void CLEAR_BITS(uintptr_t addr, uint32_t val)
addbyte(~val);
}
}
#define LOAD_Q_REG_1 REG_EAX
#define LOAD_Q_REG_2 REG_EDX
static void MMX_ENTER()
{
if (codegen_mmx_entered)
return;
addbyte(0xf6); /*TEST cr0, 0xc*/
addbyte(0x04);
addbyte(0x25);
addlong((uintptr_t)&cr0);
addbyte(0xc);
addbyte(0x74); /*JZ +*/
addbyte(11+5+12+5);
addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/
addbyte(0x04);
addbyte(0x25);
addlong((uintptr_t)&oldpc);
addlong(op_old_pc);
load_param_1_32(&codeblock[block_current], 7);
CALL_FUNC(x86_int);
addbyte(0xe9); /*JMP end*/
addlong(BLOCK_EXIT_OFFSET - (block_pos + 4));
addbyte(0x31); /*XOR EAX, EAX*/
addbyte(0xc0);
addbyte(0xc7); /*MOV ISMMX, 1*/
addbyte(0x04);
addbyte(0x25);
addlong((uint32_t)&ismmx);
addlong(1);
addbyte(0x89); /*MOV TOP, EAX*/
addbyte(0x04);
addbyte(0x25);
addlong((uint32_t)&TOP);
addbyte(0x89); /*MOV tag, EAX*/
addbyte(0x04);
addbyte(0x25);
addlong((uint32_t)&tag[0]);
addbyte(0x89); /*MOV tag+4, EAX*/
addbyte(0x04);
addbyte(0x25);
addlong((uint32_t)&tag[4]);
codegen_mmx_entered = 1;
}
extern int mmx_ebx_ecx_loaded;
static int LOAD_MMX_D(int guest_reg)
{
int host_reg = REG_EBX;
addbyte(0x8b); /*MOV EBX, reg*/
addbyte(0x04 | (host_reg << 3));
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].l[0]);
return host_reg;
}
static void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2)
{
int host_reg = REG_EBX;
if (host_reg & 8)
addbyte(0x4c);
else
addbyte(0x48);
addbyte(0x8b); /*MOV RBX, reg*/
addbyte(0x04 | ((host_reg & 7) << 3));
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].q);
*host_reg1 = host_reg;
}
static int LOAD_MMX_Q_MMX(int guest_reg)
{
int dst_reg = find_host_xmm_reg();
host_reg_xmm_mapping[dst_reg] = 100;
addbyte(0xf3); /*MOV XMMx, reg*/
addbyte(0x0f);
addbyte(0x7e);
addbyte(0x04 | ((dst_reg & 7) << 3));
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].q);
return dst_reg;
}
static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2)
{
int dst_reg = find_host_xmm_reg();
host_reg_xmm_mapping[dst_reg] = 100;
addbyte(0x66); /*MOVQ host_reg, src_reg1*/
if (src_reg1 & 8)
addbyte(0x49);
else
addbyte(0x48);
addbyte(0x0f);
addbyte(0x6e);
addbyte(0xc0 | (dst_reg << 3) | (src_reg1 & 7));
return dst_reg;
}
static void STORE_MMX_LQ(int guest_reg, int host_reg1)
{
addbyte(0xC7); /*MOVL [reg],0*/
addbyte(0x04);
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].l[1]);
addlong(0);
if (host_reg1 & 8)
addbyte(0x44);
addbyte(0x89); /*MOVL [reg],host_reg*/
addbyte(0x04 | ((host_reg1 & 7) << 3));
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].l[0]);
}
static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2)
{
if (host_reg1 & 8)
addbyte(0x4c);
else
addbyte(0x48);
addbyte(0x89); /*MOV [reg],host_reg*/
addbyte(0x04 | ((host_reg1 & 7) << 3));
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].l[0]);
}
static void STORE_MMX_Q_MMX(int guest_reg, int host_reg)
{
addbyte(0x66); /*MOVQ [guest_reg],host_reg*/
addbyte(0x0f);
addbyte(0xd6);
addbyte(0x04 | (host_reg << 3));
addbyte(0x25);
addlong((uint32_t)&MM[guest_reg].q);
}
#define MMX_x86_OP(name, opcode) \
static void MMX_ ## name(int dst_reg, int src_reg) \
{ \
addbyte(0x66); /*op dst_reg, src_reg*/ \
addbyte(0x0f); \
addbyte(opcode); \
addbyte(0xc0 | (dst_reg << 3) | src_reg); \
}
MMX_x86_OP(AND, 0xdb)
MMX_x86_OP(ANDN, 0xdf)
MMX_x86_OP(OR, 0xeb)
MMX_x86_OP(XOR, 0xef)
MMX_x86_OP(ADDB, 0xfc)
MMX_x86_OP(ADDW, 0xfd)
MMX_x86_OP(ADDD, 0xfe)
MMX_x86_OP(ADDSB, 0xec)
MMX_x86_OP(ADDSW, 0xed)
MMX_x86_OP(ADDUSB, 0xdc)
MMX_x86_OP(ADDUSW, 0xdd)
MMX_x86_OP(SUBB, 0xf8)
MMX_x86_OP(SUBW, 0xf9)
MMX_x86_OP(SUBD, 0xfa)
MMX_x86_OP(SUBSB, 0xe8)
MMX_x86_OP(SUBSW, 0xe9)
MMX_x86_OP(SUBUSB, 0xd8)
MMX_x86_OP(SUBUSW, 0xd9)
MMX_x86_OP(PUNPCKLBW, 0x60);
MMX_x86_OP(PUNPCKLWD, 0x61);
MMX_x86_OP(PUNPCKLDQ, 0x62);
MMX_x86_OP(PCMPGTB, 0x64);
MMX_x86_OP(PCMPGTW, 0x65);
MMX_x86_OP(PCMPGTD, 0x66);
MMX_x86_OP(PCMPEQB, 0x74);
MMX_x86_OP(PCMPEQW, 0x75);
MMX_x86_OP(PCMPEQD, 0x76);
MMX_x86_OP(PSRLW, 0xd1);
MMX_x86_OP(PSRLD, 0xd2);
MMX_x86_OP(PSRLQ, 0xd3);
MMX_x86_OP(PSRAW, 0xe1);
MMX_x86_OP(PSRAD, 0xe2);
MMX_x86_OP(PSLLW, 0xf1);
MMX_x86_OP(PSLLD, 0xf2);
MMX_x86_OP(PSLLQ, 0xf3);
MMX_x86_OP(PMULLW, 0xd5);
MMX_x86_OP(PMULHW, 0xe5);
MMX_x86_OP(PMADDWD, 0xf5);
static void MMX_PACKSSWB(int dst_reg, int src_reg)
{
addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x63);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x08);
}
static void MMX_PACKUSWB(int dst_reg, int src_reg)
{
addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x67);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x08);
}
static void MMX_PACKSSDW(int dst_reg, int src_reg)
{
addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x6b);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x08);
}
static void MMX_PUNPCKHBW(int dst_reg, int src_reg)
{
addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x60);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x0e);
}
static void MMX_PUNPCKHWD(int dst_reg, int src_reg)
{
addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x61);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x0e);
}
static void MMX_PUNPCKHDQ(int dst_reg, int src_reg)
{
addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x62);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x0e);
}
static void MMX_PSRLW_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRLW dst_reg, amount*/
addbyte(0x0f);
addbyte(0x71);
addbyte(0xc0 | dst_reg | 0x10);
addbyte(amount);
}
static void MMX_PSRAW_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRAW dst_reg, amount*/
addbyte(0x0f);
addbyte(0x71);
addbyte(0xc0 | dst_reg | 0x20);
addbyte(amount);
}
static void MMX_PSLLW_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSLLW dst_reg, amount*/
addbyte(0x0f);
addbyte(0x71);
addbyte(0xc0 | dst_reg | 0x30);
addbyte(amount);
}
static void MMX_PSRLD_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRLD dst_reg, amount*/
addbyte(0x0f);
addbyte(0x72);
addbyte(0xc0 | dst_reg | 0x10);
addbyte(amount);
}
static void MMX_PSRAD_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRAD dst_reg, amount*/
addbyte(0x0f);
addbyte(0x72);
addbyte(0xc0 | dst_reg | 0x20);
addbyte(amount);
}
static void MMX_PSLLD_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSLLD dst_reg, amount*/
addbyte(0x0f);
addbyte(0x72);
addbyte(0xc0 | dst_reg | 0x30);
addbyte(amount);
}
static void MMX_PSRLQ_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRLQ dst_reg, amount*/
addbyte(0x0f);
addbyte(0x73);
addbyte(0xc0 | dst_reg | 0x10);
addbyte(amount);
}
static void MMX_PSRAQ_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRAQ dst_reg, amount*/
addbyte(0x0f);
addbyte(0x73);
addbyte(0xc0 | dst_reg | 0x20);
addbyte(amount);
}
static void MMX_PSLLQ_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSLLQ dst_reg, amount*/
addbyte(0x0f);
addbyte(0x73);
addbyte(0xc0 | dst_reg | 0x30);
addbyte(amount);
}

View file

@ -6,6 +6,8 @@
*/
#define HOST_REG_START 1
#define HOST_REG_END 4
#define HOST_REG_XMM_START 0
#define HOST_REG_XMM_END 7
static inline int find_host_reg()
{
int c;
@ -19,6 +21,19 @@ static inline int find_host_reg()
fatal("Out of host regs!\n");
return c;
}
static inline int find_host_xmm_reg()
{
int c;
for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++)
{
if (host_reg_xmm_mapping[c] == -1)
break;
}
if (c == HOST_REG_XMM_END)
fatal("Out of host XMM regs!\n");
return c;
}
static void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val)
{
@ -2996,3 +3011,345 @@ static void CLEAR_BITS(uintptr_t addr, uint32_t val)
addbyte(~val);
}
}
#define LOAD_Q_REG_1 REG_EAX
#define LOAD_Q_REG_2 REG_EDX
static void MMX_ENTER()
{
if (codegen_mmx_entered)
return;
addbyte(0xf6); /*TEST cr0, 0xc*/
addbyte(0x05);
addlong((uintptr_t)&cr0);
addbyte(0xc);
addbyte(0x74); /*JZ +*/
addbyte(10+7+5+5);
addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/
addbyte(0x05);
addlong((uintptr_t)&oldpc);
addlong(op_old_pc);
addbyte(0xc7); /*MOV [ESP], 7*/
addbyte(0x04);
addbyte(0x24);
addlong(7);
addbyte(0xe8); /*CALL x86_int*/
addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4]));
addbyte(0xe9); /*JMP end*/
addlong(BLOCK_EXIT_OFFSET - (block_pos + 4));
addbyte(0x31); /*XOR EAX, EAX*/
addbyte(0xc0);
addbyte(0xc7); /*MOV ISMMX, 1*/
addbyte(0x05);
addlong((uint32_t)&ismmx);
addlong(1);
addbyte(0xa3); /*MOV TOP, EAX*/
addlong((uint32_t)&TOP);
addbyte(0xa3); /*MOV tag, EAX*/
addlong((uint32_t)&tag[0]);
addbyte(0xa3); /*MOV tag+4, EAX*/
addlong((uint32_t)&tag[4]);
codegen_mmx_entered = 1;
}
extern int mmx_ebx_ecx_loaded;
static int LOAD_MMX_D(int guest_reg)
{
int host_reg = find_host_reg();
host_reg_mapping[host_reg] = 100;
addbyte(0x8b); /*MOV EBX, reg*/
addbyte(0x05 | (host_reg << 3));
addlong((uint32_t)&MM[guest_reg].l[0]);
return host_reg;
}
static int LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2)
{
if (!mmx_ebx_ecx_loaded)
{
*host_reg1 = REG_EBX;
*host_reg2 = REG_ECX;
mmx_ebx_ecx_loaded = 1;
}
else
{
*host_reg1 = REG_EAX;
*host_reg2 = REG_EDX;
}
addbyte(0x8b); /*MOV EBX, reg*/
addbyte(0x05 | ((*host_reg1) << 3));
addlong((uint32_t)&MM[guest_reg].l[0]);
addbyte(0x8b); /*MOV ECX, reg+4*/
addbyte(0x05 | ((*host_reg2) << 3));
addlong((uint32_t)&MM[guest_reg].l[1]);
}
static int LOAD_MMX_Q_MMX(int guest_reg)
{
int dst_reg = find_host_xmm_reg();
host_reg_xmm_mapping[dst_reg] = guest_reg;
addbyte(0xf3); /*MOVQ dst_reg,[reg]*/
addbyte(0x0f);
addbyte(0x7e);
addbyte(0x05 | (dst_reg << 3));
addlong((uint32_t)&MM[guest_reg].q);
return dst_reg;
}
static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2)
{
int dst_reg = find_host_xmm_reg();
host_reg_xmm_mapping[dst_reg] = 100;
addbyte(0x66); /*MOVD dst_reg, src_reg1*/
addbyte(0x0f);
addbyte(0x6e);
addbyte(0xc0 | (dst_reg << 3) | src_reg1);
addbyte(0x66); /*MOVD XMM7, src_reg2*/
addbyte(0x0f);
addbyte(0x6e);
addbyte(0xc0 | (7 << 3) | src_reg2);
addbyte(0x66); /*PUNPCKLDQ dst_reg, XMM7*/
addbyte(0x0f);
addbyte(0x62);
addbyte(0xc0 | 7 | (dst_reg << 3));
return dst_reg;
}
static void STORE_MMX_LQ(int guest_reg, int host_reg1)
{
addbyte(0xC7); /*MOVL [reg],0*/
addbyte(0x05);
addlong((uint32_t)&MM[guest_reg].l[1]);
addlong(0);
addbyte(0x89); /*MOVL [reg],host_reg*/
addbyte(0x05 | (host_reg1 << 3));
addlong((uint32_t)&MM[guest_reg].l[0]);
}
static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2)
{
addbyte(0x89); /*MOVL [reg],host_reg*/
addbyte(0x05 | (host_reg1 << 3));
addlong((uint32_t)&MM[guest_reg].l[0]);
addbyte(0x89); /*MOVL [reg],host_reg*/
addbyte(0x05 | (host_reg2 << 3));
addlong((uint32_t)&MM[guest_reg].l[1]);
}
static void STORE_MMX_Q_MMX(int guest_reg, int host_reg)
{
addbyte(0x66); /*MOVQ [guest_reg],host_reg*/
addbyte(0x0f);
addbyte(0xd6);
addbyte(0x05 | (host_reg << 3));
addlong((uint32_t)&MM[guest_reg].q);
}
#define MMX_x86_OP(name, opcode) \
static void MMX_ ## name(int dst_reg, int src_reg) \
{ \
addbyte(0x66); /*op dst_reg, src_reg*/ \
addbyte(0x0f); \
addbyte(opcode); \
addbyte(0xc0 | (dst_reg << 3) | src_reg); \
}
MMX_x86_OP(AND, 0xdb)
MMX_x86_OP(ANDN, 0xdf)
MMX_x86_OP(OR, 0xeb)
MMX_x86_OP(XOR, 0xef)
MMX_x86_OP(ADDB, 0xfc)
MMX_x86_OP(ADDW, 0xfd)
MMX_x86_OP(ADDD, 0xfe)
MMX_x86_OP(ADDSB, 0xec)
MMX_x86_OP(ADDSW, 0xed)
MMX_x86_OP(ADDUSB, 0xdc)
MMX_x86_OP(ADDUSW, 0xdd)
MMX_x86_OP(SUBB, 0xf8)
MMX_x86_OP(SUBW, 0xf9)
MMX_x86_OP(SUBD, 0xfa)
MMX_x86_OP(SUBSB, 0xe8)
MMX_x86_OP(SUBSW, 0xe9)
MMX_x86_OP(SUBUSB, 0xd8)
MMX_x86_OP(SUBUSW, 0xd9)
MMX_x86_OP(PUNPCKLBW, 0x60);
MMX_x86_OP(PUNPCKLWD, 0x61);
MMX_x86_OP(PUNPCKLDQ, 0x62);
MMX_x86_OP(PCMPGTB, 0x64);
MMX_x86_OP(PCMPGTW, 0x65);
MMX_x86_OP(PCMPGTD, 0x66);
MMX_x86_OP(PCMPEQB, 0x74);
MMX_x86_OP(PCMPEQW, 0x75);
MMX_x86_OP(PCMPEQD, 0x76);
MMX_x86_OP(PSRLW, 0xd1);
MMX_x86_OP(PSRLD, 0xd2);
MMX_x86_OP(PSRLQ, 0xd3);
MMX_x86_OP(PSRAW, 0xe1);
MMX_x86_OP(PSRAD, 0xe2);
MMX_x86_OP(PSLLW, 0xf1);
MMX_x86_OP(PSLLD, 0xf2);
MMX_x86_OP(PSLLQ, 0xf3);
MMX_x86_OP(PMULLW, 0xd5);
MMX_x86_OP(PMULHW, 0xe5);
MMX_x86_OP(PMADDWD, 0xf5);
static void MMX_PACKSSWB(int dst_reg, int src_reg)
{
addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x63);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x08);
}
static void MMX_PACKUSWB(int dst_reg, int src_reg)
{
addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x67);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x08);
}
static void MMX_PACKSSDW(int dst_reg, int src_reg)
{
addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x6b);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x08);
}
static void MMX_PUNPCKHBW(int dst_reg, int src_reg)
{
addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x60);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x0e);
}
static void MMX_PUNPCKHWD(int dst_reg, int src_reg)
{
addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x61);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x0e);
}
static void MMX_PUNPCKHDQ(int dst_reg, int src_reg)
{
addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/
addbyte(0x0f);
addbyte(0x62);
addbyte(0xc0 | (dst_reg << 3) | src_reg);
addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/
addbyte(0x0f);
addbyte(0x70);
addbyte(0xc0 | (dst_reg << 3) | dst_reg);
addbyte(0x0e);
}
static void MMX_PSRLW_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRLW dst_reg, amount*/
addbyte(0x0f);
addbyte(0x71);
addbyte(0xc0 | dst_reg | 0x10);
addbyte(amount);
}
static void MMX_PSRAW_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRAW dst_reg, amount*/
addbyte(0x0f);
addbyte(0x71);
addbyte(0xc0 | dst_reg | 0x20);
addbyte(amount);
}
static void MMX_PSLLW_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSLLW dst_reg, amount*/
addbyte(0x0f);
addbyte(0x71);
addbyte(0xc0 | dst_reg | 0x30);
addbyte(amount);
}
static void MMX_PSRLD_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRLD dst_reg, amount*/
addbyte(0x0f);
addbyte(0x72);
addbyte(0xc0 | dst_reg | 0x10);
addbyte(amount);
}
static void MMX_PSRAD_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRAD dst_reg, amount*/
addbyte(0x0f);
addbyte(0x72);
addbyte(0xc0 | dst_reg | 0x20);
addbyte(amount);
}
static void MMX_PSLLD_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSLLD dst_reg, amount*/
addbyte(0x0f);
addbyte(0x72);
addbyte(0xc0 | dst_reg | 0x30);
addbyte(amount);
}
static void MMX_PSRLQ_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRLQ dst_reg, amount*/
addbyte(0x0f);
addbyte(0x73);
addbyte(0xc0 | dst_reg | 0x10);
addbyte(amount);
}
static void MMX_PSRAQ_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSRAQ dst_reg, amount*/
addbyte(0x0f);
addbyte(0x73);
addbyte(0xc0 | dst_reg | 0x20);
addbyte(amount);
}
static void MMX_PSLLQ_imm(int dst_reg, int amount)
{
addbyte(0x66); /*PSLLQ dst_reg, amount*/
addbyte(0x0f);
addbyte(0x73);
addbyte(0xc0 | dst_reg | 0x30);
addbyte(amount);
}

View file

@ -35,9 +35,10 @@ uint32_t op_old_pc;
uint32_t recomp_page = -1;
int host_reg_mapping[NR_HOST_REGS];
int host_reg_xmm_mapping[NR_HOST_XMM_REGS];
codeblock_t *codeblock;
codeblock_t **codeblock_hash;
int codegen_mmx_entered = 0;
int block_current = 0;
static int block_num;
@ -292,7 +293,8 @@ void codegen_block_init(uint32_t phys_addr)
codegen_flags_changed = 0;
codegen_fpu_entered = 0;
codegen_mmx_entered = 0;
codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] =
codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0;
@ -920,6 +922,8 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t
for (c = 0; c < NR_HOST_REGS; c++)
host_reg_mapping[c] = -1;
for (c = 0; c < NR_HOST_XMM_REGS; c++)
host_reg_xmm_mapping[c] = -1;
codegen_timing_start();

View file

@ -17,3 +17,5 @@ enum
#define NR_HOST_REGS 3
extern int host_reg_mapping[NR_HOST_REGS];
#define NR_HOST_XMM_REGS 7
extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS];

View file

@ -23,8 +23,10 @@
#include <windows.h>
#endif
int mmx_ebx_ecx_loaded;
int codegen_flags_changed = 0;
int codegen_fpu_entered = 0;
int codegen_mmx_entered = 0;
int codegen_fpu_loaded_iq[8];
x86seg *op_ea_seg;
int op_ssegs;
@ -33,6 +35,7 @@ uint32_t op_old_pc;
uint32_t recomp_page = -1;
int host_reg_mapping[NR_HOST_REGS];
int host_reg_xmm_mapping[NR_HOST_XMM_REGS];
codeblock_t *codeblock;
codeblock_t **codeblock_hash;
@ -266,6 +269,7 @@ void codegen_block_init(uint32_t phys_addr)
codegen_flags_changed = 0;
codegen_fpu_entered = 0;
codegen_mmx_entered = 0;
codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] =
codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0;
@ -721,6 +725,9 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t
for (c = 0; c < NR_HOST_REGS; c++)
host_reg_mapping[c] = -1;
mmx_ebx_ecx_loaded = 0;
for (c = 0; c < NR_HOST_XMM_REGS; c++)
host_reg_xmm_mapping[c] = -1;
codegen_timing_start();

View file

@ -17,3 +17,5 @@ enum
#define NR_HOST_REGS 3
extern int host_reg_mapping[NR_HOST_REGS];
#define NR_HOST_XMM_REGS 7
extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS];