- Various fixes to MMI and more changes to opcodes to mimic ps2 behavior, thanks to Nneeve.

- Brought back a gamefix for Persona games. They still have missing geometry without it (VU clip flag problem)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@835 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
ramapcsx2 2009-03-22 19:40:43 +00:00
parent 95c7ce1dbc
commit 157e696182
9 changed files with 298 additions and 124 deletions

View File

@ -66,6 +66,7 @@ extern SessionOverrideFlags g_Session;
//------------ SPECIAL GAME FIXES!!! --------------- //------------ SPECIAL GAME FIXES!!! ---------------
#define CHECK_VUADDSUBHACK (Config.GameFixes & 0x1) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate. #define CHECK_VUADDSUBHACK (Config.GameFixes & 0x1) // Special Fix for Tri-ace games, they use an encryption algorithm that requires VU addi opcode to be bit-accurate.
#define CHECK_FPUCOMPAREHACK (Config.GameFixes & 0x4) // Special Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu. #define CHECK_FPUCOMPAREHACK (Config.GameFixes & 0x4) // Special Fix for Digimon Rumble Arena 2, fixes spinning/hanging on intro-menu.
#define CHECK_VUCLIPFLAGHACK (Config.GameFixes & 0x2) // Special Fix for Persona games, maybe others. It's to do with the VU clip flag (again).
#define CHECK_FPUMULHACK (Config.GameFixes & 0x8) // Special Fix for Tales of Destiny hangs. #define CHECK_FPUMULHACK (Config.GameFixes & 0x8) // Special Fix for Tales of Destiny hangs.
//------------ Advanced Options!!! --------------- //------------ Advanced Options!!! ---------------
#define CHECK_VU_OVERFLOW (Config.vuOptions & 0x1) #define CHECK_VU_OVERFLOW (Config.vuOptions & 0x1)

View File

