pcsx2/x86/iFPU.c

1365 lines
34 KiB
C

/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2005 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 "Common.h"
#include "InterTables.h"
#include "ix86/ix86.h"
#include "iR5900.h"
#include "iFPU.h"
#define REC_FPUBRANCH(f) \
void f(); \
void rec##f() { \
MOV32ItoM((u32)&cpuRegs.code, cpuRegs.code); \
MOV32ItoM((u32)&cpuRegs.pc, pc); \
iFlushCall(FLUSH_EVERYTHING); \
CALLFunc((u32)f); \
branch = 2; \
}
#define REC_FPUFUNC(f) \
void f(); \
void rec##f() { \
MOV32ItoM((u32)&cpuRegs.code, cpuRegs.code); \
MOV32ItoM((u32)&cpuRegs.pc, pc); \
iFlushCall(FLUSH_EVERYTHING); \
CALLFunc((u32)f); \
}
/*********************************************************
* COP1 opcodes *
* *
*********************************************************/
#define _Ft_ _Rt_
#define _Fs_ _Rd_
#define _Fd_ _Sa_
extern u32 g_minvals[4], g_maxvals[4];
void SetQFromStack(u32 mem)
{
write16(0xe5d9);
FNSTSWtoAX();
write8(0x9e);
j8Ptr[0] = JAE8(0); // jnc
// sign bit is in bit 9 of EAX
FSTP(0); // pop
AND32ItoR(EAX, 0x200);
SHL32ItoR(EAX, 22);
OR32MtoR(EAX, (u32)&g_maxvals[0]);
MOV32RtoM(mem, EAX);
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
// just pop
FSTP32(mem);
x86SetJ8(j8Ptr[1]);
}
////////////////////////////////////////////////////
void recMFC1(void) {
int regt, regs;
if ( ! _Rt_ ) return;
_eeOnWriteReg(_Rt_, 1);
regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ);
if( regs >= 0 ) {
_deleteGPRtoXMMreg(_Rt_, 2);
regt = _allocCheckGPRtoMMX(g_pCurInstInfo, _Rt_, MODE_WRITE);
if( regt >= 0 ) {
SSE2_MOVDQ2Q_XMM_to_MM(regt, regs);
if(EEINST_ISLIVE1(_Rt_)) _signExtendGPRtoMMX(regt, _Rt_, 0);
else EEINST_RESETHASLIVE1(_Rt_);
}
else {
if(EEINST_ISLIVE1(_Rt_)) {
_signExtendXMMtoM((u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs, 0);
}
else {
EEINST_RESETHASLIVE1(_Rt_);
SSE_MOVSS_XMM_to_M32((u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], regs);
}
}
}
else if( (regs = _checkMMXreg(MMX_FPU+_Fs_, MODE_READ)) >= 0 ) {
// convert to mmx reg
mmxregs[regs].reg = MMX_GPR+_Rt_;
mmxregs[regs].mode |= MODE_READ|MODE_WRITE;
_signExtendGPRtoMMX(regs, _Rt_, 0);
}
else {
regt = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ);
if( regt >= 0 ) {
if( xmmregs[regt].mode & MODE_WRITE ) {
SSE_MOVHPS_XMM_to_M64((u32)&cpuRegs.GPR.r[_Rt_].UL[2], regt);
}
xmmregs[regt].inuse = 0;
}
_deleteEEreg(MMX_GPR+_Rt_, 0);
MOV32MtoR( EAX, (u32)&fpuRegs.fpr[ _Fs_ ].UL );
if(EEINST_ISLIVE1(_Rt_)) {
CDQ( );
MOV32RtoM( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX );
MOV32RtoM( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX );
}
else {
EEINST_RESETHASLIVE1(_Rt_);
MOV32RtoM( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX );
}
}
}
////////////////////////////////////////////////////
void recCFC1(void)
{
if ( ! _Rt_ ) return;
_eeOnWriteReg(_Rt_, 1);
MOV32MtoR( EAX, (u32)&fpuRegs.fprc[ _Fs_ ] );
_deleteEEreg(_Rt_, 0);
if(EEINST_ISLIVE1(_Rt_)) {
CDQ( );
MOV32RtoM( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX );
MOV32RtoM( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 1 ], EDX );
}
else {
EEINST_RESETHASLIVE1(_Rt_);
MOV32RtoM( (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ], EAX );
}
}
////////////////////////////////////////////////////
void recMTC1(void)
{
if( GPR_IS_CONST1(_Rt_) ) {
_deleteFPtoXMMreg(_Fs_, 0);
MOV32ItoM((u32)&fpuRegs.fpr[ _Fs_ ].UL, g_cpuConstRegs[_Rt_].UL[0]);
}
else {
int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ);
if( mmreg >= 0 ) {
if( g_pCurInstInfo->regs[_Rt_] & EEINST_LASTUSE ) {
// transfer the reg directly
_deleteGPRtoXMMreg(_Rt_, 2);
_deleteFPtoXMMreg(_Fs_, 2);
_allocFPtoXMMreg(mmreg, _Fs_, MODE_WRITE);
}
else {
int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE);
if( mmreg2 >= 0 ) SSE_MOVSS_XMM_to_XMM(mmreg2, mmreg);
else SSE_MOVSS_XMM_to_M32((u32)&fpuRegs.fpr[ _Fs_ ].UL, mmreg);
}
}
else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) {
if( cpucaps.hasStreamingSIMD2Extensions ) {
int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE);
if( mmreg2 >= 0 ) {
SetMMXstate();
SSE2_MOVQ2DQ_MM_to_XMM(mmreg2, mmreg);
}
else {
SetMMXstate();
MOVDMMXtoM((u32)&fpuRegs.fpr[ _Fs_ ].UL, mmreg);
}
}
else {
_deleteFPtoXMMreg(_Fs_, 0);
SetMMXstate();
MOVDMMXtoM((u32)&fpuRegs.fpr[ _Fs_ ].UL, mmreg);
}
}
else {
int mmreg2 = _allocCheckFPUtoXMM(g_pCurInstInfo, _Fs_, MODE_WRITE);
if( mmreg2 >= 0 ) SSE_MOVSS_M32_to_XMM(mmreg2, (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]);
else {
MOV32MtoR(EAX, (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ]);
MOV32RtoM((u32)&fpuRegs.fpr[ _Fs_ ].UL, EAX);
}
}
}
}
////////////////////////////////////////////////////
void recCTC1( void )
{
if( GPR_IS_CONST1(_Rt_)) {
MOV32ItoM((u32)&fpuRegs.fprc[ _Fs_ ], g_cpuConstRegs[_Rt_].UL[0]);
}
else {
int mmreg = _checkXMMreg(XMMTYPE_GPRREG, _Rt_, MODE_READ);
if( mmreg >= 0 ) {
SSEX_MOVD_XMM_to_M32((u32)&fpuRegs.fprc[ _Fs_ ], mmreg);
}
else if( (mmreg = _checkMMXreg(MMX_GPR+_Rt_, MODE_READ)) >= 0 ) {
MOVDMMXtoM((u32)&fpuRegs.fprc[ _Fs_ ], mmreg);
SetMMXstate();
}
else {
_deleteGPRtoXMMreg(_Rt_, 1);
_deleteMMXreg(MMX_GPR+_Rt_, 1);
MOV32MtoR( EAX, (u32)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] );
MOV32RtoM( (u32)&fpuRegs.fprc[ _Fs_ ], EAX );
}
}
}
////////////////////////////////////////////////////
void recCOP1_BC1()
{
recCP1BC1[_Rt_]();
}
static u32 _mxcsr = 0x7F80;
static u32 _mxcsrs;
static u32 fpucw = 0x007f;
static u32 fpucws = 0;
////////////////////////////////////////////////////
void SaveCW(int type) {
if (iCWstate & type) return;
if (type == 2) {
// SSE_STMXCSR((u32)&_mxcsrs);
// SSE_LDMXCSR((u32)&_mxcsr);
} else {
FNSTCW( (u32)&fpucws );
FLDCW( (u32)&fpucw );
}
iCWstate|= type;
}
////////////////////////////////////////////////////
void LoadCW( void ) {
if (iCWstate == 0) return;
if (iCWstate & 2) {
//SSE_LDMXCSR((u32)&_mxcsrs);
}
if (iCWstate & 1) {
FLDCW( (u32)&fpucws );
}
iCWstate = 0;
}
////////////////////////////////////////////////////
void recCOP1_S( void )
{
if( !EE_FPU_REGCACHING || !cpucaps.hasStreamingSIMD2Extensions) {
_freeMMXreg(6);
_freeMMXreg(7);
}
recCP1S[ _Funct_ ]( );
}
////////////////////////////////////////////////////
void recCOP1_W( void )
{
if( !EE_FPU_REGCACHING ) {
_freeMMXreg(6);
_freeMMXreg(7);
}
recCP1W[ _Funct_ ]( );
}
#ifndef FPU_RECOMPILE
REC_FPUFUNC(ADD_S);
REC_FPUFUNC(SUB_S);
REC_FPUFUNC(MUL_S);
REC_FPUFUNC(DIV_S);
REC_FPUFUNC(SQRT_S);
REC_FPUFUNC(RSQRT_S);
REC_FPUFUNC(ABS_S);
REC_FPUFUNC(MOV_S);
REC_FPUFUNC(NEG_S);
REC_FPUFUNC(ADDA_S);
REC_FPUFUNC(SUBA_S);
REC_FPUFUNC(MULA_S);
REC_FPUFUNC(MADD_S);
REC_FPUFUNC(MSUB_S);
REC_FPUFUNC(MADDA_S);
REC_FPUFUNC(MSUBA_S);
REC_FPUFUNC(CVT_S);
REC_FPUFUNC(CVT_W);
REC_FPUFUNC(MIN_S);
REC_FPUFUNC(MAX_S);
REC_FPUBRANCH(BC1F);
REC_FPUBRANCH(BC1T);
REC_FPUBRANCH(BC1FL);
REC_FPUBRANCH(BC1TL);
REC_FPUFUNC(C_F);
REC_FPUFUNC(C_EQ);
REC_FPUFUNC(C_LE);
REC_FPUFUNC(C_LT);
#else
#ifdef EE_FPU_REGCACHING
// define all FPU ops with XMM
#endif
////////////////////////////////////////////////////
void recC_EQ_xmm(int info)
{
// assumes that inputs are valid
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S: SSE_UCOMISS_M32_to_XMM(EEREC_S, (u32)&fpuRegs.fpr[_Ft_]); break;
case PROCESS_EE_T: SSE_UCOMISS_M32_to_XMM(EEREC_T, (u32)&fpuRegs.fpr[_Fs_]); break;
default: SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); break;
}
//write8(0x9f); // lahf
//TEST16ItoR(EAX, 0x4400);
j8Ptr[0] = JZ8(0);
AND32ItoM( (u32)&fpuRegs.fprc[31], ~0x00800000 );
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
OR32ItoM((u32)&fpuRegs.fprc[31], 0x00800000);
x86SetJ8(j8Ptr[1]);
}
void recC_EQ_(int info)
{
SetFPUstate();
FLD32( (u32)&fpuRegs.fpr[_Fs_].f);
FCOMP32( (u32)&fpuRegs.fpr[_Ft_].f);
FNSTSWtoAX( );
TEST32ItoR( EAX, 0x00004000 );
j8Ptr[ 0 ] = JE8( 0 );
OR32ItoM( (u32)&fpuRegs.fprc[ 31 ], 0x00800000 );
j8Ptr[ 1 ] = JMP8( 0 );
x86SetJ8( j8Ptr[ 0 ] );
AND32ItoM( (u32)&fpuRegs.fprc[ 31 ], ~0x00800000 );
x86SetJ8( j8Ptr[ 1 ] );
}
FPURECOMPILE_CONSTCODE(C_EQ, XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
void recC_F()
{
AND32ItoM( (u32)&fpuRegs.fprc[31], ~0x00800000 );
}
////////////////////////////////////////////////////
void recC_LT_xmm(int info)
{
// assumes that inputs are valid
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S: SSE_UCOMISS_M32_to_XMM(EEREC_S, (u32)&fpuRegs.fpr[_Ft_]); break;
case PROCESS_EE_T: SSE_UCOMISS_M32_to_XMM(EEREC_T, (u32)&fpuRegs.fpr[_Fs_]); break;
default: SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); break;
}
//write8(0x9f); // lahf
//TEST16ItoR(EAX, 0x4400);
if( info & PROCESS_EE_S ) {
j8Ptr[0] = JB8(0);
AND32ItoM( (u32)&fpuRegs.fprc[31], ~0x00800000 );
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
OR32ItoM((u32)&fpuRegs.fprc[31], 0x00800000);
x86SetJ8(j8Ptr[1]);
}
else {
j8Ptr[0] = JBE8(0);
OR32ItoM((u32)&fpuRegs.fprc[31], 0x00800000);
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
AND32ItoM( (u32)&fpuRegs.fprc[31], ~0x00800000 );
x86SetJ8(j8Ptr[1]);
}
}
void recC_LT_(int info)
{
SetFPUstate();
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FCOMP32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FNSTSWtoAX( );
TEST32ItoR( EAX, 0x00000100 );
j8Ptr[ 0 ] = JE8( 0 );
OR32ItoM( (u32)&fpuRegs.fprc[ 31 ], 0x00800000 );
j8Ptr[ 1 ] = JMP8( 0 );
x86SetJ8( j8Ptr[ 0 ] );
AND32ItoM( (u32)&fpuRegs.fprc[ 31 ], ~0x00800000 );
x86SetJ8( j8Ptr[1] );
}
FPURECOMPILE_CONSTCODE(C_LT, XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
void recC_LE_xmm(int info )
{
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S: SSE_UCOMISS_M32_to_XMM(EEREC_S, (u32)&fpuRegs.fpr[_Ft_]); break;
case PROCESS_EE_T: SSE_UCOMISS_M32_to_XMM(EEREC_T, (u32)&fpuRegs.fpr[_Fs_]); break;
default: SSE_UCOMISS_XMM_to_XMM(EEREC_S, EEREC_T); break;
}
//write8(0x9f); // lahf
//TEST16ItoR(EAX, 0x4400);
if( info & PROCESS_EE_S ) {
j8Ptr[0] = JBE8(0);
AND32ItoM( (u32)&fpuRegs.fprc[31], ~0x00800000 );
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
OR32ItoM((u32)&fpuRegs.fprc[31], 0x00800000);
x86SetJ8(j8Ptr[1]);
}
else {
j8Ptr[0] = JB8(0);
OR32ItoM((u32)&fpuRegs.fprc[31], 0x00800000);
j8Ptr[1] = JMP8(0);
x86SetJ8(j8Ptr[0]);
AND32ItoM( (u32)&fpuRegs.fprc[31], ~0x00800000 );
x86SetJ8(j8Ptr[1]);
}
}
void recC_LE_(int info)
{
SetFPUstate();
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FCOMP32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FNSTSWtoAX( );
TEST32ItoR( EAX, 0x00004100 );
j8Ptr[ 0 ] = JE8( 0 );
OR32ItoM( (u32)&fpuRegs.fprc[ 31 ], 0x00800000 );
j8Ptr[ 1 ] = JMP8( 0 );
x86SetJ8( j8Ptr[ 0 ] );
AND32ItoM( (u32)&fpuRegs.fprc[ 31 ], ~0x00800000 );
x86SetJ8( j8Ptr[ 1 ] );
}
FPURECOMPILE_CONSTCODE(C_LE, XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
static void (*recComOpXMM_to_XMM[] )(x86SSERegType, x86SSERegType) = {
SSE_ADDSS_XMM_to_XMM, SSE_MULSS_XMM_to_XMM, SSE_MAXSS_XMM_to_XMM, SSE_MINSS_XMM_to_XMM };
static void (*recComOpM32_to_XMM[] )(x86SSERegType, u32) = {
SSE_ADDSS_M32_to_XMM, SSE_MULSS_M32_to_XMM, SSE_MAXSS_M32_to_XMM, SSE_MINSS_M32_to_XMM };
void recCommutativeOp(int info, int regd, int op) {
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S:
if (regd == EEREC_S) recComOpM32_to_XMM[op](regd, (u32)&fpuRegs.fpr[_Ft_]);
else {
SSE_MOVSS_XMM_to_XMM(regd, EEREC_S);
recComOpM32_to_XMM[op](regd, (u32)&fpuRegs.fpr[_Ft_]);
}
break;
case PROCESS_EE_T:
if (regd == EEREC_T) recComOpM32_to_XMM[op](regd, (u32)&fpuRegs.fpr[_Fs_]);
else {
SSE_MOVSS_XMM_to_XMM(regd, EEREC_T);
recComOpM32_to_XMM[op](regd, (u32)&fpuRegs.fpr[_Fs_]);
}
break;
default:
if (regd == EEREC_S) {
recComOpXMM_to_XMM[op](regd, EEREC_T);
}
else if (regd == EEREC_T) {
recComOpXMM_to_XMM[op](regd, EEREC_S);
}
else {
SSE_MOVSS_XMM_to_XMM(regd, EEREC_S);
recComOpXMM_to_XMM[op](regd, EEREC_T);
}
break;
}
}
static void (*recNonComOpXMM_to_XMM[] )(x86SSERegType, x86SSERegType) = {
SSE_SUBSS_XMM_to_XMM, SSE_DIVSS_XMM_to_XMM };
static void (*recNonComOpM32_to_XMM[] )(x86SSERegType, u32) = {
SSE_SUBSS_M32_to_XMM, SSE_DIVSS_M32_to_XMM };
int recNonCommutativeOp(int info, int regd, int op)
{
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S:
if (regd != EEREC_S) SSE_MOVSS_XMM_to_XMM(regd, EEREC_S);
recNonComOpM32_to_XMM[op](regd, (u32)&fpuRegs.fpr[_Ft_]);
break;
case PROCESS_EE_T:
if (regd == EEREC_T) {
int t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_MOVSS_M32_to_XMM(t0reg, (u32)&fpuRegs.fpr[_Fs_]);
recNonComOpXMM_to_XMM[op](t0reg, EEREC_T);
// swap regs
xmmregs[t0reg] = xmmregs[regd];
xmmregs[regd].inuse = 0;
return t0reg;
}
else {
SSE_MOVSS_M32_to_XMM(regd, (u32)&fpuRegs.fpr[_Fs_]);
recNonComOpXMM_to_XMM[op](regd, EEREC_T);
}
break;
default:
if (regd == EEREC_S) {
recNonComOpXMM_to_XMM[op](regd, EEREC_T);
} else
if (regd == EEREC_T) {
int t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S);
recNonComOpXMM_to_XMM[op](t0reg, regd);
// swap regs
xmmregs[t0reg] = xmmregs[regd];
xmmregs[regd].inuse = 0;
return t0reg;
}
else {
SSE_MOVSS_XMM_to_XMM(regd, EEREC_S);
recNonComOpXMM_to_XMM[op](regd, EEREC_T);
}
break;
}
return regd;
}
void recADD_S_xmm(int info) {
recCommutativeOp(info, EEREC_D, 0);
}
void recADD_S_(int info) {
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FADD32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(ADD_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
void recSUB_S_xmm(int info)
{
recNonCommutativeOp(info, EEREC_D, 0);
}
void recSUB_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FSUB32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(SUB_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
void recMUL_S_xmm(int info)
{
recCommutativeOp(info, EEREC_D, 1);
}
void recMUL_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FMUL32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(MUL_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
void recDIV_S_xmm(int info)
{
int regd = recNonCommutativeOp(info, EEREC_D, 1);
SSE_MAXSS_M32_to_XMM(regd, (u32)&g_minvals[0]);
SSE_MINSS_M32_to_XMM(regd, (u32)&g_maxvals[0]);
// _freeXMMreg(EEREC_D);
// MOV32MtoR(EAX, (int)&fpuRegs.fpr[_Fd_]);
// AND32ItoR(EAX, 0x7f800000);
// CMP32ItoR(EAX, 0x7f800000);
// j8Ptr[0] = JNE8(0);
// MOV32ItoM((int)&fpuRegs.fpr[_Fd_], 0);
// x86SetJ8(j8Ptr[0]);
}
void recDIV_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FDIV32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
SetQFromStack( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(DIV_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
__declspec(align(16)) static u32 s_neg[4] = { 0x80000000, 0, 0, 0 };
__declspec(align(16)) static u32 s_pos[4] = { 0x7fffffff, 0, 0, 0 };
void recSQRT_S_xmm(int info)
{
if( info & PROCESS_EE_T ) {
if( CHECK_FORCEABS ) {
if( EEREC_D == EEREC_T ) SSE_ANDPS_M128_to_XMM(EEREC_D, (u32)&s_pos[0]);
else {
SSE_MOVSS_M32_to_XMM(EEREC_D, (u32)&s_pos[0]);
SSE_ANDPS_XMM_to_XMM(EEREC_D, EEREC_T);
}
SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D);
}
else {
SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_T);
}
}
else {
if( CHECK_FORCEABS ) {
SSE_MOVSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Ft_]);
SSE_ANDPS_M128_to_XMM(EEREC_D, (u32)&s_pos[0]);
SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D);
}
else {
SSE_SQRTSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Ft_]);
}
}
}
void recSQRT_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSQRT( );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(SQRT_S, XMMINFO_WRITED|XMMINFO_READT);
void recABS_S_xmm(int info)
{
if( info & PROCESS_EE_S ) {
if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S);
SSE_ANDPS_M128_to_XMM(EEREC_D, (u32)&s_pos[0]);
}
else {
if( _Fs_ == _Fd_ ) {
AND32ItoM((u32)&fpuRegs.fpr[_Fs_], 0x7fffffff);
SSE_MOVSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
xmmregs[EEREC_D].mode &= ~MODE_WRITE;
}
else {
SSE_MOVSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
SSE_ANDPS_M128_to_XMM(EEREC_D, (u32)&s_pos[0]);
}
}
}
void recABS_S_(int info)
{
MOV32MtoR( EAX, (u32)&fpuRegs.fpr[ _Fs_ ].f );
AND32ItoR( EAX, 0x7fffffff );
MOV32RtoM( (u32)&fpuRegs.fpr[ _Fd_ ].f, EAX );
}
FPURECOMPILE_CONSTCODE(ABS_S, XMMINFO_WRITED|XMMINFO_READS);
void recMOV_S_xmm(int info)
{
if( info & PROCESS_EE_S ) {
if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S);
}
else {
SSE_MOVSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
}
}
void recMOV_S_(int info)
{
MOV32MtoR( EAX, (u32)&fpuRegs.fpr[ _Fs_ ].UL );
MOV32RtoM( (u32)&fpuRegs.fpr[ _Fd_ ].UL, EAX );
}
FPURECOMPILE_CONSTCODE(MOV_S, XMMINFO_WRITED|XMMINFO_READS);
void recNEG_S_xmm(int info) {
if( info & PROCESS_EE_S ) {
if( EEREC_D != EEREC_S ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_S);
}
else {
SSE_MOVSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
}
SSE_XORPS_M128_to_XMM(EEREC_D, (uptr)&s_neg[0]);
}
void recNEG_S_(int info)
{
MOV32MtoR( EAX,(u32)&fpuRegs.fpr[ _Fs_ ].f );
XOR32ItoR( EAX, 0x80000000 );
MOV32RtoM( (u32)&fpuRegs.fpr[ _Fd_ ].f, EAX );
}
FPURECOMPILE_CONSTCODE(NEG_S, XMMINFO_WRITED|XMMINFO_READS);
void recRSQRT_S_xmm(int info)
{
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S:
if( EEREC_D == EEREC_S ) {
int t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_RSQRTSS_M32_to_XMM(t0reg, (u32)&fpuRegs.fpr[_Ft_]);
SSE_MULSS_XMM_to_XMM(EEREC_D, t0reg);
_freeXMMreg(t0reg);
}
else {
SSE_RSQRTSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Ft_]);
SSE_MULSS_XMM_to_XMM(EEREC_D, EEREC_S);
}
break;
case PROCESS_EE_T:
SSE_RSQRTSS_XMM_to_XMM(EEREC_D, EEREC_T);
SSE_MULSS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
break;
default:
if( EEREC_D == EEREC_S ) {
int t0reg;
if( g_pCurInstInfo->regs[_Ft_]&EEINST_LASTUSE ) {
_freeXMMreg(EEREC_T);
t0reg = EEREC_T;
}
else {
t0reg = _allocTempXMMreg(XMMT_FPS, -1);
_freeXMMreg(t0reg);
}
SSE_RSQRTSS_XMM_to_XMM(t0reg, EEREC_T);
SSE_MULSS_XMM_to_XMM(EEREC_D, t0reg);
}
else {
SSE_RSQRTSS_XMM_to_XMM(EEREC_D, EEREC_T);
SSE_MULSS_XMM_to_XMM(EEREC_D, EEREC_S);
}
break;
}
SSE_MAXSS_M32_to_XMM(EEREC_D, (u32)&g_minvals[0]);
SSE_MINSS_M32_to_XMM(EEREC_D, (u32)&g_maxvals[0]);
}
void recRSQRT_S_(int info)
{
static u32 tmp;
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSQRT( );
FSTP32( (u32)&tmp );
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FDIV32( (u32)&tmp );
SetQFromStack( (u32)&fpuRegs.fpr[ _Fd_ ].f );
// FLD32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
// FSQRT( );
// FSTP32( (u32)&tmp );
//
// MOV32MtoR( EAX, (u32)&tmp );
// OR32RtoR( EAX, EAX );
// j8Ptr[ 0 ] = JE8( 0 );
// FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
// FDIV32( (u32)&tmp );
// FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
// x86SetJ8( j8Ptr[ 0 ] );
}
FPURECOMPILE_CONSTCODE(RSQRT_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
void recADDA_S_xmm(int info)
{
recCommutativeOp(info, EEREC_ACC, 0);
}
void recADDA_S_(int info) {
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FADD32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSTP32( (u32)&fpuRegs.ACC.f );
}
FPURECOMPILE_CONSTCODE(ADDA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT);
void recSUBA_S_xmm(int info) {
recNonCommutativeOp(info, EEREC_ACC, 0);
}
void recSUBA_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FSUB32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSTP32( (u32)&fpuRegs.ACC.f );
}
FPURECOMPILE_CONSTCODE(SUBA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT);
void recMULA_S_xmm(int info) {
recCommutativeOp(info, EEREC_ACC, 1);
}
void recMULA_S_(int info) {
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FMUL32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSTP32( (u32)&fpuRegs.ACC.f );
}
FPURECOMPILE_CONSTCODE(MULA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT);
void recMADDtemp(int info, int regd)
{
int vreg;
u32 mreg;
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S:
case PROCESS_EE_T:
vreg = (info&PROCESS_EE_S)?EEREC_S:EEREC_T;
mreg = (info&PROCESS_EE_S)?(u32)&fpuRegs.fpr[_Ft_]:(u32)&fpuRegs.fpr[_Fs_];
if (regd == vreg) {
SSE_MULSS_M32_to_XMM(regd, mreg);
if( info & PROCESS_EE_ACC ) SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC);
else SSE_ADDSS_M32_to_XMM(regd, (u32)&fpuRegs.ACC);
}
else if( (info&PROCESS_EE_ACC) && regd == EEREC_ACC ) {
int t0reg;
if( g_pCurInstInfo->regs[(info&PROCESS_EE_S)?_Fs_:_Ft_] & EEINST_LASTUSE ) {
_freeXMMreg(vreg);
t0reg = vreg;
SSE_MULSS_M32_to_XMM(t0reg, mreg);
}
else {
t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_MOVSS_XMM_to_XMM(t0reg, vreg);
SSE_MULSS_M32_to_XMM(vreg, mreg);
// swap regs for better timing
xmmregs[t0reg] = xmmregs[vreg];
xmmregs[vreg].inuse = 0;
t0reg = vreg;
}
SSE_ADDSS_XMM_to_XMM(regd, t0reg);
}
else {
SSE_MOVSS_M32_to_XMM(regd, mreg);
SSE_MULSS_XMM_to_XMM(regd, vreg);
if( info & PROCESS_EE_ACC ) SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC);
else SSE_ADDSS_M32_to_XMM(regd, (u32)&fpuRegs.ACC);
}
break;
default:
if (regd == EEREC_S) {
SSE_MULSS_XMM_to_XMM(regd, EEREC_T);
if( info & PROCESS_EE_ACC ) {
assert( regd != EEREC_ACC );
SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC);
}
else SSE_ADDSS_M32_to_XMM(regd, (u32)&fpuRegs.ACC);
}
else if (regd == EEREC_T) {
SSE_MULSS_XMM_to_XMM(regd, EEREC_S);
if( info & PROCESS_EE_ACC ) {
assert( regd != EEREC_ACC );
SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC);
}
else SSE_ADDSS_M32_to_XMM(regd, (u32)&fpuRegs.ACC);
}
else if( (info&PROCESS_EE_ACC) && regd == EEREC_ACC ) {
int t0reg ;
if( g_pCurInstInfo->regs[_Fs_] & EEINST_LASTUSE ) {
_freeXMMreg(EEREC_S);
t0reg = EEREC_S;
SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T);
}
else if( g_pCurInstInfo->regs[_Ft_] & EEINST_LASTUSE ) {
_freeXMMreg(EEREC_T);
t0reg = EEREC_T;
SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S);
}
else {
t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S);
SSE_MULSS_XMM_to_XMM(EEREC_S, EEREC_T);
// swap regs for better timing
xmmregs[t0reg] = xmmregs[EEREC_S];
xmmregs[EEREC_S].inuse = 0;
t0reg = EEREC_S;
}
SSE_ADDSS_XMM_to_XMM(regd, t0reg);
}
else {
SSE_MOVSS_XMM_to_XMM(regd, EEREC_S);
SSE_MULSS_XMM_to_XMM(regd, EEREC_T);
if( info & PROCESS_EE_ACC ) SSE_ADDSS_XMM_to_XMM(regd, EEREC_ACC);
else SSE_ADDSS_M32_to_XMM(regd, (u32)&fpuRegs.ACC);
}
break;
}
}
void recMADD_S_xmm(int info)
{
recMADDtemp(info, EEREC_D);
}
void recMADD_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FMUL32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FADD32( (u32)&fpuRegs.ACC.f );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(MADD_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT);
void recMADDA_S_xmm(int info)
{
recMADDtemp(info, EEREC_ACC);
}
void recMADDA_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FMUL32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FADD32( (u32)&fpuRegs.ACC.f );
FSTP32( (u32)&fpuRegs.ACC.f );
}
FPURECOMPILE_CONSTCODE(MADDA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT);
void recMSUBtemp(int info, int regd)
{
int vreg;
u32 mreg;
if( !(info&PROCESS_EE_ACC)) {
int regacc = _allocFPACCtoXMMreg(-1, MODE_WRITE|MODE_READ);
info |= PROCESS_EE_SET_ACC(regacc)|PROCESS_EE_ACC;
}
switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) {
case PROCESS_EE_S:
case PROCESS_EE_T:
vreg = (info&PROCESS_EE_S)?EEREC_S:EEREC_T;
mreg = (info&PROCESS_EE_S)?(u32)&fpuRegs.fpr[_Ft_]:(u32)&fpuRegs.fpr[_Fs_];
if (regd == vreg) {
assert( regd != EEREC_ACC );
_freeXMMreg(EEREC_ACC);
SSE_MULSS_M32_to_XMM(regd, mreg);
SSE_SUBSS_XMM_to_XMM(EEREC_ACC, regd);
xmmregs[EEREC_ACC] = xmmregs[regd];
xmmregs[regd].inuse = 0;
}
else if( regd == EEREC_ACC ) {
int t0reg;
if( g_pCurInstInfo->regs[(info&PROCESS_EE_S)?_Fs_:_Ft_] & EEINST_LASTUSE ) {
_freeXMMreg(vreg);
t0reg = vreg;
SSE_MULSS_M32_to_XMM(t0reg, mreg);
}
else {
t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_MOVSS_XMM_to_XMM(t0reg, vreg);
SSE_MULSS_M32_to_XMM(vreg, mreg);
// swap regs for better timing
xmmregs[t0reg] = xmmregs[vreg];
xmmregs[vreg].inuse = 0;
t0reg = vreg;
}
SSE_SUBSS_XMM_to_XMM(regd, t0reg);
}
else {
if( regd != EEREC_ACC ) {
_freeXMMreg(EEREC_ACC);
xmmregs[EEREC_ACC] = xmmregs[regd];
xmmregs[regd].inuse = 0;
}
SSE_MOVSS_M32_to_XMM(regd, mreg);
SSE_MULSS_XMM_to_XMM(regd, vreg);
SSE_SUBSS_XMM_to_XMM(EEREC_ACC, regd);
}
break;
default:
if (regd == EEREC_S) {
assert( regd != EEREC_ACC );
_freeXMMreg(EEREC_ACC);
SSE_MULSS_XMM_to_XMM(regd, EEREC_T);
SSE_SUBSS_XMM_to_XMM(EEREC_ACC, regd);
xmmregs[EEREC_ACC] = xmmregs[regd];
xmmregs[regd].inuse = 0;
}
else if (regd == EEREC_T) {
assert( regd != EEREC_ACC );
_freeXMMreg(EEREC_ACC);
SSE_MULSS_XMM_to_XMM(regd, EEREC_S);
SSE_SUBSS_XMM_to_XMM(EEREC_ACC, regd);
xmmregs[EEREC_ACC] = xmmregs[regd];
xmmregs[regd].inuse = 0;
}
else if( regd == EEREC_ACC ) {
int t0reg ;
if( g_pCurInstInfo->regs[_Fs_] & EEINST_LASTUSE ) {
_freeXMMreg(EEREC_S);
t0reg = EEREC_S;
SSE_MULSS_XMM_to_XMM(t0reg, EEREC_T);
}
else if( g_pCurInstInfo->regs[_Ft_] & EEINST_LASTUSE ) {
_freeXMMreg(EEREC_T);
t0reg = EEREC_T;
SSE_MULSS_XMM_to_XMM(t0reg, EEREC_S);
}
else {
t0reg = _allocTempXMMreg(XMMT_FPS, -1);
SSE_MOVSS_XMM_to_XMM(t0reg, EEREC_S);
SSE_MULSS_XMM_to_XMM(EEREC_S, EEREC_T);
// swap regs for better timing
xmmregs[t0reg] = xmmregs[EEREC_S];
xmmregs[EEREC_S].inuse = 0;
t0reg = EEREC_S;
}
SSE_SUBSS_XMM_to_XMM(regd, t0reg);
}
else {
if( regd != EEREC_ACC ) {
_freeXMMreg(EEREC_ACC);
xmmregs[EEREC_ACC] = xmmregs[regd];
xmmregs[regd].inuse = 0;
}
SSE_MOVSS_XMM_to_XMM(regd, EEREC_S);
SSE_MULSS_XMM_to_XMM(regd, EEREC_T);
SSE_SUBSS_XMM_to_XMM(EEREC_ACC, regd);
}
break;
}
}
void recMSUB_S_xmm(int info)
{
recMSUBtemp(info, EEREC_D);
}
void recMSUB_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.ACC.f );
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FMUL32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSUBP( );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(MSUB_S, XMMINFO_WRITED|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT);
void recMSUBA_S_xmm(int info)
{
recMSUBtemp(info, EEREC_ACC);
}
void recMSUBA_S_(int info)
{
SetFPUstate();
SaveCW(1);
FLD32( (u32)&fpuRegs.ACC.f );
FLD32( (u32)&fpuRegs.fpr[ _Fs_ ].f );
FMUL32( (u32)&fpuRegs.fpr[ _Ft_ ].f );
FSUBP( );
FSTP32( (u32)&fpuRegs.ACC.f );
}
FPURECOMPILE_CONSTCODE(MSUBA_S, XMMINFO_WRITEACC|XMMINFO_READACC|XMMINFO_READS|XMMINFO_READT);
void recCVT_S_xmm(int info)
{
if( !(info&PROCESS_EE_S) || (EEREC_D != EEREC_S && !(xmmregs[EEREC_S].mode&MODE_WRITE)) ) {
SSE_CVTSI2SS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
}
else {
if( cpucaps.hasStreamingSIMD2Extensions ) {
SSE2_CVTDQ2PS_XMM_to_XMM(EEREC_D, EEREC_S);
}
else {
_deleteGPRtoXMMreg(_Fs_, 1);
SSE_CVTSI2SS_M32_to_XMM(EEREC_D, (u32)&fpuRegs.fpr[_Fs_]);
}
}
}
void recCVT_S_(int info)
{
SetFPUstate();
FILD32( (u32)&fpuRegs.fpr[ _Fs_ ].UL );
FSTP32( (u32)&fpuRegs.fpr[ _Fd_ ].f );
}
FPURECOMPILE_CONSTCODE(CVT_S, XMMINFO_WRITED|XMMINFO_READS);
////////////////////////////////////////////////////
void recCVT_W()
{
int t0reg;
int regs = _checkXMMreg(XMMTYPE_FPREG, _Fs_, MODE_READ);
if( regs >= 0 ) {
t0reg = _allocTempXMMreg(XMMT_FPS, -1);
_freeXMMreg(t0reg);
SSE_XORPS_XMM_to_XMM(t0reg, t0reg);
SSE_CVTTSS2SI_XMM_to_R32(EAX, regs);
}
else SSE_CVTTSS2SI_M32_to_R32(EAX, (u32)&fpuRegs.fpr[ _Fs_ ]);
_deleteFPtoXMMreg(_Fd_, 2);
CMP32ItoR(EAX, 0x80000000);
j8Ptr[0] = JNE8(0);
// need to detect if reg is positive
if( regs >= 0 ) {
SSE_UCOMISS_XMM_to_XMM(regs, t0reg);
j8Ptr[2] = JB8(0);
}
else {
TEST32ItoM((u32)&fpuRegs.fpr[_Fs_], 0x80000000);
j8Ptr[2] = JNZ8(0);
}
MOV32ItoM((u32)&fpuRegs.fpr[_Fd_], 0x7fffffff);
j8Ptr[1] = JMP8(0);
x86SetJ8( j8Ptr[0] );
x86SetJ8( j8Ptr[2] );
MOV32RtoM((u32)&fpuRegs.fpr[_Fd_], EAX);
x86SetJ8( j8Ptr[1] );
// MOV32MtoR(EAX, (u32)&fpuRegs.fpr[ _Fs_ ].f);
// MOV32RtoR(ECX, EAX);
// AND32ItoR(ECX, 0x7F800000);
// CMP32ItoR(ECX, 0x4e800000);
// j8Ptr[0] = JA8(0);
//
// // convert
// SSE_CVTTSS2SI_M32_to_R32(EAX, (u32)&fpuRegs.fpr[ _Fs_ ].f);
// MOV32RtoM((u32)&fpuRegs.fpr[ _Fd_ ].UL, EAX );
//
// j8Ptr[1] = JMP8(0);
//
// x86SetJ8( j8Ptr[0] );
//
// // check negative, eax = (eax&0x80000000)?0x80000000:0x7fffffff
// AND32ItoR(EAX, 0x80000000);
// SBB32RtoR(EAX, EAX);
// NEG32R(EAX);
// ADD32ItoR(EAX, 0x7fffffff);
// MOV32RtoM((u32)&fpuRegs.fpr[ _Fd_ ].UL, EAX);
//
// x86SetJ8( j8Ptr[1] );
}
void recMAX_S_xmm(int info)
{
recCommutativeOp(info, EEREC_D, 2);
}
void recMAX_S_(int info)
{
MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code );
MOV32ItoM( (u32)&cpuRegs.pc, pc );
iFlushCall(FLUSH_NODESTROY);
CALLFunc( (u32)MAX_S );
}
FPURECOMPILE_CONSTCODE(MAX_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
void recMIN_S_xmm(int info)
{
recCommutativeOp(info, EEREC_D, 3);
}
void recMIN_S_(int info) {
MOV32ItoM( (u32)&cpuRegs.code, cpuRegs.code );
MOV32ItoM( (u32)&cpuRegs.pc, pc );
iFlushCall(FLUSH_NODESTROY);
CALLFunc( (u32)MIN_S );
}
FPURECOMPILE_CONSTCODE(MIN_S, XMMINFO_WRITED|XMMINFO_READS|XMMINFO_READT);
////////////////////////////////////////////////////
void recBC1F( void ) {
u32 branchTo = (s32)_Imm_ * 4 + pc;
_eeFlushAllUnused();
MOV32MtoR(EAX, (u32)&fpuRegs.fprc[31]);
TEST32ItoR(EAX, 0x00800000);
j32Ptr[0] = JNZ32(0);
SaveBranchState();
recompileNextInstruction(1);
SetBranchImm(branchTo);
x86SetJ32(j32Ptr[0]);
// recopy the next inst
pc -= 4;
LoadBranchState();
recompileNextInstruction(1);
SetBranchImm(pc);
}
void recBC1T( void ) {
u32 branchTo = (s32)_Imm_ * 4 + pc;
_eeFlushAllUnused();
MOV32MtoR(EAX, (u32)&fpuRegs.fprc[31]);
TEST32ItoR(EAX, 0x00800000);
j32Ptr[0] = JZ32(0);
SaveBranchState();
recompileNextInstruction(1);
SetBranchImm(branchTo);
//j32Ptr[1] = JMP32(0);
x86SetJ32(j32Ptr[0]);
// recopy the next inst
pc -= 4;
LoadBranchState();
recompileNextInstruction(1);
SetBranchImm(pc);
//x86SetJ32(j32Ptr[1]);
}
////////////////////////////////////////////////////
void recBC1FL( void ) {
u32 branchTo = _Imm_ * 4 + pc;
_eeFlushAllUnused();
MOV32MtoR(EAX, (u32)&fpuRegs.fprc[31]);
TEST32ItoR(EAX, 0x00800000);
j32Ptr[0] = JNZ32(0);
SaveBranchState();
recompileNextInstruction(1);
SetBranchImm(branchTo);
x86SetJ32(j32Ptr[0]);
LoadBranchState();
SetBranchImm(pc);
}
////////////////////////////////////////////////////
void recBC1TL( void ) {
u32 branchTo = _Imm_ * 4 + pc;
_eeFlushAllUnused();
MOV32MtoR(EAX, (u32)&fpuRegs.fprc[31]);
TEST32ItoR(EAX, 0x00800000);
j32Ptr[0] = JZ32(0);
SaveBranchState();
recompileNextInstruction(1);
SetBranchImm(branchTo);
x86SetJ32(j32Ptr[0]);
LoadBranchState();
SetBranchImm(pc);
}
#endif