/* Pcsx2 - Pc Ps2 Emulator * Copyright (C) 2002-2003 Pcsx2 Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include "Common.h" #include "InterTables.h" #include "ix86/ix86.h" #include "iR5900.h" #ifdef __WIN32__ #pragma warning(disable:4244) #pragma warning(disable:4761) #endif /********************************************************* * Register arithmetic * * Format: OP rd, rs, rt * *********************************************************/ // NOTE: The reason ADD/SUB/etc are so large is because they are very commonly // used and recompiler needs to cover ALL possible usages to minimize code size (zerofrog) #ifndef ARITHMETIC_RECOMPILE REC_FUNC(ADD); REC_FUNC(ADDU); REC_FUNC(DADD); REC_FUNC(DADDU); REC_FUNC(SUB); REC_FUNC(SUBU); REC_FUNC(DSUB); REC_FUNC(DSUBU); REC_FUNC(AND); REC_FUNC(OR); REC_FUNC(XOR); REC_FUNC(NOR); REC_FUNC(SLT); REC_FUNC(SLTU); #elif defined(EE_CONST_PROP) //// ADD void recADD_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] + g_cpuConstRegs[_Rt_].SL[0]; } void recADD_constv(int info, int creg, int vreg) { assert( !(info&PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; if( g_cpuConstRegs[ creg ].UL[0] ) { u32* ptempmem; ptempmem = _eeGetConstReg(creg); if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); PADDDMtoR(EEREC_D, (u32)ptempmem); _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); } else { // just move and sign extend if( EEINST_HASLIVE1(vreg) ) { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); } else { _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, mmreg, vreg); } } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[ creg ].UL[0]) ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); if( EEINST_HASLIVE1(vreg) && EEINST_ISLIVE1(_Rd_) ) { MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); } else { if( g_cpuConstRegs[creg].UL[0] ) { MOVDMtoMMX(mmreg, (u32)_eeGetConstReg(creg)); PADDDMtoR(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); } else { if( EEINST_ISLIVE1(_Rd_) ) { _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); } else { MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); EEINST_RESETHASLIVE1(_Rd_); } } } } else { if( _Rd_ == vreg ) { ADD32ItoM((int)&cpuRegs.GPR.r[_Rd_].UL[ 0 ], g_cpuConstRegs[creg].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); if( g_cpuConstRegs[ creg ].UL[0] ) ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[0] ); if( EEINST_ISLIVE1(_Rd_) ) { CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } else { EEINST_RESETHASLIVE1(_Rd_); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); } } } } } // s is constant void recADD_consts(int info) { recADD_constv(info, _Rs_, _Rt_); EEINST_SETSIGNEXT(_Rd_); EEINST_SETSIGNEXT(_Rt_); } // t is constant void recADD_constt(int info) { recADD_constv(info, _Rt_, _Rs_); EEINST_SETSIGNEXT(_Rd_); EEINST_SETSIGNEXT(_Rs_); } // nothing is constant void recADD_(int info) { assert( !(info&PROCESS_EE_XMM) ); EEINST_SETSIGNEXT(_Rd_); EEINST_SETSIGNEXT(_Rs_); EEINST_SETSIGNEXT(_Rt_); if( info & PROCESS_EE_MMX ) { if( EEREC_D == EEREC_S ) PADDDRtoR(EEREC_D, EEREC_T); else if( EEREC_D == EEREC_T ) PADDDRtoR(EEREC_D, EEREC_S); else { MOVQRtoR(EEREC_D, EEREC_T); PADDDRtoR(EEREC_D, EEREC_S); } if( EEINST_ISLIVE1(_Rd_) ) { // sign extend _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); } else { EEINST_RESETHASLIVE1(_Rd_); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_) ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); EEINST_RESETHASLIVE1(_Rd_); MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); PADDDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); } else { if( _Rd_ == _Rs_ ) { if( _Rd_ == _Rt_ ) SHL32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 1); // mult by 2 else { MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); } if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); else EEINST_RESETHASLIVE1(_Rd_); return; } else if( _Rd_ == _Rt_ ) { EEINST_RESETHASLIVE1(_Rd_); MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], ECX); if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); if( _Rs_ != _Rt_ ) ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); else SHL32ItoR(EAX, 1); // mult by 2 if( EEINST_ISLIVE1(_Rd_) ) { CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } else { EEINST_RESETHASLIVE1(_Rd_); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); } } } } } EERECOMPILE_CODE0(ADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); //// ADDU void recADDU( void ) { recADD( ); } //// DADD void recDADD_const( void ) { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] + g_cpuConstRegs[_Rt_].SD[0]; } void recDADD_constv(int info, int creg, int vreg) { assert( !(info&PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; assert( cpucaps.hasStreamingSIMD2Extensions ); if( g_cpuConstRegs[ creg ].UD[0] ) { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); PADDQMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); } else { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); if( g_cpuConstRegs[ creg ].UD[0] ) PADDQMtoR(mmreg, (u32)_eeGetConstReg(creg)); } else { if( g_cpuConstRegs[ creg ].UL[0] == 0 && g_cpuConstRegs[ creg ].UL[1] == 0 && _hasFreeMMXreg() ) { // copy int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); if( EEINST_ISLIVE1(_Rd_) ) MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); else { MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ]); EEINST_RESETHASLIVE1(_Rd_); } } else { if( _Rd_ == vreg ) { if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ creg ].UL[ 0 ] || g_cpuConstRegs[ creg ].UL[ 1 ]) ) { ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); ADC32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ creg ].UL[ 1 ] ); } else if( g_cpuConstRegs[ creg ].UL[ 0 ] ) { EEINST_RESETHASLIVE1(_Rd_); ADD32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ creg ].UL[ 0 ] ); } return; } MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { ADD32ItoR( EAX, g_cpuConstRegs[ creg ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) ADC32ItoR( EDX, g_cpuConstRegs[ creg ].UL[ 1 ] ); } MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); } } } } void recDADD_consts(int info) { recDADD_constv(info, _Rs_, _Rt_); } void recDADD_constt(int info) { recDADD_constv(info, _Rt_, _Rs_); } void recDADD_(int info) { assert( !(info&PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { assert( cpucaps.hasStreamingSIMD2Extensions ); if( EEREC_D == EEREC_S ) PADDQRtoR(EEREC_D, EEREC_T); else if( EEREC_D == EEREC_T ) PADDQRtoR(EEREC_D, EEREC_S); else { MOVQRtoR(EEREC_D, EEREC_T); PADDQRtoR(EEREC_D, EEREC_S); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); if( _Rs_ != _Rt_ ) PADDQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); else PSLLQItoR(mmreg, 1); // mult by 2 } else { if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ vreg ].UL[ 1 ] ); ADD32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX); if( EEINST_ISLIVE1(_Rd_) ) ADC32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX); else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); } } } } EERECOMPILE_CODE0(DADD, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT); //// DADDU void recDADDU( void ) { recDADD( ); } //// SUB void recSUB_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SL[0] - g_cpuConstRegs[_Rt_].SL[0]; } void recSUB_consts(int info) { assert( !(info&PROCESS_EE_XMM) ); EEINST_SETSIGNEXT(_Rt_); EEINST_SETSIGNEXT(_Rd_); if( info & PROCESS_EE_MMX ) { if( g_cpuConstRegs[ _Rs_ ].UL[0] ) { if( EEREC_D != EEREC_T ) { MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); PSUBDRtoR(EEREC_D, EEREC_T); if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); else EEINST_RESETHASLIVE1(_Rd_); } else { int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVDMtoMMX(t0reg, (u32)_eeGetConstReg(_Rs_)); PSUBDRtoR(t0reg, EEREC_T); // swap mmx regs mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); else EEINST_RESETHASLIVE1(_Rd_); } } else { // just move and sign extend if( EEREC_D != EEREC_T ) { PXORRtoR(EEREC_D, EEREC_D); PSUBDRtoR(EEREC_D, EEREC_T); if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); else EEINST_RESETHASLIVE1(_Rd_); } else { int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); PXORRtoR(t0reg, t0reg); PSUBDRtoR(t0reg, EEREC_T); // swap mmx regs.. don't ask mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; if( EEINST_ISLIVE1(_Rd_) ) _signExtendGPRtoMMX(t0reg, _Rd_, 0); else EEINST_RESETHASLIVE1(_Rd_); } } } else { if( _Rd_ == _Rt_ ) { if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) SUB32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rs_ ].UL[ 0 ]); NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); else EEINST_RESETHASLIVE1(_Rd_); } else { if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ) { MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); NEG32R(EAX); } if( EEINST_ISLIVE1(_Rd_) ) { CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } else { EEINST_RESETHASLIVE1(_Rd_); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); } } } } void recSUB_constt(int info) { assert( !(info&PROCESS_EE_XMM) ); EEINST_SETSIGNEXT(_Rs_); EEINST_SETSIGNEXT(_Rd_); if( info & PROCESS_EE_MMX ) { if( g_cpuConstRegs[ _Rt_ ].UL[0] ) { u32* ptempmem = _eeGetConstReg(_Rt_); if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); PSUBDMtoR(EEREC_D, (u32)ptempmem); _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); } else { // just move and sign extend if( EEINST_HASLIVE1(_Rs_) ) { if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); } else { _signExtendGPRMMXtoMMX(EEREC_D, _Rd_, EEREC_S, _Rs_); } } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && (!EEINST_ISLIVE1(_Rd_) || !g_cpuConstRegs[_Rt_].UL[0]) ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); if( EEINST_HASLIVE1(_Rs_) && EEINST_ISLIVE1(_Rd_) ) { MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); } else { if( g_cpuConstRegs[_Rt_].UL[0] ) { MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); PSUBDMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); } else { if( EEINST_ISLIVE1(_Rd_) ) { _signExtendMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); } else { MOVDMtoMMX(mmreg, (u32)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); EEINST_RESETHASLIVE1(_Rd_); } } } } else { if( _Rd_ == _Rs_ ) { if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { SUB32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], g_cpuConstRegs[ _Rt_ ].UL[ 0 ]); if( EEINST_ISLIVE1(_Rd_) ) _signExtendSFtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ]); else EEINST_RESETHASLIVE1(_Rd_); } } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) { CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } else { EEINST_RESETHASLIVE1(_Rd_); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); } } } } } void recSUB_(int info) { assert( !(info&PROCESS_EE_XMM) ); EEINST_SETSIGNEXT(_Rs_); EEINST_SETSIGNEXT(_Rt_); EEINST_SETSIGNEXT(_Rd_); if( info & PROCESS_EE_MMX ) { if( EEREC_D == EEREC_S ) PSUBDRtoR(EEREC_D, EEREC_T); else if( EEREC_D == EEREC_T ) { int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVQRtoR(t0reg, EEREC_S); PSUBDRtoR(t0reg, EEREC_T); // swap mmx regs.. don't ask mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; info = (info&~PROCESS_EE_SET_D(0xf))|PROCESS_EE_SET_D(t0reg); } else { MOVQRtoR(EEREC_D, EEREC_S); PSUBDRtoR(EEREC_D, EEREC_T); } if( EEINST_ISLIVE1(_Rd_) ) { // sign extend _signExtendGPRtoMMX(EEREC_D, _Rd_, 0); } else { EEINST_RESETHASLIVE1(_Rd_); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && !EEINST_ISLIVE1(_Rd_)) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); EEINST_RESETHASLIVE1(_Rd_); MOVDMtoMMX(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[0] ); PSUBDMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[0] ); } else { if( !EEINST_ISLIVE1(_Rd_) ) { if( _Rd_ == _Rs_) { EEINST_RESETHASLIVE1(_Rd_); MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); return; } } MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) { CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } else { EEINST_RESETHASLIVE1(_Rd_); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); } } } } EERECOMPILE_CODE0(SUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); //// SUBU void recSUBU( void ) { recSUB( ); } //// DSUB void recDSUB_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] - g_cpuConstRegs[_Rt_].SD[0]; } void recDSUB_consts(int info) { assert( !(info&PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { assert( cpucaps.hasStreamingSIMD2Extensions ); if( g_cpuConstRegs[ _Rs_ ].UD[0] ) { // flush if( EEREC_D != EEREC_T ) { MOVQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); PSUBQRtoR(EEREC_D, EEREC_T); } else { int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVQMtoR(t0reg, (u32)_eeGetConstReg(_Rs_)); PSUBQRtoR(t0reg, EEREC_T); // swap mmx regs.. don't ask mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; } } else { // just move and sign extend if( EEREC_D != EEREC_T ) { PXORRtoR(EEREC_D, EEREC_D); PSUBQRtoR(EEREC_D, EEREC_T); } else { int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); PXORRtoR(t0reg, t0reg); PSUBQRtoR(t0reg, EEREC_T); // swap mmx regs.. don't ask mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; } } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(mmreg, (u32)_eeGetConstReg(_Rs_)); PSUBQMtoR(mmreg, (u32)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); } else { if( g_cpuConstRegs[ _Rs_ ].UL[ 0 ] || g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ) { MOV32ItoR( EAX, g_cpuConstRegs[ _Rs_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoR( EDX, g_cpuConstRegs[ _Rs_ ].UL[ 1 ] ); SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); } else { if( _Rd_ == _Rt_ ) { // negate _Rt_ all in memory if( EEINST_ISLIVE1(_Rd_) ) { MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); NEG32M((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); ADC32ItoR(EDX, 0); NEG32R(EDX); MOV32RtoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX); } else { EEINST_RESETHASLIVE1(_Rd_); NEG32M((int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ]); } return; } MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); // take negative of 64bit number NEG32R(EAX); if( EEINST_ISLIVE1(_Rd_) ) { ADC32ItoR(EDX, 0); NEG32R(EDX); } else { EEINST_RESETHASLIVE1(_Rd_); } } MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); else { EEINST_RESETHASLIVE1(_Rd_); } } } } void recDSUB_constt(int info) { assert( !(info&PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { assert( cpucaps.hasStreamingSIMD2Extensions ); if( g_cpuConstRegs[ _Rt_ ].UD[0] ) { if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); PSUBQMtoR(EEREC_D, (u32)_eeGetConstReg(_Rt_)); } else { if( EEREC_D != EEREC_S ) MOVQRtoR(EEREC_D, EEREC_S); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); if( g_cpuConstRegs[_Rt_].UD[0] ) PSUBQMtoR(mmreg, (u32)_eeGetConstReg(_Rt_)); } else { if( _Rd_ == _Rs_ ) { if( EEINST_ISLIVE1(_Rd_) && (g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ]) ) { SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); SBB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[1], g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); } else if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ) { EEINST_RESETHASLIVE1(_Rd_); SUB32ItoM( (u32)&cpuRegs.GPR.r[_Rd_].UL[0], g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); } } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); if( g_cpuConstRegs[ _Rt_ ].UL[ 0 ] || g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ) { SUB32ItoR( EAX, g_cpuConstRegs[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) SBB32ItoR( EDX, g_cpuConstRegs[ _Rt_ ].UL[ 1 ] ); } MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); else EEINST_RESETHASLIVE1(_Rd_); } } } } void recDSUB_(int info) { assert( !(info&PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { assert( cpucaps.hasStreamingSIMD2Extensions ); if( EEREC_D == EEREC_S ) PSUBQRtoR(EEREC_D, EEREC_T); else if( EEREC_D == EEREC_T ) { int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVQRtoR(t0reg, EEREC_S); PSUBQRtoR(t0reg, EEREC_T); // swap mmx regs.. don't ask mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; } else { MOVQRtoR(EEREC_D, EEREC_S); PSUBQRtoR(EEREC_D, EEREC_T); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) && cpucaps.hasStreamingSIMD2Extensions ) { int mmreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rs_].UL[ 0 ]); PSUBQMtoR(mmreg, (int)&cpuRegs.GPR.r[_Rt_].UL[ 0 ]); } else { if( _Rd_ == _Rs_ ) { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); SUB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) SBB32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); if( EEINST_ISLIVE1(_Rd_) ) SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); else EEINST_RESETHASLIVE1(_Rd_); } } } } EERECOMPILE_CODE0(DSUB, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); //// DSUBU void recDSUBU( void ) { recDSUB( ); } //// AND void recAND_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] & g_cpuConstRegs[_Rt_].UD[0]; } void recAND_constv(int info, int creg, int vreg) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { _flushConstReg(creg); if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); PANDMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); } else { PXORRtoR(EEREC_D, EEREC_D); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); PANDMtoR(rdreg, (u32)_eeGetConstReg(creg) ); } else { if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { if( _Rd_ == vreg ) { AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) { if( g_cpuConstRegs[creg].UL[1] != 0xffffffff ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); } else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); AND32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) AND32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); else EEINST_RESETHASLIVE1(_Rd_); } } else { MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ], 0); if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, 0); else EEINST_RESETHASLIVE1(_Rd_); } } } } void recAND_consts(int info) { recAND_constv(info, _Rs_, _Rt_); } void recAND_constt(int info) { recAND_constv(info, _Rt_, _Rs_); } void recLogicalOp(int info, int op) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { if( EEREC_D == EEREC_S ) LogicalOpRtoR(EEREC_D, EEREC_T, op); else if( EEREC_D == EEREC_T ) LogicalOpRtoR(EEREC_D, EEREC_S, op); else { MOVQRtoR(EEREC_D, EEREC_S); LogicalOpRtoR(EEREC_D, EEREC_T, op); } } else if( (g_pCurInstInfo->regs[_Rs_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rt_]&EEINST_MMX) || (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) ) { int rsreg, rtreg, rdreg; _addNeededMMXreg(MMX_GPR+_Rs_); _addNeededMMXreg(MMX_GPR+_Rt_); _addNeededMMXreg(MMX_GPR+_Rd_); rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); rsreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rs_, MODE_READ); rtreg = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_READ); SetMMXstate(); if( rdreg == rsreg ) { if( rtreg >= 0 ) LogicalOpRtoR(rdreg, rtreg, op); else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ], op); } else { if( rdreg != rtreg ) { if( rtreg >= 0 ) MOVQRtoR(rdreg, rtreg); else MOVQMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rt_ ]); } if( rsreg >= 0 ) LogicalOpRtoR(rdreg, rsreg, op); else LogicalOpMtoR(rdreg, (int)&cpuRegs.GPR.r[ _Rs_ ], op); } } else { if( _Rd_ == _Rs_ || _Rd_ == _Rt_ ) { int vreg = _Rd_ == _Rs_ ? _Rt_ : _Rs_; MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR(EDX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX, op ); if( EEINST_ISLIVE1(_Rd_) ) LogicalOp32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ] + 4, EDX, op ); if( op == 3 ) { NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]); if( EEINST_ISLIVE1(_Rd_) ) NOT32M((int)&cpuRegs.GPR.r[ _Rd_ ]+4); } if( !EEINST_ISLIVE1(_Rd_) ) EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rs_ ]); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ] + 4 ); LogicalOp32MtoR(EAX, (int)&cpuRegs.GPR.r[ _Rt_ ], op ); if( EEINST_ISLIVE1(_Rd_) ) LogicalOp32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rt_ ] + 4, op ); if( op == 3 ) { NOT32R(EAX); if( EEINST_ISLIVE1(_Rd_) ) NOT32R(ECX); } MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); else EEINST_RESETHASLIVE1(_Rd_); } } } void recAND_(int info) { recLogicalOp(info, 0); } EERECOMPILE_CODE0(AND, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); //// OR void recOR_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]; } void recOR_constv(int info, int creg, int vreg) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { _flushConstReg(creg); if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); PORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); } else { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); } } else { if( _Rd_ == vreg ) { OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) { if( g_cpuConstRegs[creg].UL[1] ) OR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); } else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); else EEINST_RESETHASLIVE1(_Rd_); } } } } void recOR_consts(int info) { recOR_constv(info, _Rs_, _Rt_); } void recOR_constt(int info) { recOR_constv(info, _Rt_, _Rs_); } void recOR_(int info) { recLogicalOp(info, 1); } EERECOMPILE_CODE0(OR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); //// XOR void recXOR_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] ^ g_cpuConstRegs[_Rt_].UD[0]; } void recXOR_constv(int info, int creg, int vreg) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { _flushConstReg(creg); if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); PXORMtoR(EEREC_D, (u32)&cpuRegs.GPR.r[creg].UL[0] ); } else { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); } } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); SetMMXstate(); MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { PXORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); } } else { if( _Rd_ == vreg ) { XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], g_cpuConstRegs[creg].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) { if( g_cpuConstRegs[creg].UL[1] ) XOR32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], g_cpuConstRegs[creg].UL[1]); } else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); if( g_cpuConstRegs[ creg ].UL[0] ) XOR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) XOR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); else EEINST_RESETHASLIVE1(_Rd_); } } } } void recXOR_consts(int info) { recXOR_constv(info, _Rs_, _Rt_); } void recXOR_constt(int info) { recXOR_constv(info, _Rt_, _Rs_); } void recXOR_(int info) { recLogicalOp(info, 2); } EERECOMPILE_CODE0(XOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); //// NOR void recNOR_const() { g_cpuConstRegs[_Rd_].UD[0] =~(g_cpuConstRegs[_Rs_].UD[0] | g_cpuConstRegs[_Rt_].UD[0]); } void recNOR_constv(int info, int creg, int vreg) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { int mmreg = vreg == _Rt_ ? EEREC_T : EEREC_S; int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); if( g_cpuConstRegs[ creg ].UL[0] || g_cpuConstRegs[ creg ].UL[1] ) { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); PORMtoR(EEREC_D, (u32)_eeGetConstReg(creg)); } else { if( EEREC_D != mmreg ) MOVQRtoR(EEREC_D, mmreg); } // take the NOT PCMPEQDRtoR( t0reg,t0reg); PXORRtoR( EEREC_D,t0reg); _freeMMXreg(t0reg); } else { if( (g_pCurInstInfo->regs[_Rd_]&EEINST_MMX) || (_Rd_ != vreg && _hasFreeMMXreg()) ) { int rdreg = _allocMMXreg(-1, MMX_GPR+_Rd_, MODE_WRITE); int t0reg = _allocMMXreg(-1, MMX_TEMP, 0); SetMMXstate(); MOVQMtoR(rdreg, (u32)&cpuRegs.GPR.r[vreg].UL[0] ); PCMPEQDRtoR( t0reg,t0reg); if( g_cpuConstRegs[ creg ].UD[0] ) PORMtoR(rdreg, (u32)_eeGetConstReg(creg) ); // take the NOT PXORRtoR( rdreg,t0reg); _freeMMXreg(t0reg); } else { if( _Rd_ == vreg ) { NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) NOT32M((int)&cpuRegs.GPR.r[ vreg ].UL[1]); if( g_cpuConstRegs[creg].UL[0] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[0], ~g_cpuConstRegs[creg].UL[0]); if( EEINST_ISLIVE1(_Rd_) ) { if( g_cpuConstRegs[creg].UL[1] ) AND32ItoM((int)&cpuRegs.GPR.r[ vreg ].UL[1], ~g_cpuConstRegs[creg].UL[1]); } else EEINST_RESETHASLIVE1(_Rd_); } else { MOV32MtoR(EAX, (int)&cpuRegs.GPR.r[ vreg ]); if( EEINST_ISLIVE1(_Rd_) ) MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ vreg ] + 4 ); if( g_cpuConstRegs[ creg ].UL[0] ) OR32ItoR(EAX, g_cpuConstRegs[ creg ].UL[0]); if( g_cpuConstRegs[ creg ].UL[1] && EEINST_ISLIVE1(_Rd_) ) OR32ItoR(ECX, g_cpuConstRegs[ creg ].UL[1]); NOT32R(EAX); if( EEINST_ISLIVE1(_Rd_) ) NOT32R(ECX); MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ], EAX); if( EEINST_ISLIVE1(_Rd_) ) MOV32RtoM((int)&cpuRegs.GPR.r[ _Rd_ ]+4, ECX); else EEINST_RESETHASLIVE1(_Rd_); } } } } void recNOR_consts(int info) { recNOR_constv(info, _Rs_, _Rt_); } void recNOR_constt(int info) { recNOR_constv(info, _Rt_, _Rs_); } void recNOR_(int info) { recLogicalOp(info, 3); } EERECOMPILE_CODE0(NOR, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); //// SLT - test with silent hill, lemans void recSLT_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].SD[0] < g_cpuConstRegs[_Rt_].SD[0]; } static u32 s_sltconst = 0x80000000; static u32 s_sltconst64[2] = {0, 0x80000000}; u32 s_sltone = 1; void recSLTs_consts(int info, int sign) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { if( _Rs_ == _Rt_ ) { PXORRtoR(EEREC_D, EEREC_D); return; } if( g_cpuConstRegs[_Rs_].UL[1] == (g_cpuConstRegs[_Rs_].SL[0]<0?0xffffffff:0) && EEINST_ISSIGNEXT(_Rt_) ) { // just compare the lower values if( sign ) { if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); PCMPGTDMtoR(EEREC_D, (u32)_eeGetConstReg(_Rs_)); PUNPCKLDQRtoR(EEREC_D, EEREC_D); PSRLQItoR(EEREC_D, 63); } else { u32* ptempmem = recAllocStackMem(8,4); ptempmem[0] = g_cpuConstRegs[_Rs_].UL[0]^0x80000000; ptempmem[1] = 0; if( EEREC_D != EEREC_T ) { MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); PXORRtoR(EEREC_D, EEREC_T); } else { PXORMtoR(EEREC_D, (u32)&s_sltconst); } PCMPGTDMtoR(EEREC_D, (u32)ptempmem); PUNPCKLDQRtoR(EEREC_D, EEREC_D); PSRLQItoR(EEREC_D, 63); } return; } else { // need to compare total 64 bit value if( info & PROCESS_EE_MODEWRITET ) { MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; } // fall through mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed } } if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); else XOR32RtoR(EAX, EAX); CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], g_cpuConstRegs[_Rs_].UL[1]); if( sign ) { j8Ptr[0] = JL8( 0 ); j8Ptr[2] = JG8( 0 ); } else { j8Ptr[0] = JB8( 0 ); j8Ptr[2] = JA8( 0 ); } CMP32ItoM((int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], g_cpuConstRegs[_Rs_].UL[0]); j8Ptr[1] = JBE8(0); x86SetJ8(j8Ptr[2]); if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); else MOV32ItoR(EAX, 1); x86SetJ8(j8Ptr[0]); x86SetJ8(j8Ptr[1]); if( !(info & PROCESS_EE_MMX) ) { MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); else EEINST_RESETHASLIVE1(_Rd_); } } // SLT with one operand coming from mem (compares only low 32 bits) void recSLTmemconstt(int regd, int regs, u32 mem, int sign) { // just compare the lower values int t0reg; if( sign ) { if( regd == regs ) { t0reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVQMtoR(t0reg, mem); PCMPGTDRtoR(t0reg, regs); PUNPCKLDQRtoR(t0reg, t0reg); PSRLQItoR(t0reg, 63); // swap regs mmxregs[t0reg] = mmxregs[regd]; mmxregs[regd].inuse = 0; } else { MOVQMtoR(regd, mem); PCMPGTDRtoR(regd, regs); PUNPCKLDQRtoR(regd, regd); PSRLQItoR(regd, 63); } } else { t0reg = _allocMMXreg(-1, MMX_TEMP, 0); if( regd == regs ) { MOVQMtoR(t0reg, mem); PXORMtoR(regs, (u32)&s_sltconst); PCMPGTDRtoR(t0reg, regs); PUNPCKLDQRtoR(t0reg, t0reg); PSRLQItoR(t0reg, 63); // swap regs mmxregs[t0reg] = mmxregs[regd]; mmxregs[regd].inuse = 0; } else { MOVQRtoR(t0reg, regs); MOVQMtoR(regd, mem); PXORMtoR(t0reg, (u32)&s_sltconst); PCMPGTDRtoR(regd, t0reg); PUNPCKLDQRtoR(regd, regd); PSRLQItoR(regd, 63); _freeMMXreg(t0reg); } } } void recSLTs_constt(int info, int sign) { assert( !(info & PROCESS_EE_XMM) ); if( info & PROCESS_EE_MMX ) { if( _Rs_ == _Rt_ ) { PXORRtoR(EEREC_D, EEREC_D); return; } if( EEINST_ISSIGNEXT(_Rs_) && g_cpuConstRegs[_Rt_].UL[1] == (g_cpuConstRegs[_Rt_].SL[0]<0?0xffffffff:0) ) { // just compare the lower values if( sign ) { recSLTmemconstt(EEREC_D, EEREC_S, (u32)_eeGetConstReg(_Rt_), 1); } else { u32* ptempmem = recAllocStackMem(8,4); ptempmem[0] = g_cpuConstRegs[_Rt_].UL[0]^0x80000000; ptempmem[1] = 0; recSLTmemconstt(EEREC_D, EEREC_S, (u32)ptempmem, 0); } return; } else { // need to compare total 64 bit value if( info & PROCESS_EE_MODEWRITES ) { MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; } mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed // fall through } } if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); else MOV32ItoR(EAX, 1); CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], g_cpuConstRegs[_Rt_].UL[1]); if( sign ) { j8Ptr[0] = JL8( 0 ); j8Ptr[2] = JG8( 0 ); } else { j8Ptr[0] = JB8( 0 ); j8Ptr[2] = JA8( 0 ); } CMP32ItoM((int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], g_cpuConstRegs[_Rt_].UL[0]); j8Ptr[1] = JB8(0); x86SetJ8(j8Ptr[2]); if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); else XOR32RtoR(EAX, EAX); x86SetJ8(j8Ptr[0]); x86SetJ8(j8Ptr[1]); if( !(info & PROCESS_EE_MMX) ) { MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); else EEINST_RESETHASLIVE1(_Rd_); } } void recSLTs_(int info, int sign) { if( info & PROCESS_EE_MMX ) MOVDMtoMMX(EEREC_D, (u32)&s_sltone); else MOV32ItoR(EAX, 1); MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); if( sign ) { j8Ptr[0] = JL8( 0 ); j8Ptr[2] = JG8( 0 ); } else { j8Ptr[0] = JB8( 0 ); j8Ptr[2] = JA8( 0 ); } MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); j8Ptr[1] = JB8(0); x86SetJ8(j8Ptr[2]); if( info & PROCESS_EE_MMX ) PXORRtoR(EEREC_D, EEREC_D); else XOR32RtoR(EAX, EAX); x86SetJ8(j8Ptr[0]); x86SetJ8(j8Ptr[1]); if( !(info & PROCESS_EE_MMX) ) { MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); if( EEINST_ISLIVE1(_Rd_) ) MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); else EEINST_RESETHASLIVE1(_Rd_); } } void recSLT_consts(int info) { recSLTs_consts(info, 1); } void recSLT_constt(int info) { recSLTs_constt(info, 1); } void recSLT_(int info) { int t0reg; assert( !(info & PROCESS_EE_XMM) ); if( !(info & PROCESS_EE_MMX) ) { recSLTs_(info, 1); return; } if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { // need to compare total 64 bit value if( info & PROCESS_EE_MODEWRITES ) { MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; } if( info & PROCESS_EE_MODEWRITET ) { MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; } mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed recSLTs_(info, 1); return; } if( EEREC_S == EEREC_T ) { PXORRtoR(EEREC_D, EEREC_D); return; } // just compare the lower values if( EEREC_D == EEREC_S ) { t0reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVQRtoR(t0reg, EEREC_T); PCMPGTDRtoR(t0reg, EEREC_S); PUNPCKLDQRtoR(t0reg, t0reg); PSRLQItoR(t0reg, 63); // swap regs mmxregs[t0reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; } else { if( EEREC_D != EEREC_T ) MOVQRtoR(EEREC_D, EEREC_T); PCMPGTDRtoR(EEREC_D, EEREC_S); PUNPCKLDQRtoR(EEREC_D, EEREC_D); PSRLQItoR(EEREC_D, 63); } } EERECOMPILE_CODE0(SLT, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); // SLTU - test with silent hill, lemans void recSLTU_const() { g_cpuConstRegs[_Rd_].UD[0] = g_cpuConstRegs[_Rs_].UD[0] < g_cpuConstRegs[_Rt_].UD[0]; } void recSLTU_consts(int info) { recSLTs_consts(info, 0); EEINST_SETSIGNEXT(_Rd_); } void recSLTU_constt(int info) { recSLTs_constt(info, 0); EEINST_SETSIGNEXT(_Rd_); } void recSLTU_(int info) { int t1reg; assert( !(info & PROCESS_EE_XMM) ); EEINST_SETSIGNEXT(_Rd_); if( !(info & PROCESS_EE_MMX) ) { recSLTs_(info, 0); return; } if( EEREC_S == EEREC_T ) { PXORRtoR(EEREC_D, EEREC_D); return; } if( !EEINST_ISSIGNEXT(_Rs_) || !EEINST_ISSIGNEXT(_Rt_) ) { // need to compare total 64 bit value if( info & PROCESS_EE_MODEWRITES ) { MOVQRtoM((u32)&cpuRegs.GPR.r[_Rs_], EEREC_S); if( mmxregs[EEREC_S].reg == MMX_GPR+_Rs_ ) mmxregs[EEREC_S].mode &= ~MODE_WRITE; } if( info & PROCESS_EE_MODEWRITET ) { MOVQRtoM((u32)&cpuRegs.GPR.r[_Rt_], EEREC_T); if( mmxregs[EEREC_T].reg == MMX_GPR+_Rt_ ) mmxregs[EEREC_T].mode &= ~MODE_WRITE; } mmxregs[EEREC_D].mode |= MODE_WRITE; // in case EEREC_D was just flushed recSLTs_(info, 0); return; } t1reg = _allocMMXreg(-1, MMX_TEMP, 0); MOVDMtoMMX(t1reg, (u32)&s_sltconst); if( EEREC_D == EEREC_S ) { PXORRtoR(EEREC_S, t1reg); PXORRtoR(t1reg, EEREC_T); PCMPGTDRtoR(t1reg, EEREC_S); PUNPCKLDQRtoR(t1reg, t1reg); PSRLQItoR(t1reg, 63); // swap regs mmxregs[t1reg] = mmxregs[EEREC_D]; mmxregs[EEREC_D].inuse = 0; } else { if( EEREC_D != EEREC_T ) { MOVDMtoMMX(EEREC_D, (u32)&s_sltconst); PXORRtoR(t1reg, EEREC_S); PXORRtoR(EEREC_D, EEREC_T); } else { PXORRtoR(EEREC_D, t1reg); PXORRtoR(t1reg, EEREC_S); } PCMPGTDRtoR(EEREC_D, t1reg); PUNPCKLDQRtoR(EEREC_D, EEREC_D); PSRLQItoR(EEREC_D, 63); _freeMMXreg(t1reg); } } EERECOMPILE_CODE0(SLTU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITED); #else //////////////////////////////////////////////////// void recADD( void ) { if ( ! _Rd_ ) { return; } MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } //////////////////////////////////////////////////// void recADDU( void ) { recADD( ); } //////////////////////////////////////////////////// void recDADD( void ) { if ( ! _Rd_ ) { return; } MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); ADD32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); ADC32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } //////////////////////////////////////////////////// void recDADDU( void ) { recDADD( ); } //////////////////////////////////////////////////// void recSUB( void ) { if ( ! _Rd_ ) return; MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); CDQ( ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } //////////////////////////////////////////////////// void recSUBU( void ) { recSUB( ); } //////////////////////////////////////////////////// void recDSUB( void ) { if ( ! _Rd_ ) return; MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); MOV32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ] ); SUB32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); SBB32MtoR( EDX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ] ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], EDX ); } //////////////////////////////////////////////////// void recDSUBU( void ) { recDSUB( ); } //////////////////////////////////////////////////// void recAND( void ) { if ( ! _Rd_ ) { return; } if ( ( _Rt_ == 0 ) || ( _Rs_ == 0 ) ) { MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0 ); MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); } else { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); PANDRtoR( MM0, MM1); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); } } //////////////////////////////////////////////////// void recOR( void ) { if ( ! _Rd_ ) { return; } if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) { MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], 0x0 ); MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0x0 ); } else if ( _Rs_ == 0 ) { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); } else if ( _Rt_ == 0 ) { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); } else { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); PORRtoR( MM0, MM1 ); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); } } //////////////////////////////////////////////////// void recXOR( void ) { if ( ! _Rd_ ) { return; } if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) { MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0x0); MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0x0); return; } if ( _Rs_ == 0 ) { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); return; } if ( _Rt_ == 0 ) { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); return; } MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); MOVQMtoR( MM1, (int)&cpuRegs.GPR.r[ _Rt_ ] ); PXORRtoR( MM0, MM1); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ], MM0 ); SetMMXstate(); } //////////////////////////////////////////////////// void recNOR( void ) { if ( ! _Rd_ ) { return; } if ( ( _Rs_ == 0 ) && ( _Rt_ == 0 ) ) { MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ],0xffffffff); MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ],0xffffffff); return; } if ( _Rs_ == 0 ) { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rt_ ] ); PCMPEQDRtoR( MM1,MM1); PXORRtoR( MM0,MM1); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); SetMMXstate(); return; } if ( _Rt_ == 0 ) { MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); PCMPEQDRtoR( MM1,MM1); PXORRtoR( MM0,MM1); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); SetMMXstate(); return; } MOVQMtoR( MM0, (int)&cpuRegs.GPR.r[ _Rs_ ] ); PCMPEQDRtoR( MM1,MM1); PORMtoR( MM0,(int)&cpuRegs.GPR.r[ _Rt_ ] ); PXORRtoR( MM0,MM1); MOVQRtoM( (int)&cpuRegs.GPR.r[ _Rd_ ],MM0); SetMMXstate(); } //////////////////////////////////////////////////// // test with silent hill, lemans void recSLT( void ) { if ( ! _Rd_ ) return; MOV32ItoR(EAX, 1); if( _Rs_ == 0 ) { CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); j8Ptr[0] = JG8( 0 ); j8Ptr[2] = JL8( 0 ); CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); j8Ptr[1] = JA8(0); x86SetJ8(j8Ptr[2]); XOR32RtoR(EAX, EAX); } else if( _Rt_ == 0 ) { CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); j8Ptr[0] = JL8( 0 ); j8Ptr[2] = JG8( 0 ); CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); j8Ptr[1] = JB8(0); x86SetJ8(j8Ptr[2]); XOR32RtoR(EAX, EAX); } else { MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); j8Ptr[0] = JL8( 0 ); j8Ptr[2] = JG8( 0 ); MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); j8Ptr[1] = JB8(0); x86SetJ8(j8Ptr[2]); XOR32RtoR(EAX, EAX); } x86SetJ8(j8Ptr[0]); x86SetJ8(j8Ptr[1]); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); } //////////////////////////////////////////////////// void recSLTU( void ) { MOV32ItoR(EAX, 1); if( _Rs_ == 0 ) { CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], 0); j8Ptr[0] = JA8( 0 ); j8Ptr[2] = JB8( 0 ); CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], 0 ); j8Ptr[1] = JA8(0); x86SetJ8(j8Ptr[2]); XOR32RtoR(EAX, EAX); } else if( _Rt_ == 0 ) { CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ], 0); j8Ptr[0] = JB8( 0 ); j8Ptr[2] = JA8( 0 ); CMP32ItoM( (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ], 0); j8Ptr[1] = JB8(0); x86SetJ8(j8Ptr[2]); XOR32RtoR(EAX, EAX); } else { MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 1 ]); CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ]); j8Ptr[0] = JB8( 0 ); j8Ptr[2] = JA8( 0 ); MOV32MtoR(ECX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ]); CMP32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]); j8Ptr[1] = JB8(0); x86SetJ8(j8Ptr[2]); XOR32RtoR(EAX, EAX); } x86SetJ8(j8Ptr[0]); x86SetJ8(j8Ptr[1]); MOV32RtoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 0 ], EAX ); MOV32ItoM( (int)&cpuRegs.GPR.r[ _Rd_ ].UL[ 1 ], 0 ); } #endif