@ -113,11 +113,22 @@ namespace OpcodeImpl {
if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1]; if (_Rd_) cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.LO.UD[1];
} }
void DIV1() { void DIV1() {
if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) { if (cpuRegs.GPR.r[_Rs_].UL[0] == 0x80000000 && cpuRegs.GPR.r[_Rt_].UL[0] == 0xffffffff)
{
cpuRegs.LO.SD[1] = (s32)0x80000000;
cpuRegs.HI.SD[1] = (s32)0x0;
}
else if (cpuRegs.GPR.r[_Rt_].SL[0] != 0)
{
cpuRegs.LO.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; cpuRegs.LO.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0];
cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0];
} }
else
{
cpuRegs.LO.SD[1] = (cpuRegs.GPR.r[_Rs_].SL[0] < 0) ? 1 : -1;
cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0];
}
} }
void DIVU1() void DIVU1()
@ -129,6 +140,11 @@ namespace OpcodeImpl {
cpuRegs.LO.SD[1] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]); cpuRegs.LO.SD[1] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]);
cpuRegs.HI.SD[1] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]); cpuRegs.HI.SD[1] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]);
} }
else
{
cpuRegs.LO.SD[1] = -1;
cpuRegs.HI.SD[1] = cpuRegs.GPR.r[_Rs_].SL[0];
}
} }
namespace MMI { namespace MMI {
@ -187,19 +203,19 @@ void PMFHL() {
case 0x02: // SLW case 0x02: // SLW
{ {
u64 TempU64 = ((u64)cpuRegs.HI.UL[0] << 32) | (u64)cpuRegs.LO.UL[0]; s64 TempS64 = ((u64)cpuRegs.HI.UL[0] << 32) | (u64)cpuRegs.LO.UL[0];
if (TempU64 >= 0x000000007fffffffLL) { if (TempS64 >= 0x000000007fffffffLL) {
cpuRegs.GPR.r[_Rd_].UD[0] = 0x000000007fffffffLL; cpuRegs.GPR.r[_Rd_].UD[0] = 0x000000007fffffffLL;
} else if (TempU64 <= 0xffffffff80000000LL) { } else if (TempS64 <= 0xffffffff80000000LL) {
cpuRegs.GPR.r[_Rd_].UD[0] = 0xffffffff80000000LL; cpuRegs.GPR.r[_Rd_].UD[0] = 0xffffffff80000000LL;
} else { } else {
cpuRegs.GPR.r[_Rd_].UD[0] = (s64)cpuRegs.LO.SL[0]; cpuRegs.GPR.r[_Rd_].UD[0] = (s64)cpuRegs.LO.SL[0];
} }
TempU64 = ((u64)cpuRegs.HI.UL[2] << 32) | (u64)cpuRegs.LO.UL[2]; TempS64 = ((u64)cpuRegs.HI.UL[2] << 32) | (u64)cpuRegs.LO.UL[2];
if (TempU64 >= 0x000000007fffffffLL) { if (TempS64 >= 0x000000007fffffffLL) {
cpuRegs.GPR.r[_Rd_].UD[1] = 0x000000007fffffffLL; cpuRegs.GPR.r[_Rd_].UD[1] = 0x000000007fffffffLL;
} else if (TempU64 <= 0xffffffff80000000LL) { } else if (TempS64 <= 0xffffffff80000000LL) {
cpuRegs.GPR.r[_Rd_].UD[1] = 0xffffffff80000000LL; cpuRegs.GPR.r[_Rd_].UD[1] = 0xffffffff80000000LL;
} else { } else {
cpuRegs.GPR.r[_Rd_].UD[1] = (s64)cpuRegs.LO.SL[2]; cpuRegs.GPR.r[_Rd_].UD[1] = (s64)cpuRegs.LO.SL[2];
@ -603,7 +619,7 @@ __forceinline void _PADDSB(int n)
if (sTemp16 > 0x7F) if (sTemp16 > 0x7F)
cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F;
else if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) else if (sTemp16 < (s16)0xff80)
cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; cpuRegs.GPR.r[_Rd_].UC[n] = 0x80;
else else
cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16;
@ -624,7 +640,7 @@ static __forceinline void _PSUBSB( u8 n )
if (sTemp16 >= 0x7F) if (sTemp16 >= 0x7F)
cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F; cpuRegs.GPR.r[_Rd_].UC[n] = 0x7F;
else if ((sTemp16 < 0x180) && (sTemp16 >= 0x100)) else if (sTemp16 <= (s16)0xff80)
cpuRegs.GPR.r[_Rd_].UC[n] = 0x80; cpuRegs.GPR.r[_Rd_].UC[n] = 0x80;
else else
cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16; cpuRegs.GPR.r[_Rd_].UC[n] = (s8)sTemp16;
@ -727,7 +743,12 @@ void PPAC5() {
__forceinline void _PABSW(int n) __forceinline void _PABSW(int n)
{ {
cpuRegs.GPR.r[_Rd_].UL[n] = abs(cpuRegs.GPR.r[_Rt_].SL[n]); if (cpuRegs.GPR.r[_Rt_].UL[n] == 0x80000000)
cpuRegs.GPR.r[_Rd_].UL[n] = 0x7fffffff; //clamp
else if (cpuRegs.GPR.r[_Rt_].SL[n] < 0)
cpuRegs.GPR.r[_Rd_].UL[n] = - cpuRegs.GPR.r[_Rt_].SL[n];
else
cpuRegs.GPR.r[_Rd_].UL[n] = cpuRegs.GPR.r[_Rt_].SL[n];
} }
void PABSW() { void PABSW() {
@ -773,7 +794,12 @@ void PADSBH() {
__forceinline void _PABSH(int n) __forceinline void _PABSH(int n)
{ {
cpuRegs.GPR.r[_Rd_].US[n] = abs(cpuRegs.GPR.r[_Rt_].SS[n]); if (cpuRegs.GPR.r[_Rt_].US[n] == 0x8000)
cpuRegs.GPR.r[_Rd_].US[n] = 0x7fff; //clamp
else if (cpuRegs.GPR.r[_Rt_].SS[n] < 0)
cpuRegs.GPR.r[_Rd_].US[n] = - cpuRegs.GPR.r[_Rt_].SS[n];
else
cpuRegs.GPR.r[_Rd_].US[n] = cpuRegs.GPR.r[_Rt_].SS[n];
} }
void PABSH() { void PABSH() {
@ -994,38 +1020,39 @@ void QFSRV() { // JayteeMaster: changed a bit to avoid screw up
GPR_reg Rd; GPR_reg Rd;
if (!_Rd_) return; if (!_Rd_) return;
if (cpuRegs.sa == 0) { u32 sa_amt = cpuRegs.sa << 3;
if (sa_amt == 0) {
cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0]; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0];
cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1]; cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1];
//saZero++; //saZero++;
//if( saZero >= 388800 ) //if( saZero >= 388800 )
//Console::WriteLn( "SA Is Zero, Bitch: %d zeros and counting.", params saZero ); //Console::WriteLn( "SA Is Zero, Bitch: %d zeros and counting.", params saZero );
} else { } else {
//Console::WriteLn( "SA Properly Valued at: %d (after %d zeros)", params cpuRegs.sa, saZero ); //Console::WriteLn( "SA Properly Valued at: %d (after %d zeros)", params sa_amt, saZero );
//saZero = 0; //saZero = 0;
if (cpuRegs.sa < 64) { if (sa_amt < 64) {
/* /*
cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> sa_amt;
cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> sa_amt;
cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - sa_amt);
cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - sa_amt);
*/ */
Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> cpuRegs.sa; Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[0] >> sa_amt;
Rd.UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> cpuRegs.sa; Rd.UD[1] = cpuRegs.GPR.r[_Rt_].UD[1] >> sa_amt;
Rd.UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - cpuRegs.sa); Rd.UD[0]|= cpuRegs.GPR.r[_Rt_].UD[1] << (64 - sa_amt);
Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - cpuRegs.sa); Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[0] << (64 - sa_amt);
cpuRegs.GPR.r[_Rd_] = Rd; cpuRegs.GPR.r[_Rd_] = Rd;
} else { } else {
/* /*
cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); cpuRegs.GPR.r[_Rd_].UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (sa_amt - 64);
cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); cpuRegs.GPR.r[_Rd_].UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (sa_amt - 64);
cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); cpuRegs.GPR.r[_Rd_].UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - sa_amt);
cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); cpuRegs.GPR.r[_Rd_].UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - sa_amt);
*/ */
Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (cpuRegs.sa - 64); Rd.UD[0] = cpuRegs.GPR.r[_Rt_].UD[1] >> (sa_amt - 64);
Rd.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (cpuRegs.sa - 64); Rd.UD[1] = cpuRegs.GPR.r[_Rs_].UD[0] >> (sa_amt - 64);
Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - cpuRegs.sa); Rd.UD[0]|= cpuRegs.GPR.r[_Rs_].UD[0] << (128 - sa_amt);
Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - cpuRegs.sa); Rd.UD[1]|= cpuRegs.GPR.r[_Rs_].UD[1] << (128 - sa_amt);
cpuRegs.GPR.r[_Rd_] = Rd; cpuRegs.GPR.r[_Rd_] = Rd;
} }
} }
@ -1132,11 +1159,21 @@ void PMULTW() {
__forceinline void _PDIVW(int dd, int ss) __forceinline void _PDIVW(int dd, int ss)
{ {
if (cpuRegs.GPR.r[_Rt_].UL[ss] != 0) if (cpuRegs.GPR.r[_Rs_].UL[ss] == 0x80000000 && cpuRegs.GPR.r[_Rt_].UL[ss] == 0xffffffff)
{
cpuRegs.LO.SD[dd] = (s32)0x80000000;
cpuRegs.HI.SD[dd] = (s32)0;
}
else if (cpuRegs.GPR.r[_Rt_].SL[ss] != 0)
{ {
cpuRegs.LO.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] / cpuRegs.GPR.r[_Rt_].SL[ss]; cpuRegs.LO.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] / cpuRegs.GPR.r[_Rt_].SL[ss];
cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] % cpuRegs.GPR.r[_Rt_].SL[ss]; cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss] % cpuRegs.GPR.r[_Rt_].SL[ss];
} }
else
{
cpuRegs.LO.SD[dd] = (cpuRegs.GPR.r[_Rs_].SL[ss] < 0) ? 1 : -1;
cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss];
}
} }
void PDIVW() { void PDIVW() {
@ -1196,18 +1233,20 @@ void PMADDH() { // JayteeMaster: changed a bit to avoid screw up
// JayteeMaster: changed a bit to avoid screw up // JayteeMaster: changed a bit to avoid screw up
__forceinline void _PHMADH_LO(int dd, int n) __forceinline void _PHMADH_LO(int dd, int n)
{ {
s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ s32 firsttemp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1];
(s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; s32 temp = firsttemp + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n];
cpuRegs.LO.UL[dd] = temp; cpuRegs.LO.UL[dd] = temp;
cpuRegs.LO.UL[dd+1] = firsttemp;
} }
__forceinline void _PHMADH_HI(int dd, int n) __forceinline void _PHMADH_HI(int dd, int n)
{ {
s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] + \ s32 firsttemp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1];
(s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; s32 temp = firsttemp + (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n];
cpuRegs.HI.UL[dd] = temp; cpuRegs.HI.UL[dd] = temp;
cpuRegs.HI.UL[dd+1] = firsttemp;
} }
void PHMADH() { // JayteeMaster: changed a bit to avoid screw up. Also used 0,2,4,6 instead of 0,1,2,3 void PHMADH() { // JayteeMaster: changed a bit to avoid screw up. Also used 0,2,4,6 instead of 0,1,2,3
@ -1279,17 +1318,19 @@ void PMSUBH() { // JayteeMaster: changed a bit to avoid screw up
// JayteeMaster: changed a bit to avoid screw up // JayteeMaster: changed a bit to avoid screw up
__forceinline void _PHMSBH_LO(int dd, int n, int rdd) __forceinline void _PHMSBH_LO(int dd, int n, int rdd)
{ {
s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ s32 firsttemp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1];
(s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; s32 temp = firsttemp - (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n];
cpuRegs.LO.UL[dd] = temp; cpuRegs.LO.UL[dd] = temp;
cpuRegs.LO.UL[dd+1] = ~firsttemp;
} }
__forceinline void _PHMSBH_HI(int dd, int n, int rdd) __forceinline void _PHMSBH_HI(int dd, int n, int rdd)
{ {
s32 temp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1] - \ s32 firsttemp = (s32)cpuRegs.GPR.r[_Rs_].SS[n+1] * (s32)cpuRegs.GPR.r[_Rt_].SS[n+1];
(s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n]; s32 temp = firsttemp - (s32)cpuRegs.GPR.r[_Rs_].SS[n] * (s32)cpuRegs.GPR.r[_Rt_].SS[n];
cpuRegs.HI.UL[dd] = temp; cpuRegs.HI.UL[dd] = temp;
cpuRegs.HI.UL[dd+1] = ~firsttemp;
} }
void PHMSBH() { // JayteeMaster: changed a bit to avoid screw up void PHMSBH() { // JayteeMaster: changed a bit to avoid screw up
@ -1378,13 +1419,24 @@ void PMULTH() { // JayteeMaster: changed a bit to avoid screw up
__forceinline void _PDIVBW(int n) __forceinline void _PDIVBW(int n)
{ {
cpuRegs.LO.UL[n] = (s32)(cpuRegs.GPR.r[_Rs_].SL[n] / cpuRegs.GPR.r[_Rt_].SS[0]); if (cpuRegs.GPR.r[_Rs_].UL[n] == 0x80000000 && cpuRegs.GPR.r[_Rt_].US[0] == 0xffff)
cpuRegs.HI.UL[n] = (s16)(cpuRegs.GPR.r[_Rs_].SL[n] % cpuRegs.GPR.r[_Rt_].SS[0]); {
cpuRegs.LO.SL[n] = (s32)0x80000000;
cpuRegs.HI.SL[n] = (s32)0x0;
}
else if (cpuRegs.GPR.r[_Rt_].US[0] != 0)
{
cpuRegs.LO.SL[n] = cpuRegs.GPR.r[_Rs_].SL[n] / cpuRegs.GPR.r[_Rt_].SS[0];
cpuRegs.HI.SL[n] = cpuRegs.GPR.r[_Rs_].SL[n] % cpuRegs.GPR.r[_Rt_].SS[0];
}
else
{
cpuRegs.LO.SL[n] = (cpuRegs.GPR.r[_Rs_].SL[n] < 0) ? 1 : -1;
cpuRegs.HI.SL[n] = cpuRegs.GPR.r[_Rs_].SL[n];
}
} }
void PDIVBW() { void PDIVBW() {
if (cpuRegs.GPR.r[_Rt_].US[0] == 0) return;
_PDIVBW(0); _PDIVBW(1); _PDIVBW(2); _PDIVBW(3); _PDIVBW(0); _PDIVBW(1); _PDIVBW(2); _PDIVBW(3);
} }
@ -1489,6 +1541,11 @@ __forceinline void _PDIVUW(int dd, int ss)
cpuRegs.LO.SD[dd] = (s32)(cpuRegs.GPR.r[_Rs_].UL[ss] / cpuRegs.GPR.r[_Rt_].UL[ss]); cpuRegs.LO.SD[dd] = (s32)(cpuRegs.GPR.r[_Rs_].UL[ss] / cpuRegs.GPR.r[_Rt_].UL[ss]);
cpuRegs.HI.SD[dd] = (s32)(cpuRegs.GPR.r[_Rs_].UL[ss] % cpuRegs.GPR.r[_Rt_].UL[ss]); cpuRegs.HI.SD[dd] = (s32)(cpuRegs.GPR.r[_Rs_].UL[ss] % cpuRegs.GPR.r[_Rt_].UL[ss]);
} }
else
{
cpuRegs.LO.SD[dd] = -1;
cpuRegs.HI.SD[dd] = cpuRegs.GPR.r[_Rs_].SL[ss];
}
} }
void PDIVUW() { void PDIVUW() {

View File

@ -247,14 +247,29 @@ void SLTU() { if (!_Rd_) return; cpuRegs.GPR.r[_Rd_].UD[0] = (cpuRegs.GPR.r[_Rs
* Format: OP rs, rt * * Format: OP rs, rt *
*********************************************************/ *********************************************************/
// Signed division "overflows" on (0x80000000 / -1), here (LO = 0x80000000, HI = 0) is returned by MIPS
// in division by zero on MIPS, it appears that:
// LO gets 1 if rs is negative (and the division is signed) and -1 otherwise.
// HI gets the value of rs.
// Result is stored in HI/LO [no arithmetic exceptions] // Result is stored in HI/LO [no arithmetic exceptions]
void DIV() void DIV()
{ {
if (cpuRegs.GPR.r[_Rt_].SL[0] != 0) if (cpuRegs.GPR.r[_Rs_].UL[0] == 0x80000000 && cpuRegs.GPR.r[_Rt_].UL[0] == 0xffffffff)
{
cpuRegs.LO.SD[0] = (s32)0x80000000;
cpuRegs.HI.SD[0] = (s32)0x0;
}
else if (cpuRegs.GPR.r[_Rt_].SL[0] != 0)
{ {
cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0]; cpuRegs.LO.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] / cpuRegs.GPR.r[_Rt_].SL[0];
cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0]; cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0] % cpuRegs.GPR.r[_Rt_].SL[0];
} }
else
{
cpuRegs.LO.SD[0] = (cpuRegs.GPR.r[_Rs_].SL[0] < 0) ? 1 : -1;
cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0];
}
} }
// Result is stored in HI/LO [no arithmetic exceptions] // Result is stored in HI/LO [no arithmetic exceptions]
@ -267,6 +282,11 @@ void DIVU()
cpuRegs.LO.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]); cpuRegs.LO.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] / cpuRegs.GPR.r[_Rt_].UL[0]);
cpuRegs.HI.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]); cpuRegs.HI.SD[0] = (s32)(cpuRegs.GPR.r[_Rs_].UL[0] % cpuRegs.GPR.r[_Rt_].UL[0]);
} }
else
{
cpuRegs.LO.SD[0] = -1;
cpuRegs.HI.SD[0] = cpuRegs.GPR.r[_Rs_].SL[0];
}
} }
// Result is written to both HI/LO and to the _Rd_ (Lo only) // Result is written to both HI/LO and to the _Rd_ (Lo only)
@ -858,7 +878,7 @@ void MFSA( void ) {
} }
void MTSA( void ) { void MTSA( void ) {
cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0]; cpuRegs.sa = (s32)cpuRegs.GPR.r[_Rs_].SD[0] & 0xf;
} }
// SNY supports three basic modes, two which synchronize memory accesses (related // SNY supports three basic modes, two which synchronize memory accesses (related
@ -907,11 +927,11 @@ void TLTIU() { if (cpuRegs.GPR.r[_Rs_].UD[0] < (u64)_Imm_) throw R5900Exception
*********************************************************/ *********************************************************/
void MTSAB() { void MTSAB() {
cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3; cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF));
} }
void MTSAH() { void MTSAH() {
cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4; cpuRegs.sa = ((cpuRegs.GPR.r[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1;
} }
} } } // end namespace R5900::Interpreter::OpcodeImpl } } } // end namespace R5900::Interpreter::OpcodeImpl

