From 522d6ade68d49ff6df2587bbd18667d03c3661e3 Mon Sep 17 00:00:00 2001 From: ramapcsx2 Date: Thu, 22 Jan 2009 11:06:13 +0000 Subject: [PATCH] Changed default EE FPU roundmode to "chop" and made the 2 instructions that needed "nearest" rounding change the mode at runtime. Note that the default mode is now the only one that is correct. Games will break with any other mode. The choice is still there though for any games that don't work with "chop". Please report these so I can fix them as well. git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@622 a6443dda-0b58-4228-96e9-037be469359c --- pcsx2/Misc.h | 4 ++-- pcsx2/x86/iFPU.cpp | 42 ++++++++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/pcsx2/Misc.h b/pcsx2/Misc.h index e5871b1355..69aa6602b3 100644 --- a/pcsx2/Misc.h +++ b/pcsx2/Misc.h @@ -123,8 +123,8 @@ extern SessionOverrideFlags g_Session; #define DEFAULT_eeOptions 0x01 #define DEFAULT_vuOptions 0x01 //------------ DEFAULT sseMXCSR VALUES!!! --------------- -#define DEFAULT_sseMXCSR 0x9fc0 //disable all exception, round to 0, flush to 0 -#define DEFAULT_sseVUMXCSR 0x7f80 //disable all exception +#define DEFAULT_sseMXCSR 0xffc0 //FPU rounding, DaZ, FtZ, "chop" +#define DEFAULT_sseVUMXCSR 0x7f80 //VU rounding, "chop" #define CHECK_FRAMELIMIT (Config.Options&PCSX2_FRAMELIMIT_MASK) diff --git a/pcsx2/x86/iFPU.cpp b/pcsx2/x86/iFPU.cpp index 4caa0cd069..9d63b72710 100644 --- a/pcsx2/x86/iFPU.cpp +++ b/pcsx2/x86/iFPU.cpp @@ -459,22 +459,13 @@ FPURECOMPILE_CONSTCODE(ABS_S, XMMINFO_WRITED|XMMINFO_READS); //------------------------------------------------------------------ void FPU_ADD_SUB(int regd, int regt, int issub) { - static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; int tempecx = _allocX86reg(ECX, X86TYPE_TEMP, 0, 0); //receives regd int temp2 = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); //receives regt - int xmmtemp = _allocTempXMMreg(XMMT_FPS, -1); //temporary for anding with regd/regt - int roundmodeFlag = 0; + int xmmtemp = _allocTempXMMreg(XMMT_FPS, -1); //temporary for anding with regd/regt if (tempecx != ECX) { Console::Error("FPU: ADD/SUB Allocation Error!"); tempecx = ECX;} if (temp2 == -1) { Console::Error("FPU: ADD/SUB Allocation Error!"); temp2 = EAX;} if (xmmtemp == -1) { Console::Error("FPU: ADD/SUB Allocation Error!"); xmmtemp = XMM0;} - - if ((g_sseMXCSR & 0x00006000) != 0x00006000) { // Set roundmode to chop if it isn't already - roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF) | 0x00006000; // Set new roundmode - roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode - SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change - roundmodeFlag = 1; - } SSE2_MOVD_XMM_to_R(tempecx, regd); SSE2_MOVD_XMM_to_R(temp2, regt); @@ -551,10 +542,6 @@ void FPU_ADD_SUB(int regd, int regt, int issub) x86SetJ8(j8Ptr[6]); x86SetJ8(j8Ptr[7]); - if (roundmodeFlag == 1) { // Set roundmode back if it was changed - SSE_LDMXCSR ((uptr)&roundmode_temp[1]); - } - _freeXMMreg(xmmtemp); _freeX86reg(temp2); _freeX86reg(tempecx); @@ -1079,8 +1066,18 @@ void recDIVhelper2(int regd, int regt) // Doesn't sets flags void recDIV_S_xmm(int info) { + static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int roundmodeFlag = 0; int t0reg = _allocTempXMMreg(XMMT_FPS, -1); //if (t0reg == -1) {Console::Error("FPU: DIV Allocation Error!");} + //SysPrintf("DIV\n"); + if ((g_sseMXCSR & 0x00006000) != 0x00000000) { // Set roundmode to nearest if it isn't already + //SysPrintf("div to nearest\n"); + roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF); // Set new roundmode + roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode + SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change + roundmodeFlag = 1; + } switch(info & (PROCESS_EE_S|PROCESS_EE_T) ) { case PROCESS_EE_S: @@ -1126,6 +1123,9 @@ void recDIV_S_xmm(int info) else recDIVhelper2(EEREC_D, t0reg); break; } + if (roundmodeFlag == 1) { // Set roundmode back if it was changed + SSE_LDMXCSR ((uptr)&roundmode_temp[1]); + } _freeXMMreg(t0reg); } @@ -1623,9 +1623,19 @@ FPURECOMPILE_CONSTCODE(SUBA_S, XMMINFO_WRITEACC|XMMINFO_READS|XMMINFO_READT); void recSQRT_S_xmm(int info) { u8* pjmp; + static u32 PCSX2_ALIGNED16(roundmode_temp[4]) = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int roundmodeFlag = 0; int tempReg = _allocX86reg(-1, X86TYPE_TEMP, 0, 0); if (tempReg == -1) {Console::Error("FPU: SQRT Allocation Error!"); tempReg = EAX;} //SysPrintf("FPU: SQRT\n"); + + if ((g_sseMXCSR & 0x00006000) != 0x00000000) { // Set roundmode to nearest if it isn't already + //SysPrintf("sqrt to nearest\n"); + roundmode_temp[0] = (g_sseMXCSR & 0xFFFF9FFF); // Set new roundmode + roundmode_temp[1] = g_sseMXCSR; // Backup old Roundmode + SSE_LDMXCSR ((uptr)&roundmode_temp[0]); // Recompile Roundmode Change + roundmodeFlag = 1; + } if( info & PROCESS_EE_T ) SSE_MOVSS_XMM_to_XMM(EEREC_D, EEREC_T); else SSE_MOVSS_M32_to_XMM(EEREC_D, (uptr)&fpuRegs.fpr[_Ft_]); @@ -1646,6 +1656,10 @@ void recSQRT_S_xmm(int info) if (CHECK_FPU_OVERFLOW) SSE_MINSS_M32_to_XMM(EEREC_D, (uptr)&g_maxvals[0]);// Only need to do positive clamp, since EEREC_D is positive SSE_SQRTSS_XMM_to_XMM(EEREC_D, EEREC_D); if (CHECK_FPU_EXTRA_OVERFLOW) ClampValues(EEREC_D); // Shouldn't need to clamp again since SQRT of a number will always be smaller than the original number, doing it just incase :/ + + if (roundmodeFlag == 1) { // Set roundmode back if it was changed + SSE_LDMXCSR ((uptr)&roundmode_temp[1]); + } _freeX86reg(tempReg); }