diff --git a/src/386.c b/src/386.c index b9f5492..bedc69a 100644 --- a/src/386.c +++ b/src/386.c @@ -1210,8 +1210,6 @@ void cpu_386_flags_rebuild() int oldi; -static uint64_t tsc = 0; - uint32_t testr[9]; int dontprint=0; diff --git a/src/386_ops.h b/src/386_ops.h index f687920..fba97a4 100644 --- a/src/386_ops.h +++ b/src/386_ops.h @@ -76,6 +76,13 @@ static inline uint32_t POP_L() #include "x86_ops_io.h" #include "x86_ops_jump.h" #include "x86_ops_misc.h" +#include "x86_ops_mmx.h" +#include "x86_ops_mmx_arith.h" +#include "x86_ops_mmx_cmp.h" +#include "x86_ops_mmx_logic.h" +#include "x86_ops_mmx_mov.h" +#include "x86_ops_mmx_pack.h" +#include "x86_ops_mmx_shift.h" #include "x86_ops_mov.h" #include "x86_ops_mov_ctrl.h" #include "x86_ops_mov_seg.h" @@ -95,6 +102,8 @@ static inline uint32_t POP_L() static int ILLEGAL(uint32_t fetchdat) { pc = oldpc; + +// fatal("Illegal instruction %08X\n", fetchdat); x86illegal(); return 0; } @@ -103,13 +112,20 @@ static int op0F_w_a16(uint32_t fetchdat) { int opcode = fetchdat & 0xff; pc++; - + if (x86_opcodes_0f[opcode] == ILLEGAL && opcode != 0xff) + { + fatal("Illegal 0f instruction %02X w_a16\n", opcode); + } return x86_opcodes_0f[opcode](fetchdat >> 8); } static int op0F_l_a16(uint32_t fetchdat) { int opcode = fetchdat & 0xff; pc++; + if (x86_opcodes_0f[opcode | 0x100] == ILLEGAL && opcode != 0xff) + { + fatal("Illegal 0f instruction %02X l_a16\n", opcode); + } return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); } @@ -117,6 +133,10 @@ static int op0F_w_a32(uint32_t fetchdat) { int opcode = fetchdat & 0xff; pc++; + if (x86_opcodes_0f[opcode | 0x200] == ILLEGAL && opcode != 0xff) + { + fatal("Illegal 0f instruction %02X w_a32\n", opcode); + } return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); } @@ -124,6 +144,10 @@ static int op0F_l_a32(uint32_t fetchdat) { int opcode = fetchdat & 0xff; pc++; + if (x86_opcodes_0f[opcode | 0x300] == ILLEGAL && opcode != 0xff) + { + fatal("Illegal 0f instruction %02X l_a32\n", opcode); + } return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); } @@ -232,7 +256,7 @@ OpFn ops_386_0f[1024] = /*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -254,7 +278,7 @@ OpFn ops_386_0f[1024] = /*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -276,7 +300,7 @@ OpFn ops_386_0f[1024] = /*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -298,7 +322,7 @@ OpFn ops_386_0f[1024] = /*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, -/*30*/ ILLEGAL, opRDTSC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, /*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, @@ -316,6 +340,97 @@ OpFn ops_386_0f[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; +OpFn ops_winchip_0f[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,ILLEGAL, ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,ILLEGAL, ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + OpFn ops_286[1024] = { /*16-bit data, 16-bit addr*/ diff --git a/src/cpu.c b/src/cpu.c index 9fd6103..d0de431 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -4,6 +4,14 @@ #include "io.h" #include "x86_ops.h" +enum +{ + CPUID_FPU = (1 << 0), + CPUID_TSC = (1 << 4), + CPUID_MSR = (1 << 5), + CPUID_MMX = (1 << 23) +}; + int cpu = 3, cpu_manufacturer = 0; CPU *cpu_s; int cpu_multi; @@ -11,6 +19,8 @@ int cpu_iscyrix; int cpu_16bitbus; int cpu_busspeed; int cpu_hasrdtsc; +int cpu_hasMMX, cpu_hasMSR; +uint64_t tsc = 0; int timing_rr; int timing_mr, timing_mrl; @@ -18,6 +28,14 @@ int timing_rm, timing_rml; int timing_mm, timing_mml; int timing_bt, timing_bnt; +static struct +{ + uint32_t tr1, tr12; + uint32_t cesr; + uint32_t fcr; + uint64_t fcr2, fcr3; +} msr; + /*Available cpuspeeds : 0 = 16 MHz 1 = 20 MHz @@ -239,6 +257,8 @@ void cpu_set() cpu_busspeed = cpu_s->rspeed / cpu_s->multi; cpu_multi = cpu_s->multi; cpu_hasrdtsc = 0; + cpu_hasMMX = 0; + cpu_hasMSR = 0; if (cpu_iscyrix) io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); @@ -250,6 +270,8 @@ void cpu_set() x86_setopcodes(ops_386, ops_386_0f); + memset(&msr, 0, sizeof(msr)); + switch (cpu_s->cpu_type) { case CPU_8088: @@ -370,6 +392,7 @@ void cpu_set() break; case CPU_WINCHIP: + x86_setopcodes(ops_386, ops_winchip_0f); timing_rr = 1; /*register dest - register src*/ timing_rm = 2; /*register dest - memory src*/ timing_mr = 3; /*memory dest - register src*/ @@ -380,6 +403,8 @@ void cpu_set() timing_bt = 3-1; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = cpu_hasMSR = 1; break; default: @@ -403,7 +428,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = 1; /*FPU*/ + EDX = CPUID_FPU; /*FPU*/ } else EAX = 0; @@ -438,7 +463,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = 1; /*FPU*/ + EDX = CPUID_FPU; /*FPU*/ } else EAX = 0; @@ -448,15 +473,26 @@ void cpu_CPUID() if (!EAX) { EAX = 1; - EBX = 0x746e6543; /*CentaurHauls*/ - ECX = 0x736c7561; - EDX = 0x48727561; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } } else if (EAX == 1) { - EAX = CPUID; + EAX = 0x540; EBX = ECX = 0; - EDX = 1; /*FPU*/ + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; } else EAX = 0; @@ -464,6 +500,80 @@ void cpu_CPUID() } } +void cpu_RDMSR() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_WINCHIP: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + } +} + +void cpu_WRMSR() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_WINCHIP: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x11: + msr.cesr = EAX & 0xff00ff; + break; + case 0x107: + msr.fcr = EAX; + cpu_hasMMX = EAX & (1 << 9); + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + } +} static int cyrix_addr; diff --git a/src/cpu.h b/src/cpu.h index 83757da..51e651f 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -71,8 +71,15 @@ extern int cpu_busspeed; extern int cpu_multi; extern int cpu_hasrdtsc; +extern int cpu_hasMSR; +extern int cpu_hasMMX; + +extern uint64_t tsc; void cyrix_write(uint16_t addr, uint8_t val, void *priv); uint8_t cyrix_read(uint16_t addr, void *priv); extern int is8086; + +void cpu_RDMSR(); +void cpu_WRMSR(); diff --git a/src/x86_ops.h b/src/x86_ops.h index ce4f43a..b5d9713 100644 --- a/src/x86_ops.h +++ b/src/x86_ops.h @@ -10,3 +10,5 @@ extern OpFn ops_286_0f[1024]; extern OpFn ops_386[1024]; extern OpFn ops_386_0f[1024]; + +extern OpFn ops_winchip_0f[1024]; diff --git a/src/x86_ops_fpu.h b/src/x86_ops_fpu.h index a5430f8..2252695 100644 --- a/src/x86_ops_fpu.h +++ b/src/x86_ops_fpu.h @@ -2,7 +2,7 @@ static int opESCAPE_ ## num ##_a16(uint32_t fetchdat) \ { \ flags_rebuild(); \ - if ((cr0 & 6) == 4) \ + if (cr0 & 0xc) \ { \ x86_int(7); \ } \ @@ -24,7 +24,7 @@ static int opESCAPE_ ## num ## _a32(uint32_t fetchdat) \ { \ flags_rebuild(); \ - if ((cr0 & 6) == 4) \ + if (cr0 & 0xc) \ { \ x86_int(7); \ } \ @@ -55,6 +55,11 @@ opESCAPE(df); static int opWAIT(uint32_t fetchdat) { + if ((cr0 & 0xa) == 0xa) + { + x86_int(7); + return 0; + } cycles -= 4; return 0; } diff --git a/src/x86_ops_misc.h b/src/x86_ops_misc.h index d9f6fb2..a7ee9fd 100644 --- a/src/x86_ops_misc.h +++ b/src/x86_ops_misc.h @@ -675,4 +675,29 @@ static int opCPUID(uint32_t fetchdat) return 0; } - +static int opRDMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_RDMSR(); + cycles -= 9; + return 0; + } + pc = oldpc; + x86illegal(); + return 0; +} + +static int opWRMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_WRMSR(); + cycles -= 9; + return 0; + } + pc = oldpc; + x86illegal(); + return 0; +} + diff --git a/src/x86_ops_mmx.h b/src/x86_ops_mmx.h new file mode 100644 index 0000000..5e31d08 --- /dev/null +++ b/src/x86_ops_mmx.h @@ -0,0 +1,49 @@ +#define SSATB(val) (((val) < -128) ? -128 : (((val) > 127) ? 127 : (val))) +#define SSATW(val) (((val) < -32768) ? -32768 : (((val) > 32767) ? 32767 : (val))) +#define USATB(val) (((val) < 0) ? 0 : (((val) > 255) ? 255 : (val))) +#define USATW(val) (((val) < 0) ? 0 : (((val) > 65535) ? 65535 : (val))) + +#define MMX_GETSRC() \ + if (mod == 3) \ + { \ + src = MM[rm]; \ + cycles--; \ + } \ + else \ + { \ + src.l[0] = readmeml(easeg, eaaddr); \ + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; \ + cycles -= 2; \ + } + +#define MMX_ENTER() \ + if (!cpu_hasMMX) \ + { \ + pc = oldpc; \ + x86illegal(); \ + return 0; \ + } \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 0; \ + } \ + x87_set_mmx() + +int opEMMS(uint32_t fetchdat) +{ + if (!cpu_hasMMX) + { + pc = oldpc; + x86illegal(); + return 0; + } + if (cr0 & 4) + { + x86_int(7); + return 0; + } + x87_emms(); + cycles -= 100; /*Guess*/ + return 0; +} diff --git a/src/x86_ops_mmx_arith.h b/src/x86_ops_mmx_arith.h new file mode 100644 index 0000000..203ae48 --- /dev/null +++ b/src/x86_ops_mmx_arith.h @@ -0,0 +1,625 @@ +int opPADDB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] += src.b[0]; + MM[reg].b[1] += src.b[1]; + MM[reg].b[2] += src.b[2]; + MM[reg].b[3] += src.b[3]; + MM[reg].b[4] += src.b[4]; + MM[reg].b[5] += src.b[5]; + MM[reg].b[6] += src.b[6]; + MM[reg].b[7] += src.b[7]; + + return 0; +} +int opPADDB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] += src.b[0]; + MM[reg].b[1] += src.b[1]; + MM[reg].b[2] += src.b[2]; + MM[reg].b[3] += src.b[3]; + MM[reg].b[4] += src.b[4]; + MM[reg].b[5] += src.b[5]; + MM[reg].b[6] += src.b[6]; + MM[reg].b[7] += src.b[7]; + + return 0; +} + +int opPADDW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] += src.w[0]; + MM[reg].w[1] += src.w[1]; + MM[reg].w[2] += src.w[2]; + MM[reg].w[3] += src.w[3]; + + return 0; +} +int opPADDW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] += src.w[0]; + MM[reg].w[1] += src.w[1]; + MM[reg].w[2] += src.w[2]; + MM[reg].w[3] += src.w[3]; + + return 0; +} + +int opPADDD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] += src.l[0]; + MM[reg].l[1] += src.l[1]; + + return 0; +} +int opPADDD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] += src.l[0]; + MM[reg].l[1] += src.l[1]; + + return 0; +} + +int opPADDSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] + src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] + src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] + src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] + src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] + src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] + src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] + src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] + src.sb[7]); + + return 0; +} +int opPADDSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] + src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] + src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] + src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] + src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] + src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] + src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] + src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] + src.sb[7]); + + return 0; +} + +int opPADDUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] + src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] + src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] + src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] + src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] + src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] + src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] + src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] + src.b[7]); + + return 0; +} +int opPADDUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] + src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] + src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] + src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] + src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] + src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] + src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] + src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] + src.b[7]); + + return 0; +} + +int opPADDSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] + src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] + src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] + src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] + src.sw[3]); + + return 0; +} +int opPADDSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] + src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] + src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] + src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] + src.sw[3]); + + return 0; +} + +int opPADDUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] + src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] + src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] + src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] + src.w[3]); + + return 0; +} +int opPADDUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] + src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] + src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] + src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] + src.w[3]); + + return 0; +} + +int opPMADDWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + if (MM[reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + MM[reg].l[0] = 0x80000000; + else + MM[reg].sl[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]); + + if (MM[reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + MM[reg].l[1] = 0x80000000; + else + MM[reg].sl[1] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} +int opPMADDWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + if (MM[reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + MM[reg].l[0] = 0x80000000; + else + MM[reg].sl[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]); + + if (MM[reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + MM[reg].l[1] = 0x80000000; + else + MM[reg].sl[1] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} + + +int opPMULLW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].w[0] *= MM[rm].w[0]; + MM[reg].w[1] *= MM[rm].w[1]; + MM[reg].w[2] *= MM[rm].w[2]; + MM[reg].w[3] *= MM[rm].w[3]; + cycles--; + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] *= src.w[0]; + MM[reg].w[1] *= src.w[1]; + MM[reg].w[2] *= src.w[2]; + MM[reg].w[3] *= src.w[3]; + cycles -= 2; + } + return 0; +} +int opPMULLW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].w[0] *= MM[rm].w[0]; + MM[reg].w[1] *= MM[rm].w[1]; + MM[reg].w[2] *= MM[rm].w[2]; + MM[reg].w[3] *= MM[rm].w[3]; + cycles--; + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] *= src.w[0]; + MM[reg].w[1] *= src.w[1]; + MM[reg].w[2] *= src.w[2]; + MM[reg].w[3] *= src.w[3]; + cycles -= 2; + } + return 0; +} + +int opPMULHW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)MM[rm].sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)MM[rm].sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)MM[rm].sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)MM[rm].sw[3]) >> 16; + cycles--; + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]) >> 16; + cycles -= 2; + } + return 0; +} +int opPMULHW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)MM[rm].sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)MM[rm].sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)MM[rm].sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)MM[rm].sw[3]) >> 16; + cycles--; + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]) >> 16; + cycles -= 2; + } + return 0; +} + +int opPSUBB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] -= src.b[0]; + MM[reg].b[1] -= src.b[1]; + MM[reg].b[2] -= src.b[2]; + MM[reg].b[3] -= src.b[3]; + MM[reg].b[4] -= src.b[4]; + MM[reg].b[5] -= src.b[5]; + MM[reg].b[6] -= src.b[6]; + MM[reg].b[7] -= src.b[7]; + + return 0; +} +int opPSUBB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] -= src.b[0]; + MM[reg].b[1] -= src.b[1]; + MM[reg].b[2] -= src.b[2]; + MM[reg].b[3] -= src.b[3]; + MM[reg].b[4] -= src.b[4]; + MM[reg].b[5] -= src.b[5]; + MM[reg].b[6] -= src.b[6]; + MM[reg].b[7] -= src.b[7]; + + return 0; +} + +int opPSUBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] -= src.w[0]; + MM[reg].w[1] -= src.w[1]; + MM[reg].w[2] -= src.w[2]; + MM[reg].w[3] -= src.w[3]; + + return 0; +} +int opPSUBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] -= src.w[0]; + MM[reg].w[1] -= src.w[1]; + MM[reg].w[2] -= src.w[2]; + MM[reg].w[3] -= src.w[3]; + + return 0; +} + +int opPSUBD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] -= src.l[0]; + MM[reg].l[1] -= src.l[1]; + + return 0; +} +int opPSUBD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] -= src.l[0]; + MM[reg].l[1] -= src.l[1]; + + return 0; +} + +int opPSUBSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] - src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] - src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] - src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] - src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] - src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] - src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] - src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] - src.sb[7]); + + return 0; +} +int opPSUBSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] - src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] - src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] - src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] - src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] - src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] - src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] - src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] - src.sb[7]); + + return 0; +} + +int opPSUBUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] - src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] - src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] - src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] - src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] - src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] - src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] - src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] - src.b[7]); + + return 0; +} +int opPSUBUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] - src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] - src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] - src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] - src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] - src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] - src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] - src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] - src.b[7]); + + return 0; +} + +int opPSUBSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] - src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] - src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] - src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] - src.sw[3]); + + return 0; +} +int opPSUBSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] - src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] - src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] - src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] - src.sw[3]); + + return 0; +} + +int opPSUBUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] - src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] - src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] - src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] - src.w[3]); + + return 0; +} +int opPSUBUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] - src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] - src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] - src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] - src.w[3]); + + return 0; +} diff --git a/src/x86_ops_mmx_cmp.h b/src/x86_ops_mmx_cmp.h new file mode 100644 index 0000000..a6b974d --- /dev/null +++ b/src/x86_ops_mmx_cmp.h @@ -0,0 +1,205 @@ +static int opPCMPEQB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].b[0] == src.b[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].b[1] == src.b[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].b[2] == src.b[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].b[3] == src.b[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].b[4] == src.b[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].b[5] == src.b[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].b[6] == src.b[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPEQB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].b[0] == src.b[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].b[1] == src.b[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].b[2] == src.b[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].b[3] == src.b[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].b[4] == src.b[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].b[5] == src.b[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].b[6] == src.b[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPGTB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].sb[0] > src.sb[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].sb[1] > src.sb[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].sb[2] > src.sb[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].sb[3] > src.sb[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].sb[4] > src.sb[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].sb[5] > src.sb[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].sb[6] > src.sb[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPGTB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].sb[0] > src.sb[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].sb[1] > src.sb[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].sb[2] > src.sb[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].sb[3] > src.sb[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].sb[4] > src.sb[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].sb[5] > src.sb[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].sb[6] > src.sb[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPEQW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].w[0] == src.w[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].w[1] == src.w[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].w[2] == src.w[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPEQW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].w[0] == src.w[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].w[1] == src.w[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].w[2] == src.w[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPGTW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].sw[0] > src.sw[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].sw[1] > src.sw[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].sw[2] > src.sw[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPGTW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].sw[0] > src.sw[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].sw[1] > src.sw[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].sw[2] > src.sw[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPEQD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].l[0] == src.l[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPEQD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].l[0] == src.l[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} + +static int opPCMPGTD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPGTD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} diff --git a/src/x86_ops_mmx_logic.h b/src/x86_ops_mmx_logic.h new file mode 100644 index 0000000..eb6544d --- /dev/null +++ b/src/x86_ops_mmx_logic.h @@ -0,0 +1,91 @@ +int opPAND_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= src.q; + return 0; +} +int opPAND_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= src.q; + return 0; +} + +int opPANDN_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= ~src.q; + return 0; +} +int opPANDN_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= ~src.q; + return 0; +} + +int opPOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q |= src.q; + return 0; +} +int opPOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q |= src.q; + return 0; +} + +int opPXOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q ^= src.q; + return 0; +} +int opPXOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q ^= src.q; + return 0; +} diff --git a/src/x86_ops_mmx_mov.h b/src/x86_ops_mmx_mov.h new file mode 100644 index 0000000..655fb4c --- /dev/null +++ b/src/x86_ops_mmx_mov.h @@ -0,0 +1,163 @@ +int opMOVD_l_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].l[0] = regs[rm].l; + MM[reg].l[1] = 0; + cycles--; + } + else + { + uint32_t dst; + + dst = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[0] = dst; + MM[reg].l[1] = 0; + + cycles -= 2; + } + return 0; +} +int opMOVD_l_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].l[0] = regs[rm].l; + MM[reg].l[1] = 0; + cycles--; + } + else + { + uint32_t dst; + + dst = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[0] = dst; + MM[reg].l[1] = 0; + + cycles -= 2; + } + return 0; +} + +int opMOVD_mm_l_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + regs[rm].l = MM[reg].l[0]; + cycles--; + } + else + { + writememl(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 0; + cycles -= 2; + } + return 0; +} +int opMOVD_mm_l_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + regs[rm].l = MM[reg].l[0]; + cycles--; + } + else + { + writememl(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 0; + cycles -= 2; + } + return 0; +} + +int opMOVQ_q_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].q = MM[rm].q; + cycles--; + } + else + { + uint32_t dst[2]; + + dst[0] = readmeml(easeg, eaaddr); + dst[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].l[0] = dst[0]; + MM[reg].l[1] = dst[1]; + cycles -= 2; + } + return 0; +} +int opMOVQ_q_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].q = MM[rm].q; + cycles--; + } + else + { + uint32_t dst[2]; + + dst[0] = readmeml(easeg, eaaddr); + dst[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].l[0] = dst[0]; + MM[reg].l[1] = dst[1]; + cycles -= 2; + } + return 0; +} + +int opMOVQ_mm_q_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[rm].q = MM[reg].q; + cycles--; + } + else + { + writememl(easeg, eaaddr, MM[reg].l[0]); + writememl(easeg, eaaddr + 4, MM[reg].l[1]); if (abrt) return 0; + cycles -= 2; + } + return 0; +} +int opMOVQ_mm_q_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[rm].q = MM[reg].q; + cycles--; + } + else + { + writememl(easeg, eaaddr, MM[reg].l[0]); + writememl(easeg, eaaddr + 4, MM[reg].l[1]); if (abrt) return 0; + cycles -= 2; + } + return 0; +} diff --git a/src/x86_ops_mmx_pack.h b/src/x86_ops_mmx_pack.h new file mode 100644 index 0000000..9f9cf18 --- /dev/null +++ b/src/x86_ops_mmx_pack.h @@ -0,0 +1,322 @@ +int opPUNPCKLDQ_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].l[1] = MM[rm].l[0]; + cycles--; + } + else + { + uint32_t src; + + src = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[1] = src; + + cycles -= 2; + } + return 0; +} +int opPUNPCKLDQ_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].l[1] = MM[rm].l[0]; + cycles--; + } + else + { + uint32_t src; + + src = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[1] = src; + + cycles -= 2; + } + return 0; +} + +int opPUNPCKHDQ_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = src.l[1]; + + return 0; +} +int opPUNPCKHDQ_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = src.l[1]; + + return 0; +} + +int opPUNPCKLBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[7] = src.b[3]; + MM[reg].b[6] = MM[reg].b[3]; + MM[reg].b[5] = src.b[2]; + MM[reg].b[4] = MM[reg].b[2]; + MM[reg].b[3] = src.b[1]; + MM[reg].b[2] = MM[reg].b[1]; + MM[reg].b[1] = src.b[0]; + MM[reg].b[0] = MM[reg].b[0]; + + return 0; +} +int opPUNPCKLBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[7] = src.b[3]; + MM[reg].b[6] = MM[reg].b[3]; + MM[reg].b[5] = src.b[2]; + MM[reg].b[4] = MM[reg].b[2]; + MM[reg].b[3] = src.b[1]; + MM[reg].b[2] = MM[reg].b[1]; + MM[reg].b[1] = src.b[0]; + MM[reg].b[0] = MM[reg].b[0]; + + return 0; +} + +int opPUNPCKHBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = MM[reg].b[4]; + MM[reg].b[1] = src.b[4]; + MM[reg].b[2] = MM[reg].b[5]; + MM[reg].b[3] = src.b[5]; + MM[reg].b[4] = MM[reg].b[6]; + MM[reg].b[5] = src.b[6]; + MM[reg].b[6] = MM[reg].b[7]; + MM[reg].b[7] = src.b[7]; + + return 0; +} +int opPUNPCKHBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = MM[reg].b[4]; + MM[reg].b[1] = src.b[4]; + MM[reg].b[2] = MM[reg].b[5]; + MM[reg].b[3] = src.b[5]; + MM[reg].b[4] = MM[reg].b[6]; + MM[reg].b[5] = src.b[6]; + MM[reg].b[6] = MM[reg].b[7]; + MM[reg].b[7] = src.b[7]; + + return 0; +} + +int opPUNPCKLWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[3] = src.w[1]; + MM[reg].w[2] = MM[reg].w[1]; + MM[reg].w[1] = src.w[0]; + MM[reg].w[0] = MM[reg].w[0]; + + return 0; +} +int opPUNPCKLWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[3] = src.w[1]; + MM[reg].w[2] = MM[reg].w[1]; + MM[reg].w[1] = src.w[0]; + MM[reg].w[0] = MM[reg].w[0]; + + return 0; +} + +int opPUNPCKHWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = MM[reg].w[2]; + MM[reg].w[1] = src.w[2]; + MM[reg].w[2] = MM[reg].w[3]; + MM[reg].w[3] = src.w[3]; + + return 0; +} +int opPUNPCKHWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = MM[reg].w[2]; + MM[reg].w[1] = src.w[2]; + MM[reg].w[2] = MM[reg].w[3]; + MM[reg].w[3] = src.w[3]; + + return 0; +} + +int opPACKSSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sb[0] = SSATB(dst.sw[0]); + MM[reg].sb[1] = SSATB(dst.sw[1]); + MM[reg].sb[2] = SSATB(dst.sw[2]); + MM[reg].sb[3] = SSATB(dst.sw[3]); + MM[reg].sb[4] = SSATB(src.sw[0]); + MM[reg].sb[5] = SSATB(src.sw[1]); + MM[reg].sb[6] = SSATB(src.sw[2]); + MM[reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} +int opPACKSSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sb[0] = SSATB(dst.sw[0]); + MM[reg].sb[1] = SSATB(dst.sw[1]); + MM[reg].sb[2] = SSATB(dst.sw[2]); + MM[reg].sb[3] = SSATB(dst.sw[3]); + MM[reg].sb[4] = SSATB(src.sw[0]); + MM[reg].sb[5] = SSATB(src.sw[1]); + MM[reg].sb[6] = SSATB(src.sw[2]); + MM[reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} + +int opPACKUSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].b[0] = USATB(dst.sw[0]); + MM[reg].b[1] = USATB(dst.sw[1]); + MM[reg].b[2] = USATB(dst.sw[2]); + MM[reg].b[3] = USATB(dst.sw[3]); + MM[reg].b[4] = USATB(src.sw[0]); + MM[reg].b[5] = USATB(src.sw[1]); + MM[reg].b[6] = USATB(src.sw[2]); + MM[reg].b[7] = USATB(src.sw[3]); + + return 0; +} +int opPACKUSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].b[0] = USATB(dst.sw[0]); + MM[reg].b[1] = USATB(dst.sw[1]); + MM[reg].b[2] = USATB(dst.sw[2]); + MM[reg].b[3] = USATB(dst.sw[3]); + MM[reg].b[4] = USATB(src.sw[0]); + MM[reg].b[5] = USATB(src.sw[1]); + MM[reg].b[6] = USATB(src.sw[2]); + MM[reg].b[7] = USATB(src.sw[3]); + + return 0; +} + +int opPACKSSDW_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sw[0] = SSATW(dst.sl[0]); + MM[reg].sw[1] = SSATW(dst.sl[1]); + MM[reg].sw[2] = SSATW(src.sl[0]); + MM[reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} +int opPACKSSDW_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sw[0] = SSATW(dst.sl[0]); + MM[reg].sw[1] = SSATW(dst.sl[1]); + MM[reg].sw[2] = SSATW(src.sl[0]); + MM[reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} diff --git a/src/x86_ops_mmx_shift.h b/src/x86_ops_mmx_shift.h new file mode 100644 index 0000000..21c072b --- /dev/null +++ b/src/x86_ops_mmx_shift.h @@ -0,0 +1,452 @@ +#define MMX_GETSHIFT() \ + if (mod == 3) \ + { \ + shift = MM[rm].b[0]; \ + cycles--; \ + } \ + else \ + { \ + shift = readmemb(easeg, eaaddr); if (abrt) return 0; \ + cycles -= 2; \ + } + +int opPSxxW_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + break; + case 0x20: /*PSRAW*/ + if (shift > 15) + shift = 15; + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + break; + default: + pclog("Bad PSxxW (0F 71) instruction %02X\n", op); + pc = oldpc; + x86illegal(); + return 0; + } + + cycles--; + return 0; +} + +int opPSLLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + + return 0; +} +int opPSLLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + + return 0; +} + +int opPSRLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + + return 0; +} +int opPSRLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + + return 0; +} + +int opPSRAW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + + return 0; +} +int opPSRAW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + + return 0; +} + +int opPSxxD_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLD*/ + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + break; + case 0x20: /*PSRAD*/ + if (shift > 31) + shift = 31; + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + break; + case 0x30: /*PSLLD*/ + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + break; + default: + pclog("Bad PSxxD (0F 72) instruction %02X\n", op); + pc = oldpc; + x86illegal(); + return 0; + } + + cycles--; + return 0; +} + +int opPSLLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + + return 0; +} +int opPSLLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + + return 0; +} + +int opPSRLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + + return 0; +} +int opPSRLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + + return 0; +} + +int opPSRAD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + + return 0; +} +int opPSRAD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + + return 0; +} + +int opPSxxQ_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + break; + case 0x20: /*PSRAW*/ + if (shift > 63) + shift = 63; + MM[reg].sq >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + break; + default: + pclog("Bad PSxxQ (0F 73) instruction %02X\n", op); + pc = oldpc; + x86illegal(); + return 0; + } + + cycles--; + return 0; +} + +int opPSLLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + + return 0; +} +int opPSLLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + + return 0; +} + +int opPSRLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + + return 0; +} +int opPSRLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + + return 0; +} diff --git a/src/x86seg.c b/src/x86seg.c index f794187..8665961 100644 --- a/src/x86seg.c +++ b/src/x86seg.c @@ -2394,7 +2394,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) cr3=new_cr3; - pclog("TS New CR3 %08X\n",cr3); +// pclog("TS New CR3 %08X\n",cr3); flushmmucache(); diff --git a/src/x87.c b/src/x87.c index 7f701fc..176308a 100644 --- a/src/x87.c +++ b/src/x87.c @@ -60,6 +60,8 @@ static inline uint32_t geteal() double ST[8]; +MMX_REG MM[8]; +int ismmx = 0; uint16_t npxs,npxc,tag; int TOP; @@ -90,6 +92,19 @@ int TOP; dst = src1 / (double)src2; \ } while (0) +void x87_set_mmx() +{ + TOP = 0; + tag = 0; + ismmx = 1; +} + +void x87_emms() +{ + tag = 0xffff; + ismmx = 0; +} + void x87_checkexceptions() { } @@ -100,15 +115,31 @@ void x87_reset() void x87_dumpregs() { - pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); - pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]); + if (ismmx) + { + pclog("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", MM[0].q, MM[1].q, MM[2].q, MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q); + } + else + { + pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]); + } pclog("Status = %04X Control = %04X Tag = %04X\n",npxs,npxc,tag); } void x87_print() { - pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",ST[TOP&7],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); - pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t TOP=%i CR=%04X SR=%04X TAG=%04X\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7], TOP, npxc, npxs, tag); + if (ismmx) + { + pclog("\tMM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\t", MM[0].q, MM[1].q, MM[2].q, MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q); + } + else + { + pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",ST[TOP&7],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t TOP=%i CR=%04X SR=%04X TAG=%04X\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7], TOP, npxc, npxs, tag); + } } void x87_push(double i) @@ -215,6 +246,20 @@ void x87_st80(double d) writememw(easeg,eaaddr+8,test.begin); } +void x87_ldmmx(MMX_REG *r) +{ + r->l[0] = readmeml(easeg, eaaddr); + r->l[1] = readmeml(easeg, eaaddr + 4); + r->w[4] = readmemw(easeg, eaaddr + 8); +} + +void x87_stmmx(MMX_REG r) +{ + writememl(easeg, eaaddr, r.l[0]); + writememl(easeg, eaaddr + 4, r.l[1]); + writememw(easeg, eaaddr + 8, 0xffff); +} + void x87_d8() { union @@ -545,7 +590,7 @@ void x87_d9() cycles-=7; return; case 3: /*FSTP single-precision*/ - if (fplog) pclog("FSTPs %08X:%08X\n", easeg, eaaddr); + if (fplog) pclog("FSTPs %08X:%08X %f\n", easeg, eaaddr, ST(0)); ts.s=(float)ST(0); seteal(ts.i); if (abrt) { pclog("FSTP sp abort\n"); return; } // if (pc==0x3f50c) pclog("FSTP %f %f %08X\n",ST(0),ts.s,ts.i); @@ -969,7 +1014,6 @@ void x87_dd() cycles-=8; return; case 4: /*FRSTOR*/ - if (fplog) pclog("FRSTOR %08X:%08X\n", easeg, eaaddr); switch ((cr0&1)|(op32&0x100)) { case 0x000: /*16-bit real mode*/ @@ -989,23 +1033,33 @@ void x87_dd() eaaddr+=28; break; } - ST(0)=x87_ld80(); eaaddr+=10; - ST(1)=x87_ld80(); eaaddr+=10; - ST(2)=x87_ld80(); eaaddr+=10; - ST(3)=x87_ld80(); eaaddr+=10; - ST(4)=x87_ld80(); eaaddr+=10; - ST(5)=x87_ld80(); eaaddr+=10; - ST(6)=x87_ld80(); eaaddr+=10; - ST(7)=x87_ld80(); + x87_ldmmx(&MM[0]); ST(0)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[1]); ST(1)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[2]); ST(2)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[3]); ST(3)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[4]); ST(4)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[5]); ST(5)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[6]); ST(6)=x87_ld80(); eaaddr += 10; + x87_ldmmx(&MM[7]); ST(7)=x87_ld80(); + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w == 0xffff && MM[1].w == 0xffff && MM[2].w == 0xffff && MM[3].w == 0xffff && + MM[4].w == 0xffff && MM[5].w == 0xffff && MM[6].w == 0xffff && MM[7].w == 0xffff && + !TOP && !tag) + ismmx = 1; + cycles-=(cr0&1)?34:44; + if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, eaaddr, ismmx, TOP, tag); /* pclog("new TOP %i\n", TOP); pclog("%04X %04X %04X %f %f %f %f %f %f %f %f\n", npxc, npxs, tag, ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7));*/ return; case 6: /*FSAVE*/ - if (fplog) pclog("FSAVE %08X:%08X\n", easeg, eaaddr); + if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, eaaddr, ismmx); npxs = (npxs & ~(7 << 11)) | (TOP << 11); /* pclog("old TOP %i %04X\n", TOP, npxs); pclog("%04X %04X %04X %f %f %f %f %f %f %f %f\n", npxc, npxs, tag, ST(0), ST(1), ST(2), ST(3), ST(4), ST(5), ST(6), ST(7));*/ + switch ((cr0&1)|(op32&0x100)) { case 0x000: /*16-bit real mode*/ @@ -1015,14 +1069,28 @@ void x87_dd() writememw(easeg,eaaddr+6,x87_pc_off); writememw(easeg,eaaddr+10,x87_op_off); eaaddr+=14; - x87_st80(ST(0)); eaaddr+=10; - x87_st80(ST(1)); eaaddr+=10; - x87_st80(ST(2)); eaaddr+=10; - x87_st80(ST(3)); eaaddr+=10; - x87_st80(ST(4)); eaaddr+=10; - x87_st80(ST(5)); eaaddr+=10; - x87_st80(ST(6)); eaaddr+=10; - x87_st80(ST(7)); + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + } break; case 0x001: /*16-bit protected mode*/ writememw(easeg,eaaddr,npxc); @@ -1033,14 +1101,28 @@ void x87_dd() writememw(easeg,eaaddr+10,x87_op_off); writememw(easeg,eaaddr+12,x87_op_seg); eaaddr+=14; - x87_st80(ST(0)); eaaddr+=10; - x87_st80(ST(1)); eaaddr+=10; - x87_st80(ST(2)); eaaddr+=10; - x87_st80(ST(3)); eaaddr+=10; - x87_st80(ST(4)); eaaddr+=10; - x87_st80(ST(5)); eaaddr+=10; - x87_st80(ST(6)); eaaddr+=10; - x87_st80(ST(7)); + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + } break; case 0x100: /*32-bit real mode*/ writememw(easeg,eaaddr,npxc); @@ -1050,14 +1132,28 @@ void x87_dd() writememw(easeg,eaaddr+20,x87_op_off); writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); eaaddr+=28; - x87_st80(ST(0)); eaaddr+=10; - x87_st80(ST(1)); eaaddr+=10; - x87_st80(ST(2)); eaaddr+=10; - x87_st80(ST(3)); eaaddr+=10; - x87_st80(ST(4)); eaaddr+=10; - x87_st80(ST(5)); eaaddr+=10; - x87_st80(ST(6)); eaaddr+=10; - x87_st80(ST(7)); + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + } break; case 0x101: /*32-bit protected mode*/ writememw(easeg,eaaddr,npxc); @@ -1068,14 +1164,28 @@ void x87_dd() writememl(easeg,eaaddr+20,x87_op_off); writememl(easeg,eaaddr+24,x87_op_seg); eaaddr+=28; - x87_st80(ST(0)); eaaddr+=10; - x87_st80(ST(1)); eaaddr+=10; - x87_st80(ST(2)); eaaddr+=10; - x87_st80(ST(3)); eaaddr+=10; - x87_st80(ST(4)); eaaddr+=10; - x87_st80(ST(5)); eaaddr+=10; - x87_st80(ST(6)); eaaddr+=10; - x87_st80(ST(7)); + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + } break; } cycles-=(cr0&1)?56:67; @@ -1293,3 +1403,4 @@ void x87_df() // fatal("Bad x87 DF opcode %i %02X\n",reg,rmdat32&0xFF); x86illegal(); } + diff --git a/src/x87.h b/src/x87.h index 00842cd..84988bd 100644 --- a/src/x87.h +++ b/src/x87.h @@ -1,3 +1,20 @@ uint32_t x87_pc_off,x87_op_off; uint16_t x87_pc_seg,x87_op_seg; extern uint32_t op32; + +typedef union MMX_REG +{ + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[5]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; +} MMX_REG; + +extern MMX_REG MM[8]; + +void x87_set_mmx(); +void x87_emms();