View File

@ -525,6 +525,7 @@ BOOL APIENTRY GameFixes(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
case WM_INITDIALOG: case WM_INITDIALOG:
if(Config.GameFixes & 0x1) CheckDlgButton(hDlg, IDC_GAMEFIX2, TRUE);//Tri-Ace fix if(Config.GameFixes & 0x1) CheckDlgButton(hDlg, IDC_GAMEFIX2, TRUE);//Tri-Ace fix
if(Config.GameFixes & 0x4) CheckDlgButton(hDlg, IDC_GAMEFIX3, TRUE);//Digimon FPU compare fix if(Config.GameFixes & 0x4) CheckDlgButton(hDlg, IDC_GAMEFIX3, TRUE);//Digimon FPU compare fix
if(Config.GameFixes & 0x2) CheckDlgButton(hDlg, IDC_GAMEFIX4, TRUE);//Persona3/4 fix
if(Config.GameFixes & 0x8) CheckDlgButton(hDlg, IDC_GAMEFIX5, TRUE);//Tales of Destiny fix if(Config.GameFixes & 0x8) CheckDlgButton(hDlg, IDC_GAMEFIX5, TRUE);//Tales of Destiny fix
return TRUE; return TRUE;
@ -534,6 +535,7 @@ BOOL APIENTRY GameFixes(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
uint newfixes = 0; uint newfixes = 0;
newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX2) ? 0x1 : 0; newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX2) ? 0x1 : 0;
newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX3) ? 0x4 : 0; newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX3) ? 0x4 : 0;
newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX4) ? 0x2 : 0;
newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX5) ? 0x8 : 0; newfixes |= IsDlgButtonChecked(hDlg, IDC_GAMEFIX5) ? 0x8 : 0;
EndDialog(hDlg, TRUE); EndDialog(hDlg, TRUE);

