mirror of https://github.com/PCSX2/pcsx2.git
1365 lines
34 KiB
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
|