Big FPU improvements

This commit is contained in:
SimoneN64
2023-11-11 13:48:30 +01:00
parent 61169f79ee
commit 0791e83e53
3 changed files with 313 additions and 127 deletions

View File

@@ -76,22 +76,22 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
case 0x21: cvtds(regs, instr); break; case 0x21: cvtds(regs, instr); break;
case 0x24: cvtws(regs, instr); break; case 0x24: cvtws(regs, instr); break;
case 0x25: cvtls(regs, instr); break; case 0x25: cvtls(regs, instr); break;
case 0x30: ccond<float>(regs, instr, F); break; case 0x30: cf<float>(regs, instr); break;
case 0x31: ccond<float>(regs, instr, UN); break; case 0x31: cun<float>(regs, instr); break;
case 0x32: ccond<float>(regs, instr, EQ); break; case 0x32: ceq<float>(regs, instr); break;
case 0x33: ccond<float>(regs, instr, UEQ); break; case 0x33: cueq<float>(regs, instr); break;
case 0x34: ccond<float>(regs, instr, OLT); break; case 0x34: colt<float>(regs, instr); break;
case 0x35: ccond<float>(regs, instr, ULT); break; case 0x35: cult<float>(regs, instr); break;
case 0x36: ccond<float>(regs, instr, OLE); break; case 0x36: cole<float>(regs, instr); break;
case 0x37: ccond<float>(regs, instr, ULE); break; case 0x37: cule<float>(regs, instr); break;
case 0x38: ccond<float>(regs, instr, SF); break; case 0x38: csf<float>(regs, instr); break;
case 0x39: ccond<float>(regs, instr, NGLE); break; case 0x39: cngle<float>(regs, instr); break;
case 0x3A: ccond<float>(regs, instr, SEQ); break; case 0x3A: cseq<float>(regs, instr); break;
case 0x3B: ccond<float>(regs, instr, NGL); break; case 0x3B: cngl<float>(regs, instr); break;
case 0x3C: ccond<float>(regs, instr, LT); break; case 0x3C: clt<float>(regs, instr); break;
case 0x3D: ccond<float>(regs, instr, NGE); break; case 0x3D: cnge<float>(regs, instr); break;
case 0x3E: ccond<float>(regs, instr, LE); break; case 0x3E: cle<float>(regs, instr); break;
case 0x3F: ccond<float>(regs, instr, NGT); break; case 0x3F: cngt<float>(regs, instr); break;
default: unimplemented(regs); default: unimplemented(regs);
} }
break; break;
@@ -116,22 +116,22 @@ void Cop1::decodeInterp(Interpreter &cpu, u32 instr) {
case 0x20: cvtsd(regs, instr); break; case 0x20: cvtsd(regs, instr); break;
case 0x24: cvtwd(regs, instr); break; case 0x24: cvtwd(regs, instr); break;
case 0x25: cvtld(regs, instr); break; case 0x25: cvtld(regs, instr); break;
case 0x30: ccond<double>(regs, instr, F); break; case 0x30: cf<double>(regs, instr); break;
case 0x31: ccond<double>(regs, instr, UN); break; case 0x31: cun<double>(regs, instr); break;
case 0x32: ccond<double>(regs, instr, EQ); break; case 0x32: ceq<double>(regs, instr); break;
case 0x33: ccond<double>(regs, instr, UEQ); break; case 0x33: cueq<double>(regs, instr); break;
case 0x34: ccond<double>(regs, instr, OLT); break; case 0x34: colt<double>(regs, instr); break;
case 0x35: ccond<double>(regs, instr, ULT); break; case 0x35: cult<double>(regs, instr); break;
case 0x36: ccond<double>(regs, instr, OLE); break; case 0x36: cole<double>(regs, instr); break;
case 0x37: ccond<double>(regs, instr, ULE); break; case 0x37: cule<double>(regs, instr); break;
case 0x38: ccond<double>(regs, instr, SF); break; case 0x38: csf<double>(regs, instr); break;
case 0x39: ccond<double>(regs, instr, NGLE); break; case 0x39: cngle<double>(regs, instr); break;
case 0x3A: ccond<double>(regs, instr, SEQ); break; case 0x3A: cseq<double>(regs, instr); break;
case 0x3B: ccond<double>(regs, instr, NGL); break; case 0x3B: cngl<double>(regs, instr); break;
case 0x3C: ccond<double>(regs, instr, LT); break; case 0x3C: clt<double>(regs, instr); break;
case 0x3D: ccond<double>(regs, instr, NGE); break; case 0x3D: cnge<double>(regs, instr); break;
case 0x3E: ccond<double>(regs, instr, LE); break; case 0x3E: cle<double>(regs, instr); break;
case 0x3F: ccond<double>(regs, instr, NGT); break; case 0x3F: cngt<double>(regs, instr); break;
default: unimplemented(regs); default: unimplemented(regs);
} }
break; break;
@@ -220,22 +220,22 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
case 0x21: cvtds(regs, instr); break; case 0x21: cvtds(regs, instr); break;
case 0x24: cvtws(regs, instr); break; case 0x24: cvtws(regs, instr); break;
case 0x25: cvtls(regs, instr); break; case 0x25: cvtls(regs, instr); break;
case 0x30: ccond<float>(regs, instr, F); break; case 0x30://ccond<float>(regs, instr, F); break;
case 0x31: ccond<float>(regs, instr, UN); break; case 0x31://ccond<float>(regs, instr, UN); break;
case 0x32: ccond<float>(regs, instr, EQ); break; case 0x32://ccond<float>(regs, instr, EQ); break;
case 0x33: ccond<float>(regs, instr, UEQ); break; case 0x33://ccond<float>(regs, instr, UEQ); break;
case 0x34: ccond<float>(regs, instr, OLT); break; case 0x34://ccond<float>(regs, instr, OLT); break;
case 0x35: ccond<float>(regs, instr, ULT); break; case 0x35://ccond<float>(regs, instr, ULT); break;
case 0x36: ccond<float>(regs, instr, OLE); break; case 0x36://ccond<float>(regs, instr, OLE); break;
case 0x37: ccond<float>(regs, instr, ULE); break; case 0x37://ccond<float>(regs, instr, ULE); break;
case 0x38: ccond<float>(regs, instr, SF); break; case 0x38://ccond<float>(regs, instr, SF); break;
case 0x39: ccond<float>(regs, instr, NGLE); break; case 0x39://ccond<float>(regs, instr, NGLE); break;
case 0x3A: ccond<float>(regs, instr, SEQ); break; case 0x3A://ccond<float>(regs, instr, SEQ); break;
case 0x3B: ccond<float>(regs, instr, NGL); break; case 0x3B://ccond<float>(regs, instr, NGL); break;
case 0x3C: ccond<float>(regs, instr, LT); break; case 0x3C://ccond<float>(regs, instr, LT); break;
case 0x3D: ccond<float>(regs, instr, NGE); break; case 0x3D://ccond<float>(regs, instr, NGE); break;
case 0x3E: ccond<float>(regs, instr, LE); break; case 0x3E://ccond<float>(regs, instr, LE); break;
case 0x3F: ccond<float>(regs, instr, NGT); break; case 0x3F://ccond<float>(regs, instr, NGT); break;
default: Util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); default: Util::panic("Unimplemented COP1 function S[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
} }
break; break;
@@ -263,22 +263,22 @@ void Cop1::decodeJIT(JIT &cpu, u32 instr) {
break; break;
case 0x24: cvtwd(regs, instr); break; case 0x24: cvtwd(regs, instr); break;
case 0x25: cvtld(regs, instr); break; case 0x25: cvtld(regs, instr); break;
case 0x30: ccond<double>(regs, instr, F); break; case 0x30: //ccond<double>(regs, instr, F); break;
case 0x31: ccond<double>(regs, instr, UN); break; case 0x31: //ccond<double>(regs, instr, UN); break;
case 0x32: ccond<double>(regs, instr, EQ); break; case 0x32: //ccond<double>(regs, instr, EQ); break;
case 0x33: ccond<double>(regs, instr, UEQ); break; case 0x33: //ccond<double>(regs, instr, UEQ); break;
case 0x34: ccond<double>(regs, instr, OLT); break; case 0x34: //ccond<double>(regs, instr, OLT); break;
case 0x35: ccond<double>(regs, instr, ULT); break; case 0x35: //ccond<double>(regs, instr, ULT); break;
case 0x36: ccond<double>(regs, instr, OLE); break; case 0x36: //ccond<double>(regs, instr, OLE); break;
case 0x37: ccond<double>(regs, instr, ULE); break; case 0x37: //ccond<double>(regs, instr, ULE); break;
case 0x38: ccond<double>(regs, instr, SF); break; case 0x38: //ccond<double>(regs, instr, SF); break;
case 0x39: ccond<double>(regs, instr, NGLE); break; case 0x39: //ccond<double>(regs, instr, NGLE); break;
case 0x3A: ccond<double>(regs, instr, SEQ); break; case 0x3A: //ccond<double>(regs, instr, SEQ); break;
case 0x3B: ccond<double>(regs, instr, NGL); break; case 0x3B: //ccond<double>(regs, instr, NGL); break;
case 0x3C: ccond<double>(regs, instr, LT); break; case 0x3C: //ccond<double>(regs, instr, LT); break;
case 0x3D: ccond<double>(regs, instr, NGE); break; case 0x3D: //ccond<double>(regs, instr, NGE); break;
case 0x3E: ccond<double>(regs, instr, LE); break; case 0x3E: //ccond<double>(regs, instr, LE); break;
case 0x3F: ccond<double>(regs, instr, NGT); break; case 0x3F: //ccond<double>(regs, instr, NGT); break;
default: Util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC); default: Util::panic("Unimplemented COP1 function D[{} {}] ({:08X}) ({:016X})", mask_fun >> 3, mask_fun & 7, instr, (u64)regs.oldPC);
} }
break; break;

