Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ static ConfigSetting cpuSettings[] = {
ConfigSetting("FastMemoryAccess", &g_Config.bFastMemory, true),
ReportedConfigSetting("FuncReplacements", &g_Config.bFuncReplacements, true),
ReportedConfigSetting("CPUSpeed", &g_Config.iLockedCPUSpeed, 0),
ReportedConfigSetting("SetRoundingMode", &g_Config.bSetRoundingMode, true),

ConfigSetting(false),
};
Expand Down
1 change: 1 addition & 0 deletions Core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct Config {
bool bCheckForNewVersion;
bool bForceLagSync;
bool bFuncReplacements;
bool bSetRoundingMode;

// Definitely cannot be changed while game is running.
bool bSeparateCPUThread;
Expand Down
5 changes: 5 additions & 0 deletions Core/MIPS/ARM/ArmAsm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ void Jit::GenerateFixedCode()
MovToPC(R0);
outerLoop = GetCodePtr();
SaveDowncount();
ClearRoundingMode();
QuickCallFunction(R0, &CoreTiming::Advance);
SetRoundingMode();
RestoreDowncount();
FixupBranch skipToRealDispatch = B(); //skip the sync and compare first time

Expand Down Expand Up @@ -173,7 +175,9 @@ void Jit::GenerateFixedCode()

// No block found, let's jit
SaveDowncount();
ClearRoundingMode();
QuickCallFunction(R2, (void *)&JitAt);
SetRoundingMode();
RestoreDowncount();

B(dispatcherNoCheck); // no point in special casing this
Expand All @@ -195,6 +199,7 @@ void Jit::GenerateFixedCode()
}

SaveDowncount();
ClearRoundingMode();

ADD(R_SP, R_SP, 4);

Expand Down
2 changes: 2 additions & 0 deletions Core/MIPS/ARM/ArmCompBranch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ void Jit::Comp_Syscall(MIPSOpcode op)
// If we're in a delay slot, this is off by one.
const int offset = js.inDelaySlot ? -1 : 0;
WriteDownCount(offset);
ClearRoundingMode();
js.downcountAmount = -offset;

// TODO: Maybe discard v0, v1, and some temps? Definitely at?
Expand All @@ -558,6 +559,7 @@ void Jit::Comp_Syscall(MIPSOpcode op)
QuickCallFunction(R1, (void *)&CallSyscall);
}
RestoreDowncount();
SetRoundingMode();