View File

@ -74,21 +74,23 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
// Dialog // Dialog
// //
IDD_GAMEFIXES DIALOGEX 0, 0, 279, 118 IDD_GAMEFIXES DIALOGEX 0, 0, 279, 123
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Game Special Fixes" CAPTION "Game Special Fixes"
FONT 8, "MS Shell Dlg", 400, 0, 0x1 FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN BEGIN
DEFPUSHBUTTON "OK",IDOK,87,89,50,14 DEFPUSHBUTTON "OK",IDOK,87,96,50,14
PUSHBUTTON "Cancel",IDCANCEL,142,89,50,14 PUSHBUTTON "Cancel",IDCANCEL,142,96,50,14
CTEXT "Some games need special settings.\nConfigure them here.",IDC_STATIC,7,7,265,17 CTEXT "Some games need special settings.\nConfigure them here.",IDC_STATIC,7,7,265,17
GROUPBOX "PCSX2 Gamefixes",IDC_STATIC,7,28,265,83 GROUPBOX "PCSX2 Gamefixes",IDC_STATIC,7,22,265,94
CONTROL "FPU Compare Hack - Special fix for Digimon Rumble Arena 2.",IDC_GAMEFIX3, CONTROL "FPU Compare Hack - Special fix for Digimon Rumble Arena 2.",IDC_GAMEFIX3,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,43,249,10 "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,36,249,10
CONTROL "VU Add Hack - Special fix for Tri-Ace games!",IDC_GAMEFIX2, CONTROL "VU Add Hack - Special fix for Tri-Ace games!",IDC_GAMEFIX2,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,72,252,10 "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,65,252,10
CONTROL "VU Clip Hack - Fixes missing ground geometry in Persona.",IDC_GAMEFIX4,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,79,238,10
CONTROL "FPU Mul Hack - Special fix for Tales of Destiny (possibly other games).",IDC_GAMEFIX5, CONTROL "FPU Mul Hack - Special fix for Tales of Destiny (possibly other games).",IDC_GAMEFIX5,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,57,249,10 "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,50,249,10
END END
@ -106,7 +108,7 @@ BEGIN
RIGHTMARGIN, 272 RIGHTMARGIN, 272
VERTGUIDE, 14 VERTGUIDE, 14
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 111 BOTTOMMARGIN, 116
HORZGUIDE, 103 HORZGUIDE, 103
END END
END END