View File

@@ -236,7 +236,37 @@ private:
void cvtdl(Registers&, u32 instr); void cvtdl(Registers&, u32 instr);
void cvtsl(Registers&, u32 instr); void cvtsl(Registers&, u32 instr);
template <typename T> template <typename T>
void ccond(Registers&, u32 instr, CompConds); void cf(Registers&, u32 instr);
template <typename T>
void cun(Registers&, u32 instr);
template <typename T>
void ceq(Registers&, u32 instr);
template <typename T>
void cueq(Registers&, u32 instr);
template <typename T>
void colt(Registers&, u32 instr);
template <typename T>
void cult(Registers&, u32 instr);
template <typename T>
void cole(Registers&, u32 instr);
template <typename T>
void cule(Registers&, u32 instr);
template <typename T>
void csf(Registers&, u32 instr);
template <typename T>
void cngle(Registers&, u32 instr);
template <typename T>
void cseq(Registers&, u32 instr);
template <typename T>
void cngl(Registers&, u32 instr);
template <typename T>
void clt(Registers&, u32 instr);
template <typename T>
void cnge(Registers&, u32 instr);
template <typename T>
void cle(Registers&, u32 instr);
template <typename T>
void cngt(Registers&, u32 instr);
void divs(Registers&, u32 instr); void divs(Registers&, u32 instr);
void divd(Registers&, u32 instr); void divd(Registers&, u32 instr);
void muls(Registers&, u32 instr); void muls(Registers&, u32 instr);