WriteSyscallExit();
js.compiling = false;
Expand Down
30 changes: 10 additions & 20 deletions Core/MIPS/ARM/ArmCompFPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ namespace MIPSComp
void Jit::Comp_FPU3op(MIPSOpcode op)
{
CONDITIONAL_DISABLE;
SetRoundingMode();

int ft = _FT;
int fs = _FS;
Expand Down Expand Up @@ -190,6 +191,9 @@ void Jit::Comp_FPULS(MIPSOpcode op)

void Jit::Comp_FPUComp(MIPSOpcode op) {
CONDITIONAL_DISABLE;
// TODO: Does this matter here?
SetRoundingMode();

int opc = op & 0xF;
if (opc >= 8) opc -= 8; // alias
if (opc == 0) { // f, sf (signalling false)
Expand Down Expand Up @@ -279,6 +283,7 @@ void Jit::Comp_FPU2op(MIPSOpcode op) {
VNEG(fpr.R(fd), fpr.R(fs));
break;
case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
ClearRoundingMode();
fpr.MapDirtyIn(fd, fs);
VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED);
break;
Expand All @@ -293,9 +298,10 @@ void Jit::Comp_FPU2op(MIPSOpcode op) {
break;
case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
{
ClearRoundingMode();
fpr.MapDirtyIn(fd, fs);
VMRS(SCRATCHREG2);
// Assume we're always in round-to-zero mode.
// Assume we're always in round-to-nearest mode.
ORR(SCRATCHREG1, SCRATCHREG2, AssumeMakeOperand2(1 << 22));
VMSR(SCRATCHREG1);
VCMP(fpr.R(fs), fpr.R(fs));
Expand All @@ -310,9 +316,10 @@ void Jit::Comp_FPU2op(MIPSOpcode op) {
}
case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s
{
ClearRoundingMode();
fpr.MapDirtyIn(fd, fs);
VMRS(SCRATCHREG2);
// Assume we're always in round-to-zero mode.
// Assume we're always in round-to-nearest mode.
ORR(SCRATCHREG1, SCRATCHREG2, AssumeMakeOperand2(2 << 22));
VMSR(SCRATCHREG1);
VCMP(fpr.R(fs), fpr.R(fs));
Expand All @@ -331,30 +338,13 @@ void Jit::Comp_FPU2op(MIPSOpcode op) {
break;
case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s
fpr.MapDirtyIn(fd, fs);
LDR(SCRATCHREG1, CTXREG, offsetof(MIPSState, fcr31));
AND(SCRATCHREG1, SCRATCHREG1, Operand2(3));
// MIPS Rounding Mode: ARM Rounding Mode
// 0: Round nearest 0
// 1: Round to zero 3
// 2: Round up (ceil) 1
// 3: Round down (floor) 2
CMP(SCRATCHREG1, Operand2(1));
SetCC(CC_EQ); ADD(SCRATCHREG1, SCRATCHREG1, Operand2(2));
SetCC(CC_GT); SUB(SCRATCHREG1, SCRATCHREG1, Operand2(1));
SetCC(CC_AL);

VMRS(SCRATCHREG2);
// Assume we're always in round-to-zero mode beforehand.
ORR(SCRATCHREG1, SCRATCHREG2, Operand2(SCRATCHREG1, ST_LSL, 22));
VMSR(SCRATCHREG1);
SetRoundingMode();
VCMP(fpr.R(fs), fpr.R(fs));
VCVT(fpr.R(fd), fpr.R(fs), TO_INT | IS_SIGNED);
VMRS_APSR(); // Move FP flags from FPSCR to APSR (regular flags).
SetCC(CC_VS);
MOVIU2F(fpr.R(fd), 0x7FFFFFFF, SCRATCHREG1);
SetCC(CC_AL);
// Set the rounding mode back. TODO: Keep it? Dirty?
VMSR(SCRATCHREG2);
break;
default:
DISABLE;
Expand Down
38 changes: 38 additions & 0 deletions Core/MIPS/ARM/ArmJit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "base/logging.h"
#include "Common/ChunkFile.h"
#include "Core/Reporting.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/MemMap.h"
Expand Down Expand Up @@ -466,10 +467,13 @@ void Jit::Comp_Generic(MIPSOpcode op)
if (func)
{
SaveDowncount();
// TODO: Perhaps keep the rounding mode for interp?
ClearRoundingMode();
gpr.SetRegImm(SCRATCHREG1, js.compilerPC);
MovToPC(SCRATCHREG1);
gpr.SetRegImm(R0, op.encoding);
QuickCallFunction(R1, (void *)func);
SetRoundingMode();
RestoreDowncount();
}

Expand Down Expand Up @@ -541,6 +545,40 @@ void Jit::WriteDownCountR(ARMReg reg)
}
}

void Jit::ClearRoundingMode()
{
if (g_Config.bSetRoundingMode)
{
VMRS(SCRATCHREG2);
// Assume we're always in round-to-nearest mode beforehand.
BIC(SCRATCHREG1, SCRATCHREG2, AssumeMakeOperand2(3 << 22));
VMSR(SCRATCHREG1);
}
}

void Jit::SetRoundingMode()
{
if (g_Config.bSetRoundingMode)
{
LDR(SCRATCHREG1, CTXREG, offsetof(MIPSState, fcr31));
AND(SCRATCHREG1, SCRATCHREG1, Operand2(3));
// MIPS Rounding Mode: ARM Rounding Mode
// 0: Round nearest 0
// 1: Round to zero 3
// 2: Round up (ceil) 1
// 3: Round down (floor) 2
CMP(SCRATCHREG1, Operand2(1));
SetCC(CC_EQ); ADD(SCRATCHREG1, SCRATCHREG1, Operand2(2));
SetCC(CC_GT); SUB(SCRATCHREG1, SCRATCHREG1, Operand2(1));
SetCC(CC_AL);

VMRS(SCRATCHREG2);
// Assume we're always in round-to-nearest mode beforehand.
ORR(SCRATCHREG1, SCRATCHREG2, Operand2(SCRATCHREG1, ST_LSL, 22));
VMSR(SCRATCHREG1);
}
}

// IDEA - could have a WriteDualExit that takes two destinations and two condition flags,
// and just have conditional that set PC "twice". This only works when we fall back to dispatcher
// though, as we need to have the SUBS flag set in the end. So with block linking in the mix,
Expand Down
2 changes: 2 additions & 0 deletions Core/MIPS/ARM/ArmJit.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ class Jit : public ArmGen::ARMXCodeBlock

void WriteDownCount(int offset = 0);
void WriteDownCountR(ARMReg reg);
void ClearRoundingMode();
void SetRoundingMode();
void MovFromPC(ARMReg r);
void MovToPC(ARMReg r);

Expand Down
6 changes: 6 additions & 0 deletions Core/MIPS/x86/Asm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,9 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
#endif

outerLoop = GetCodePtr();
jit->ClearRoundingMode(this);
ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance));
jit->SetRoundingMode(this);
FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time

dispatcherCheckCoreState = GetCodePtr();
Expand Down Expand Up @@ -129,7 +131,9 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
SetJumpTarget(notfound);

//Ok, no block, let's jit
jit->ClearRoundingMode(this);
ABI_CallFunction(&Jit);
jit->SetRoundingMode(this);
JMP(dispatcherNoCheck); // Let's just dispatch again, we'll enter the block since we know it's there.

SetJumpTarget(bail);
Expand All @@ -139,10 +143,12 @@ void AsmRoutineManager::Generate(MIPSState *mips, MIPSComp::Jit *jit)
J_CC(CC_Z, outerLoop, true);

SetJumpTarget(badCoreState);
jit->ClearRoundingMode(this);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();

breakpointBailout = GetCodePtr();
jit->ClearRoundingMode(this);
ABI_PopAllCalleeSavedRegsAndAdjustStack();
RET();
}
2 changes: 2 additions & 0 deletions Core/MIPS/x86/CompBranch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@ void Jit::Comp_Syscall(MIPSOpcode op)
// If we're in a delay slot, this is off by one.
const int offset = js.inDelaySlot ? -1 : 0;
WriteDowncount(offset);
ClearRoundingMode();
js.downcountAmount = -offset;

// Skip the CallSyscall where possible.
Expand All @@ -690,6 +691,7 @@ void Jit::Comp_Syscall(MIPSOpcode op)
else
ABI_CallFunctionC(&CallSyscall, op.encoding);

SetRoundingMode();
WriteSyscallExit();
js.compiling = false;
}
Expand Down
25 changes: 24 additions & 1 deletion Core/MIPS/x86/CompFPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,32 @@ void Jit::Comp_FPU2op(MIPSOpcode op) {
MOVSS(fpr.R(fd), XMM0);
break;

case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s
{
fpr.SpillLock(fs, fd);
fpr.StoreFromRegister(fd);
CVTSS2SI(EAX, fpr.R(fs));

// Did we get an indefinite integer value?
CMP(32, R(EAX), Imm32(0x80000000));
FixupBranch skip = J_CC(CC_NE);
MOVSS(XMM0, fpr.R(fs));
XORPS(XMM1, R(XMM1));
CMPSS(XMM0, R(XMM1), CMP_LT);

// At this point, -inf = 0xffffffff, inf/nan = 0x00000000.
// We want -inf to be 0x80000000 inf/nan to be 0x7fffffff, so we flip those bits.
MOVD_xmm(R(EAX), XMM0);
XOR(32, R(EAX), Imm32(0x7fffffff));

SetJumpTarget(skip);
MOV(32, fpr.R(fd), R(EAX));
}
break;

case 12: //FsI(fd) = (int)floorf(F(fs)+0.5f); break; //round.w.s
case 14: //FsI(fd) = (int)ceilf (F(fs)); break; //ceil.w.s
case 15: //FsI(fd) = (int)floorf(F(fs)); break; //floor.w.s
case 36: //FsI(fd) = (int) F(fs); break; //cvt.w.s
default:
DISABLE;
return;
Expand Down Expand Up @@ -357,6 +379,7 @@ void Jit::Comp_mxc1(MIPSOpcode op)

case 6: //currentMIPS->WriteFCR(fs, R(rt)); break; //ctc1
if (fs == 31) {
ClearRoundingMode();
if (gpr.IsImm(rt)) {
gpr.SetImm(MIPS_REG_FPCOND, (gpr.GetImm(rt) >> 23) & 1);
MOV(32, M(&mips_->fcr31), Imm32(gpr.GetImm(rt) & 0x0181FFFF));
Expand Down
Loading