View File

@ -1617,23 +1617,29 @@ REC_FUNC_DEL( QFSRV, _Rd_);
PCSX2_ALIGNED16(int s_MaskHighBitD[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; PCSX2_ALIGNED16(int s_MaskHighBitD[4]) = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
PCSX2_ALIGNED16(int s_MaskHighBitW[4]) = { 0x80008000, 0x80008000, 0x80008000, 0x80008000 }; PCSX2_ALIGNED16(int s_MaskHighBitW[4]) = { 0x80008000, 0x80008000, 0x80008000, 0x80008000 };
void recPABSW() void recPABSW() //needs clamping
{ {
if( !_Rd_ ) return; if( !_Rd_ ) return;
CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED)
int t0reg = _allocTempXMMreg(XMMT_INT, -1);
SSE2_PCMPEQD_XMM_to_XMM(t0reg, t0reg);
SSE2_PSLLD_I8_to_XMM(t0reg, 31);
SSE2_PCMPEQD_XMM_to_XMM(t0reg, EEREC_T); //0xffffffff if equal to 0x80000000
if( cpucaps.hasSupplementalStreamingSIMD3Extensions ) { if( cpucaps.hasSupplementalStreamingSIMD3Extensions ) {
SSSE3_PABSD_XMM_to_XMM(EEREC_D, EEREC_T); SSSE3_PABSD_XMM_to_XMM(EEREC_D, EEREC_T); //0x80000000 -> 0x80000000
} }
else { else {
int t0reg = _allocTempXMMreg(XMMT_INT, -1); int t1reg = _allocTempXMMreg(XMMT_INT, -1);
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T);
SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T);
SSE2_PSRAD_I8_to_XMM(t0reg, 31); SSE2_PSRAD_I8_to_XMM(t1reg, 31);
SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); SSEX_PXOR_XMM_to_XMM(EEREC_D, t1reg);
SSE2_PSUBD_XMM_to_XMM(EEREC_D, t0reg); SSE2_PSUBD_XMM_to_XMM(EEREC_D, t1reg); //0x80000000 -> 0x80000000
_freeXMMreg(t0reg); _freeXMMreg(t1reg);
} }
SSE2_PXOR_XMM_to_XMM(EEREC_D, t0reg); //0x80000000 -> 0x7fffffff
_freeXMMreg(t0reg);
CPU_SSE_XMMCACHE_END CPU_SSE_XMMCACHE_END
_deleteEEreg(_Rt_, 1); _deleteEEreg(_Rt_, 1);
@ -1645,24 +1651,31 @@ CPU_SSE_XMMCACHE_END
CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PABSW ); CALLFunc( (uptr)R5900::Interpreter::OpcodeImpl::MMI::PABSW );
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
void recPABSH() void recPABSH()
{ {
if( !_Rd_ ) return; if( !_Rd_ ) return;
CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED) CPU_SSE2_XMMCACHE_START(XMMINFO_READT|XMMINFO_WRITED)
int t0reg = _allocTempXMMreg(XMMT_INT, -1);
SSE2_PCMPEQW_XMM_to_XMM(t0reg, t0reg);
SSE2_PSLLW_I8_to_XMM(t0reg, 15);
SSE2_PCMPEQW_XMM_to_XMM(t0reg, EEREC_T); //0xffff if equal to 0x8000
if( cpucaps.hasSupplementalStreamingSIMD3Extensions ) { if( cpucaps.hasSupplementalStreamingSIMD3Extensions ) {
SSSE3_PABSW_XMM_to_XMM(EEREC_D, EEREC_T); SSSE3_PABSW_XMM_to_XMM(EEREC_D, EEREC_T); //0x8000 -> 0x8000
} }
else { else {
int t0reg = _allocTempXMMreg(XMMT_INT, -1); int t1reg = _allocTempXMMreg(XMMT_INT, -1);
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_T); SSEX_MOVDQA_XMM_to_XMM(t1reg, EEREC_T);
SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T);
SSE2_PSRAW_I8_to_XMM(t0reg, 15); SSE2_PSRAW_I8_to_XMM(t1reg, 15);
SSEX_PXOR_XMM_to_XMM(EEREC_D, t0reg); SSEX_PXOR_XMM_to_XMM(EEREC_D, t1reg);
SSE2_PSUBW_XMM_to_XMM(EEREC_D, t0reg); SSE2_PSUBW_XMM_to_XMM(EEREC_D, t1reg); //0x8000 -> 0x8000
_freeXMMreg(t0reg); _freeXMMreg(t1reg);
} }
SSE2_PXOR_XMM_to_XMM(EEREC_D, t0reg); //0x8000 -> 0x7fff
_freeXMMreg(t0reg);
CPU_SSE_XMMCACHE_END CPU_SSE_XMMCACHE_END
_deleteEEreg(_Rt_, 1); _deleteEEreg(_Rt_, 1);
@ -1968,7 +1981,7 @@ void recQFSRV()
SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T); SSE2_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_T);
MOV32MtoR(EAX, (uptr)&cpuRegs.sa); MOV32MtoR(EAX, (uptr)&cpuRegs.sa);
SHL32ItoR(EAX, 1); // Multiply SA bytes by 16 bytes (the amount of bytes in QFSRVhelper() macros) SHL32ItoR(EAX, 4); // Multiply SA bytes by 16 bytes (the amount of bytes in QFSRVhelper() macros)
AND32I8toR(EAX, 0xf0); // This can possibly be removed but keeping it incase theres garbage in SA (cottonvibes) AND32I8toR(EAX, 0xf0); // This can possibly be removed but keeping it incase theres garbage in SA (cottonvibes)
ADD32ItoEAX((uptr)x86Ptr[0] + 7); // ADD32 = 5 bytes, JMPR = 2 bytes ADD32ItoEAX((uptr)x86Ptr[0] + 7); // ADD32 = 5 bytes, JMPR = 2 bytes
JMPR(EAX); // Jumps to a QFSRVhelper() case below (a total of 16 different cases) JMPR(EAX); // Jumps to a QFSRVhelper() case below (a total of 16 different cases)
@ -2402,8 +2415,8 @@ CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WR
// shamt is 5-bit // shamt is 5-bit
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S);
SSE2_PSLLQ_I8_to_XMM(t0reg, 27); SSE2_PSLLQ_I8_to_XMM(t0reg, 27+32);
SSE2_PSRLQ_I8_to_XMM(t0reg, 27); SSE2_PSRLQ_I8_to_XMM(t0reg, 27+32);
// EEREC_D[0] <- Rt[0], t1reg[0] <- Rt[2] // EEREC_D[0] <- Rt[0], t1reg[0] <- Rt[2]
SSE_MOVHLPS_XMM_to_XMM(t1reg, EEREC_T); SSE_MOVHLPS_XMM_to_XMM(t1reg, EEREC_T);
@ -2470,8 +2483,8 @@ CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WR
// shamt is 5-bit // shamt is 5-bit
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S);
SSE2_PSLLQ_I8_to_XMM(t0reg, 27); SSE2_PSLLQ_I8_to_XMM(t0reg, 27+32);
SSE2_PSRLQ_I8_to_XMM(t0reg, 27); SSE2_PSRLQ_I8_to_XMM(t0reg, 27+32);
// EEREC_D[0] <- Rt[0], t1reg[0] <- Rt[2] // EEREC_D[0] <- Rt[0], t1reg[0] <- Rt[2]
SSE_MOVHLPS_XMM_to_XMM(t1reg, EEREC_T); SSE_MOVHLPS_XMM_to_XMM(t1reg, EEREC_T);
@ -2619,9 +2632,18 @@ void recPDIVBW()
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
PCSX2_ALIGNED16(int s_mask1[4]) = {~0, 0, ~0, 0}; PCSX2_ALIGNED16(int s_mask1[4]) = {~0, 0, ~0, 0};
//upper word of each doubleword in LO and HI is undocumented/undefined
//contains the upper multiplication result (before the addition with the lower multiplication result)
void recPHMADH() void recPHMADH()
{ {
CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI) CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI)
int t0reg = _allocTempXMMreg(XMMT_INT, -1);
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S);
SSE2_PSRLD_I8_to_XMM(t0reg, 16);
SSE2_PSLLD_I8_to_XMM(t0reg, 16);
SSE2_PMADDWD_XMM_to_XMM(t0reg, EEREC_T);
if( _Rd_ ) { if( _Rd_ ) {
if( EEREC_D == EEREC_S ) { if( EEREC_D == EEREC_S ) {
SSE2_PMADDWD_XMM_to_XMM(EEREC_D, EEREC_T); SSE2_PMADDWD_XMM_to_XMM(EEREC_D, EEREC_T);
@ -2641,14 +2663,22 @@ CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMI
} }
SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO);
SSE2_PSRLQ_I8_to_XMM(EEREC_HI, 32);
SSE_SHUFPS_XMM_to_XMM(EEREC_LO, t0reg, 0x88);
SSE_SHUFPS_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8);
SSE_SHUFPS_XMM_to_XMM(EEREC_HI, t0reg, 0xdd);
SSE_SHUFPS_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8);
_freeXMMreg(t0reg);
CPU_SSE_XMMCACHE_END CPU_SSE_XMMCACHE_END
recCall( Interp::PHMADH, _Rd_ ); recCall( Interp::PHMADH, _Rd_ );
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
//upper word of each doubleword in LO and HI is undocumented/undefined
//contains the NOT of the upper multiplication result (before the substraction of the lower multiplication result)
void recPMSUBH() void recPMSUBH()
{ {
CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI) CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_READLO|XMMINFO_READHI|XMMINFO_WRITELO|XMMINFO_WRITEHI)
@ -2710,22 +2740,41 @@ CPU_SSE_XMMCACHE_END
} }
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// rs = ... a1 a0
// rt = ... b1 b0
// rd = ... a1*b1 - a0*b0
// hi = ...
// lo = ... (undefined by doc)NOT(a1*b1), a1*b1 - a0*b0
void recPHMSBH() void recPHMSBH()
{ {
CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI) CPU_SSE2_XMMCACHE_START((_Rd_?XMMINFO_WRITED:0)|XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI)
int t0reg = _allocTempXMMreg(XMMT_INT, -1);
SSE2_PCMPEQD_XMM_to_XMM(EEREC_LO, EEREC_LO); SSE2_PCMPEQD_XMM_to_XMM(EEREC_LO, EEREC_LO);
SSE2_PSRLD_XMM_to_XMM(EEREC_LO, 16); SSE2_PSRLD_I8_to_XMM(EEREC_LO, 16);
SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S); SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_S);
SSE2_PAND_XMM_to_XMM(EEREC_HI, EEREC_LO); SSE2_PAND_XMM_to_XMM(EEREC_HI, EEREC_LO);
SSE2_PMADDWD_XMM_to_XMM(EEREC_HI, EEREC_T); SSE2_PMADDWD_XMM_to_XMM(EEREC_HI, EEREC_T);
SSE2_PSLLD_XMM_to_XMM(EEREC_LO, 16); SSE2_PSLLD_I8_to_XMM(EEREC_LO, 16);
SSE2_PAND_XMM_to_XMM(EEREC_LO, EEREC_S); SSE2_PAND_XMM_to_XMM(EEREC_LO, EEREC_S);
SSE2_PMADDWD_XMM_to_XMM(EEREC_LO, EEREC_T); SSE2_PMADDWD_XMM_to_XMM(EEREC_LO, EEREC_T);
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_LO);
SSE2_PSUBD_XMM_to_XMM(EEREC_LO, EEREC_HI); SSE2_PSUBD_XMM_to_XMM(EEREC_LO, EEREC_HI);
if( _Rd_ ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO); if( _Rd_ ) SSEX_MOVDQA_XMM_to_XMM(EEREC_D, EEREC_LO);
SSE2_PCMPEQD_XMM_to_XMM(EEREC_HI, EEREC_HI);
SSE2_PXOR_XMM_to_XMM(t0reg, EEREC_HI);
SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO); SSEX_MOVDQA_XMM_to_XMM(EEREC_HI, EEREC_LO);
SSE2_PSRLQ_I8_to_XMM(EEREC_HI, 32);
SSE_SHUFPS_XMM_to_XMM(EEREC_LO, t0reg, 0x88);
SSE_SHUFPS_XMM_to_XMM(EEREC_LO, EEREC_LO, 0xd8);
SSE_SHUFPS_XMM_to_XMM(EEREC_HI, t0reg, 0xdd);
SSE_SHUFPS_XMM_to_XMM(EEREC_HI, EEREC_HI, 0xd8);
_freeXMMreg(t0reg);
CPU_SSE_XMMCACHE_END CPU_SSE_XMMCACHE_END
recCall( Interp::PHMSBH, _Rd_ ); recCall( Interp::PHMSBH, _Rd_ );
@ -3278,8 +3327,8 @@ CPU_SSE2_XMMCACHE_START((_Rs_?XMMINFO_READS:0)|(_Rt_?XMMINFO_READT:0)|XMMINFO_WR
// shamt is 5-bit // shamt is 5-bit
SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S); SSEX_MOVDQA_XMM_to_XMM(t0reg, EEREC_S);
SSE2_PSLLQ_I8_to_XMM(t0reg, 27); SSE2_PSLLQ_I8_to_XMM(t0reg, 27+32);
SSE2_PSRLQ_I8_to_XMM(t0reg, 27); SSE2_PSRLQ_I8_to_XMM(t0reg, 27+32);
// EEREC_D[0] <- Rt[0], t1reg[0] <- Rt[2] // EEREC_D[0] <- Rt[0], t1reg[0] <- Rt[2]
SSE_MOVHLPS_XMM_to_XMM(t1reg, EEREC_T); SSE_MOVHLPS_XMM_to_XMM(t1reg, EEREC_T);