View File

@@ -89,16 +89,7 @@ void Cop1::SetCauseInvalid(Registers& regs) {
} while(0) } while(0)
template <typename T> template <typename T>
FORCE_INLINE void SetCauseByArgCVT(Registers& regs, T f) { FORCE_INLINE void SetCauseByArgWCVT(Registers& regs, T f) {
T min, max;
if constexpr(std::is_same_v<T, float>) {
min = -2147483648.0f;
max = 2147483648.0f;
} else if constexpr(std::is_same_v<T, double>) {
min = -9007199254740992.000000;
max = 9007199254740992.000000;
}
switch (std::fpclassify(f)) { switch (std::fpclassify(f)) {
case FP_NAN: case FP_NAN:
case FP_INFINITE: case FP_INFINITE:
@@ -108,7 +99,7 @@ FORCE_INLINE void SetCauseByArgCVT(Registers& regs, T f) {
case FP_NORMAL: case FP_NORMAL:
// Check overflow // Check overflow
if (f >= max || f <= min) { if (f >= 2147483648.0f || f < -2147483648.0f) {
regs.cop1.SetCauseUnimplemented(regs); regs.cop1.SetCauseUnimplemented(regs);
} }
break; break;
@@ -118,7 +109,29 @@ FORCE_INLINE void SetCauseByArgCVT(Registers& regs, T f) {
} }
} }
#define CheckCVTArg(f) do { SetCauseByArgCVT(regs, f); CheckFPUException(); } while(0) template <typename T>
FORCE_INLINE void SetCauseByArgLCVT(Registers& regs, T f) {
switch (std::fpclassify(f)) {
case FP_NAN:
case FP_INFINITE:
case FP_SUBNORMAL:
regs.cop1.SetCauseUnimplemented(regs);
break;
case FP_NORMAL:
// Check overflow
if (f >= 9007199254740992.000000 || f <= -9007199254740992.000000) {
regs.cop1.SetCauseUnimplemented(regs);
}
break;
case FP_ZERO:
break; // Fine
}
}
#define CheckWCVTArg(f) do { SetCauseByArgWCVT(regs, f); CheckFPUException(); } while(0)
#define CheckLCVTArg(f) do { SetCauseByArgLCVT(regs, f); CheckFPUException(); } while(0)
FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) { FORCE_INLINE void SetFPUCauseRaised(Registers& regs, int raised) {
if (raised == 0) { if (raised == 0) {
@@ -265,7 +278,7 @@ FORCE_INLINE void SetCauseOnResult(Registers& regs, T& d) {
#define CheckRound(a, b) do { if ((a) != (b)) { SetCauseInexact(regs); } CheckFPUException(); } while(0) #define CheckRound(a, b) do { if ((a) != (b)) { SetCauseInexact(regs); } CheckFPUException(); } while(0)
template <typename T> template <typename T>
FORCE_INLINE bool isnan(T f) { FORCE_INLINE bool is_nan(T f) {
if constexpr(std::is_same_v<T, float>) { if constexpr(std::is_same_v<T, float>) {
u32 v = F_TO_U32(f); u32 v = F_TO_U32(f);
return ((v & 0x7F800000) == 0x7F800000) && ((v & 0x7FFFFF) != 0); return ((v & 0x7F800000) == 0x7F800000) && ((v & 0x7FFFFF) != 0);
@@ -273,12 +286,12 @@ FORCE_INLINE bool isnan(T f) {
u64 v = D_TO_U64(f); u64 v = D_TO_U64(f);
return ((v & 0x7FF0000000000000) == 0x7FF0000000000000) && ((v & 0xFFFFFFFFFFFFF) != 0); return ((v & 0x7FF0000000000000) == 0x7FF0000000000000) && ((v & 0xFFFFFFFFFFFFF) != 0);
} else { } else {
Util::panic("Invalid float type in isnan"); Util::panic("Invalid float type in is_nan");
} }
} }
#define checknanregs(fs, ft) do { \ #define checknanregs(fs, ft) do { \
if(isnan(fs) || isnan(ft)) { \ if(is_nan(fs) || is_nan(ft)) { \
regs.cop1.SetCauseInvalid(regs); \ regs.cop1.SetCauseInvalid(regs); \
CheckFPUException(); \ CheckFPUException(); \
} \ } \
@@ -310,7 +323,7 @@ void Cop1::addd(Registers& regs, u32 instr) {
void Cop1::ceills(Registers& regs, u32 instr) { void Cop1::ceills(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); }); CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -320,7 +333,7 @@ void Cop1::ceills(Registers& regs, u32 instr) {
void Cop1::ceilws(Registers& regs, u32 instr) { void Cop1::ceilws(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); }); CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -330,7 +343,7 @@ void Cop1::ceilws(Registers& regs, u32 instr) {
void Cop1::ceilld(Registers& regs, u32 instr) { void Cop1::ceilld(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); }); CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -340,7 +353,7 @@ void Cop1::ceilld(Registers& regs, u32 instr) {
void Cop1::ceilwd(Registers& regs, u32 instr) { void Cop1::ceilwd(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); }); CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -420,7 +433,7 @@ void Cop1::cvtsl(Registers& regs, u32 instr) {
void Cop1::cvtwd(Registers& regs, u32 instr) { void Cop1::cvtwd(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
PUSHROUNDING; PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); }); CVT_OP_CheckExcept({ result = std::rint(fs); });
@@ -432,7 +445,7 @@ void Cop1::cvtwd(Registers& regs, u32 instr) {
void Cop1::cvtws(Registers& regs, u32 instr) { void Cop1::cvtws(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
PUSHROUNDING; PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); }); CVT_OP_CheckExcept({ result = std::rint(fs); });
@@ -444,7 +457,7 @@ void Cop1::cvtws(Registers& regs, u32 instr) {
void Cop1::cvtls(Registers& regs, u32 instr) { void Cop1::cvtls(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
PUSHROUNDING; PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); }); CVT_OP_CheckExcept({ result = std::rint(fs); });
@@ -479,7 +492,7 @@ void Cop1::cvtdl(Registers& regs, u32 instr) {
void Cop1::cvtld(Registers& regs, u32 instr) { void Cop1::cvtld(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
PUSHROUNDING; PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); }); CVT_OP_CheckExcept({ result = std::rint(fs); });
@@ -489,38 +502,181 @@ void Cop1::cvtld(Registers& regs, u32 instr) {
} }
template <typename T> template <typename T>
inline bool CalculateCondition(T fs, T ft, CompConds cond) { void Cop1::cf(Registers& regs, u32 instr) {
switch(cond) {
case F: case SF: return false;
case UN: case NGLE: return any_unordered(fs, ft);
case EQ: case SEQ: return fs == ft;
case UEQ: case NGL: return fs == ft || any_unordered(fs, ft);
case OLT: case LT: return fs < ft;
case ULT: case NGE: return fs < ft || any_unordered(fs, ft);
case OLE: case LE: return fs <= ft;
case ULE: case NGT: return fs <= ft || any_unordered(fs, ft);
}
}
template <typename T>
inline void CheckInvalidRegs(Registers& regs, T fs, T ft, CompConds cond) {
switch(cond) {
case F ... ULE: checkqnanregs(fs, ft); break;
case SF ... NGT: checknanregs(fs, ft); break;
}
}
template <typename T>
void Cop1::ccond(Registers& regs, u32 instr, CompConds cond) {
CheckFPUUsable(); CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr)); T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr)); T ft = GetFGR_FT<T>(FT(instr));
CheckInvalidRegs(regs, fs, ft, cond); checkqnanregs(fs, ft);
fcr31.compare = CalculateCondition(fs, ft, cond); fcr31.compare = false;
} }
template void Cop1::ccond<float>(Registers& regs, u32 instr, CompConds cond); template <typename T>
template void Cop1::ccond<double>(Registers& regs, u32 instr, CompConds cond); void Cop1::cun(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = any_unordered(fs, ft);
}
template <typename T>
void Cop1::ceq(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs == ft;
}
template <typename T>
void Cop1::cueq(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs == ft || any_unordered(fs, ft);
}
template <typename T>
void Cop1::colt(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs < ft;
}
template <typename T>
void Cop1::cult(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs < ft || any_unordered(fs, ft);
}
template <typename T>
void Cop1::cole(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs <= ft;
}
template <typename T>
void Cop1::cule(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs <= ft || any_unordered(fs, ft);
}
template <typename T>
void Cop1::csf(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = false;
}
template <typename T>
void Cop1::cngle(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = any_unordered(fs, ft);
}
template <typename T>
void Cop1::cseq(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs == ft;
}
template <typename T>
void Cop1::cngl(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs == ft || any_unordered(fs, ft);
}
template <typename T>
void Cop1::clt(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs < ft;
}
template <typename T>
void Cop1::cnge(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs < ft || any_unordered(fs, ft);
}
template <typename T>
void Cop1::cle(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs <= ft;
}
template <typename T>
void Cop1::cngt(Registers& regs, u32 instr) {
CheckFPUUsable();
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
T ft = GetFGR_FT<T>(FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs <= ft || any_unordered(fs, ft);
}
template void Cop1::cf<float>(Registers&, u32 instr);
template void Cop1::cun<float>(Registers&, u32 instr);
template void Cop1::ceq<float>(Registers&, u32 instr);
template void Cop1::cueq<float>(Registers&, u32 instr);
template void Cop1::colt<float>(Registers&, u32 instr);
template void Cop1::cult<float>(Registers&, u32 instr);
template void Cop1::cole<float>(Registers&, u32 instr);
template void Cop1::cule<float>(Registers&, u32 instr);
template void Cop1::csf<float>(Registers&, u32 instr);
template void Cop1::cngle<float>(Registers&, u32 instr);
template void Cop1::cseq<float>(Registers&, u32 instr);
template void Cop1::cngl<float>(Registers&, u32 instr);
template void Cop1::clt<float>(Registers&, u32 instr);
template void Cop1::cnge<float>(Registers&, u32 instr);
template void Cop1::cle<float>(Registers&, u32 instr);
template void Cop1::cngt<float>(Registers&, u32 instr);
template void Cop1::cf<double>(Registers&, u32 instr);
template void Cop1::cun<double>(Registers&, u32 instr);
template void Cop1::ceq<double>(Registers&, u32 instr);
template void Cop1::cueq<double>(Registers&, u32 instr);
template void Cop1::colt<double>(Registers&, u32 instr);
template void Cop1::cult<double>(Registers&, u32 instr);
template void Cop1::cole<double>(Registers&, u32 instr);
template void Cop1::cule<double>(Registers&, u32 instr);
template void Cop1::csf<double>(Registers&, u32 instr);
template void Cop1::cngle<double>(Registers&, u32 instr);
template void Cop1::cseq<double>(Registers&, u32 instr);
template void Cop1::cngl<double>(Registers&, u32 instr);
template void Cop1::clt<double>(Registers&, u32 instr);
template void Cop1::cnge<double>(Registers&, u32 instr);
template void Cop1::cle<double>(Registers&, u32 instr);
template void Cop1::cngt<double>(Registers&, u32 instr);
void Cop1::divs(Registers &regs, u32 instr) { void Cop1::divs(Registers &regs, u32 instr) {
OP(float, fs / ft); OP(float, fs / ft);
@@ -577,7 +733,7 @@ void Cop1::sqrtd(Registers &regs, u32 instr) {
void Cop1::roundls(Registers& regs, u32 instr) { void Cop1::roundls(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -587,7 +743,7 @@ void Cop1::roundls(Registers& regs, u32 instr) {
void Cop1::roundld(Registers& regs, u32 instr) { void Cop1::roundld(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -597,7 +753,7 @@ void Cop1::roundld(Registers& regs, u32 instr) {
void Cop1::roundws(Registers& regs, u32 instr) { void Cop1::roundws(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -607,7 +763,7 @@ void Cop1::roundws(Registers& regs, u32 instr) {
void Cop1::roundwd(Registers& regs, u32 instr) { void Cop1::roundwd(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); }); CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -617,7 +773,7 @@ void Cop1::roundwd(Registers& regs, u32 instr) {
void Cop1::floorls(Registers& regs, u32 instr) { void Cop1::floorls(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::floor(fs); }); CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -627,7 +783,7 @@ void Cop1::floorls(Registers& regs, u32 instr) {
void Cop1::floorld(Registers& regs, u32 instr) { void Cop1::floorld(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::floor(fs); }); CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -637,7 +793,7 @@ void Cop1::floorld(Registers& regs, u32 instr) {
void Cop1::floorws(Registers& regs, u32 instr) { void Cop1::floorws(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::floor(fs); }); CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -647,7 +803,7 @@ void Cop1::floorws(Registers& regs, u32 instr) {
void Cop1::floorwd(Registers& regs, u32 instr) { void Cop1::floorwd(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::floor(fs); }); CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -657,7 +813,7 @@ void Cop1::floorwd(Registers& regs, u32 instr) {
void Cop1::truncws(Registers& regs, u32 instr) { void Cop1::truncws(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); }); CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -667,7 +823,7 @@ void Cop1::truncws(Registers& regs, u32 instr) {
void Cop1::truncwd(Registers& regs, u32 instr) { void Cop1::truncwd(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckWCVTArg(fs);
s32 result; s32 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); }); CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -677,7 +833,7 @@ void Cop1::truncwd(Registers& regs, u32 instr) {
void Cop1::truncls(Registers& regs, u32 instr) { void Cop1::truncls(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); }); CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result); CheckRound(fs, result);
@@ -687,7 +843,7 @@ void Cop1::truncls(Registers& regs, u32 instr) {
void Cop1::truncld(Registers& regs, u32 instr) { void Cop1::truncld(Registers& regs, u32 instr) {
CheckFPUUsable(); CheckFPUUsable();
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr)); auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
CheckCVTArg(fs); CheckLCVTArg(fs);
s64 result; s64 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); }); CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result); CheckRound(fs, result);