View File

@ -94,10 +94,11 @@ void recMFSA( void )
} }
} }
// SA is 4-bit and contains the amount of bytes to shift
void recMTSA( void ) void recMTSA( void )
{ {
if( GPR_IS_CONST1(_Rs_) ) { if( GPR_IS_CONST1(_Rs_) ) {
MOV32ItoM((uptr)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] ); MOV32ItoM((uptr)&cpuRegs.sa, g_cpuConstRegs[_Rs_].UL[0] & 0xf );
} }
else { else {
int mmreg; int mmreg;
@ -113,19 +114,19 @@ void recMTSA( void )
MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]); MOV32MtoR(EAX, (uptr)&cpuRegs.GPR.r[_Rs_].UL[0]);
MOV32RtoM((uptr)&cpuRegs.sa, EAX); MOV32RtoM((uptr)&cpuRegs.sa, EAX);
} }
AND32ItoM((uptr)&cpuRegs.sa, 0xf);
} }
} }
void recMTSAB( void ) void recMTSAB( void )
{ {
if( GPR_IS_CONST1(_Rs_) ) { if( GPR_IS_CONST1(_Rs_) ) {
MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) << 3); MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0xF) ^ (_Imm_ & 0xF)) );
} }
else { else {
_eeMoveGPRtoR(EAX, _Rs_); _eeMoveGPRtoR(EAX, _Rs_);
AND32ItoR(EAX, 0xF); AND32ItoR(EAX, 0xF);
XOR32ItoR(EAX, _Imm_&0xf); XOR32ItoR(EAX, _Imm_&0xf);
SHL32ItoR(EAX, 3);
MOV32RtoM((uptr)&cpuRegs.sa, EAX); MOV32RtoM((uptr)&cpuRegs.sa, EAX);
} }
} }
@ -133,13 +134,13 @@ void recMTSAB( void )
void recMTSAH( void ) void recMTSAH( void )
{ {
if( GPR_IS_CONST1(_Rs_) ) { if( GPR_IS_CONST1(_Rs_) ) {
MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 4); MOV32ItoM((uptr)&cpuRegs.sa, ((g_cpuConstRegs[_Rs_].UL[0] & 0x7) ^ (_Imm_ & 0x7)) << 1);
} }
else { else {
_eeMoveGPRtoR(EAX, _Rs_); _eeMoveGPRtoR(EAX, _Rs_);
AND32ItoR(EAX, 0x7); AND32ItoR(EAX, 0x7);
XOR32ItoR(EAX, _Imm_&0x7); XOR32ItoR(EAX, _Imm_&0x7);
SHL32ItoR(EAX, 4); SHL32ItoR(EAX, 1);
MOV32RtoM((uptr)&cpuRegs.sa, EAX); MOV32RtoM((uptr)&cpuRegs.sa, EAX);
} }
} }

View File

@ -3000,7 +3000,7 @@ void VuInstruction::Recompile(list<VuInstruction>::iterator& itinst, u32 vuxyz)
if( type & INST_CLIP_WRITE ) { if( type & INST_CLIP_WRITE ) {
if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) { if( nParentPc < s_pCurBlock->startpc || nParentPc >= (int)pc ) {
if( pparentinst != NULL ) { if( !CHECK_VUCLIPFLAGHACK && pparentinst != NULL ) {
if( nParentCheckForExecution >= 0 ) { if( nParentCheckForExecution >= 0 ) {
if( pparentinst->pClipWrite == 0 ) if( pparentinst->pClipWrite == 0 )

View File

@ -595,14 +595,31 @@ void recMULTU1_constt(int info)
EERECOMPILE_CODE0(MULTU1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0)); EERECOMPILE_CODE0(MULTU1, XMMINFO_READS|XMMINFO_READT|(_Rd_?XMMINFO_WRITED:0));
//// DIV //// DIV
void recDIVconst(int upper)
{
s32 quot, rem;
if (g_cpuConstRegs[_Rs_].UL[0] == 0x80000000 && g_cpuConstRegs[_Rt_].SL[0] == -1)
{
quot = (s32)0x80000000;
rem = 0;
}
else if (g_cpuConstRegs[_Rt_].SL[0] != 0)
{
quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0];
rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0];
}
else
{
quot = (g_cpuConstRegs[_Rs_].SL[0] < 0) ? 1 : -1;
rem = g_cpuConstRegs[_Rs_].SL[0];
}
recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, upper);
}
void recDIV_const() void recDIV_const()
{ {
if (g_cpuConstRegs[_Rt_].SL[0] != 0) { recDIVconst(0);
s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0];
s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0];
recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0);
}
} }
void recDIVsuper(int info, int sign, int upper, int process) void recDIVsuper(int info, int sign, int upper, int process)
@ -610,24 +627,46 @@ void recDIVsuper(int info, int sign, int upper, int process)
EEINST_SETSIGNEXT(_Rs_); EEINST_SETSIGNEXT(_Rs_);
EEINST_SETSIGNEXT(_Rt_); EEINST_SETSIGNEXT(_Rt_);
if( process & PROCESS_CONSTT ) { if( process & PROCESS_CONSTT )
if( !g_cpuConstRegs[_Rt_].UL[0] )
return;
MOV32ItoR( ECX, g_cpuConstRegs[_Rt_].UL[0] ); MOV32ItoR( ECX, g_cpuConstRegs[_Rt_].UL[0] );
} else
else {
MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] ); MOV32MtoR( ECX, (int)&cpuRegs.GPR.r[ _Rt_ ].UL[ 0 ] );
OR32RtoR( ECX, ECX );
j8Ptr[ 0 ] = JE8( 0 );
}
if( process & PROCESS_CONSTS ) if( process & PROCESS_CONSTS )
MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] ); MOV32ItoR( EAX, g_cpuConstRegs[_Rs_].UL[0] );
else { else
MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] ); MOV32MtoR( EAX, (int)&cpuRegs.GPR.r[ _Rs_ ].UL[ 0 ] );
u8 *end1;
if (sign) //test for overflow (x86 will just throw an exception)
{
CMP32ItoR( EAX, 0x80000000 );
u8 *cont1 = JNE8(0);
CMP32ItoR( ECX, 0xffffffff );
u8 *cont2 = JNE8(0);
//overflow case:
XOR32RtoR( EDX, EDX ); //EAX remains 0x80000000
end1 = JMP8(0);
x86SetJ8(cont1);
x86SetJ8(cont2);
} }
CMP32ItoR( ECX, 0 );
u8 *cont3 = JNE8(0);
//divide by zero
MOV32RtoR( EDX, EAX );
if (sign) //set EAX to (EAX < 0)?1:-1
{
SAR32ItoR( EAX, 31 ); //(EAX < 0)?-1:0
SHL32ItoR( EAX, 1 ); //(EAX < 0)?-2:0
NOT32R( EAX ); //(EAX < 0)?1:-1
}
else
MOV32ItoR( EAX, 0xffffffff );
u8 *end2 = JMP8(0);
x86SetJ8(cont3);
if( sign ) { if( sign ) {
CDQ(); CDQ();
IDIV32R( ECX ); IDIV32R( ECX );
@ -636,7 +675,9 @@ void recDIVsuper(int info, int sign, int upper, int process)
XOR32RtoR( EDX, EDX ); XOR32RtoR( EDX, EDX );
DIV32R( ECX ); DIV32R( ECX );
} }
if( !(process & PROCESS_CONSTT) ) x86SetJ8( j8Ptr[ 0 ] );
if (sign) x86SetJ8( end1 );
x86SetJ8( end2 );
// need to execute regardless of bad divide // need to execute regardless of bad divide
recWritebackHILO(info, 0, upper); recWritebackHILO(info, 0, upper);
@ -660,14 +701,25 @@ void recDIV_constt(int info)
EERECOMPILE_CODE0(DIV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI); EERECOMPILE_CODE0(DIV, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRITEHI);
//// DIVU //// DIVU
void recDIVUconst(int upper)
{
u32 quot, rem;
if (g_cpuConstRegs[_Rt_].UL[0] != 0) {
quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0];
rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0];
}
else
{
quot = 0xffffffff;
rem = g_cpuConstRegs[_Rs_].UL[0];
}
recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, upper);
}
void recDIVU_const() void recDIVU_const()
{ {
if (g_cpuConstRegs[_Rt_].UL[0] != 0) { recDIVUconst(0);
u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0];
u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0];
recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 0);
}
} }
void recDIVU_(int info) void recDIVU_(int info)
@ -689,12 +741,7 @@ EERECOMPILE_CODE0(DIVU, XMMINFO_READS|XMMINFO_READT|XMMINFO_WRITELO|XMMINFO_WRIT
void recDIV1_const() void recDIV1_const()
{ {
if (g_cpuConstRegs[_Rt_].SL[0] != 0) { recDIVconst(1);
s32 quot = g_cpuConstRegs[_Rs_].SL[0] / g_cpuConstRegs[_Rt_].SL[0];
s32 rem = g_cpuConstRegs[_Rs_].SL[0] % g_cpuConstRegs[_Rt_].SL[0];
recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1);
}
} }
void recDIV1_(int info) void recDIV1_(int info)
@ -716,12 +763,7 @@ EERECOMPILE_CODE0(DIV1, XMMINFO_READS|XMMINFO_READT);
void recDIVU1_const() void recDIVU1_const()
{ {
if (g_cpuConstRegs[_Rt_].UL[0] != 0) { recDIVUconst(1);
u32 quot = g_cpuConstRegs[_Rs_].UL[0] / g_cpuConstRegs[_Rt_].UL[0];
u32 rem = g_cpuConstRegs[_Rs_].UL[0] % g_cpuConstRegs[_Rt_].UL[0];
recWritebackConstHILO((u64)quot|((u64)rem<<32), 0, 1);
}
} }
void recDIVU1_(int info) void recDIVU1_(int info)