accurat-er

This commit is contained in:
SimoneN64
2024-06-19 21:58:11 +02:00
parent 78551827c9
commit 1f1931d6ad
2 changed files with 174 additions and 122 deletions

View File

@@ -120,7 +120,11 @@ struct Cop1 {
void SetCauseInvalid();
private:
template <typename T>
auto FGR(Cop0Status&, u32) -> T&;
auto FGR_T(Cop0Status&, u32) -> T&;
template <typename T>
auto FGR_S(Cop0Status&, u32) -> T&;
template <typename T>
auto FGR_D(Cop0Status&, u32) -> T&;
void decodeInterp(Interpreter&, u32);
void decodeJIT(JIT&, u32);
void absd(u32 instr);

View File

@@ -6,35 +6,25 @@
#include <cfenv>
namespace n64 {
template<> auto Cop1::FGR<s32>(Cop0Status& status, u32 index) -> s32& {
template<> auto Cop1::FGR_T<s32>(Cop0Status& status, u32 index) -> s32& {
if (status.fr) {
return fgr[index].int32;
} else {
if (index & 1) {
} else if (index & 1) {
return fgr[index & ~1].int32h;
} else {
return fgr[index].int32;
}
return fgr[index & ~1].int32;
}
}
template<> auto Cop1::FGR<u32>(Cop0Status& status, u32 index) -> u32& {
return (u32&)FGR<s32>(status, index);
template<> auto Cop1::FGR_T<u32>(Cop0Status& status, u32 index) -> u32& {
return (u32&)FGR_T<s32>(status, index);
}
template<> auto Cop1::FGR<float>(Cop0Status& status, u32 index) -> float& {
if (status.fr) {
template<> auto Cop1::FGR_T<float>(Cop0Status& status, u32 index) -> float& {
return fgr[index].float32;
} else {
if (index & 1) {
return fgr[index & ~1].float32h;
} else {
return fgr[index].float32;
}
}
}
template<> auto Cop1::FGR<s64>(Cop0Status& status, u32 index) -> s64& {
template<> auto Cop1::FGR_T<s64>(Cop0Status& status, u32 index) -> s64& {
if (status.fr) {
return fgr[index].int64;
} else {
@@ -42,11 +32,43 @@ template<> auto Cop1::FGR<s64>(Cop0Status& status, u32 index) -> s64& {
}
}
template<> auto Cop1::FGR<u64>(Cop0Status& status, u32 index) -> u64& {
return (u64&)FGR<s64>(status, index);
template<> auto Cop1::FGR_T<u64>(Cop0Status& status, u32 index) -> u64& {
return (u64&)FGR_T<s64>(status, index);
}
template<> auto Cop1::FGR<double>(Cop0Status& status, u32 index) -> double& {
template<> auto Cop1::FGR_T<double>(Cop0Status& status, u32 index) -> double& {
return fgr[index].float64;
}
template<> auto Cop1::FGR_S<s32>(Cop0Status& status, u32 index) -> s32& {
if (status.fr) {
return fgr[index].int32;
} else {
return fgr[index & ~1].int32;
}
}
template<> auto Cop1::FGR_S<u32>(Cop0Status& status, u32 index) -> u32& {
return (u32&)FGR_S<s32>(status, index);
}
template<> auto Cop1::FGR_S<float>(Cop0Status& status, u32 index) -> float& {
if (status.fr) {
return fgr[index].float32;
} else {
return fgr[index & ~1].float32;
}
}
template<> auto Cop1::FGR_S<s64>(Cop0Status& status, u32 index) -> s64& {
return FGR_T<s64>(status, index);
}
template<> auto Cop1::FGR_S<u64>(Cop0Status& status, u32 index) -> u64& {
return (u64&)FGR_S<s64>(status, index);
}
template<> auto Cop1::FGR_S<double>(Cop0Status& status, u32 index) -> double& {
if (status.fr) {
return fgr[index].float64;
} else {
@@ -54,6 +76,32 @@ template<> auto Cop1::FGR<double>(Cop0Status& status, u32 index) -> double& {
}
}
template<> auto Cop1::FGR_D<s32>(Cop0Status& status, u32 index) -> s32& {
fgr[index].int32h = 0;
return fgr[index].int32;
}
template<> auto Cop1::FGR_D<u32>(Cop0Status& status, u32 index) -> u32& {
return (u32&)FGR_D<s32>(status, index);
}
template<> auto Cop1::FGR_D<float>(Cop0Status& status, u32 index) -> float& {
fgr[index].float32h = 0;
return fgr[index].float32;
}
template<> auto Cop1::FGR_D<s64>(Cop0Status& status, u32 index) -> s64& {
return fgr[index].int64;
}
template<> auto Cop1::FGR_D<u64>(Cop0Status& status, u32 index) -> u64& {
return (u64&)FGR_D<s64>(status, index);
}
template<> auto Cop1::FGR_D<double>(Cop0Status& status, u32 index) -> double& {
return FGR_T<double>(status, index);
}
bool Cop1::FireException() {
u32 enable = fcr31.enable | (1 << 5);
if(fcr31.cause & enable) {
@@ -124,14 +172,14 @@ void Cop1::SetCauseInvalid() {
#define OP(T, op) do { \
CheckFPUUsable(); \
auto fs = FGR<T>(regs.cop0.status, FS(instr)); \
auto ft = FGR<T>(regs.cop0.status, FT(instr)); \
auto fs = FGR_S<T>(regs.cop0.status, FS(instr)); \
auto ft = FGR_T<T>(regs.cop0.status, FT(instr)); \
CheckArg(fs); \
CheckArg(ft); \
T result; \
OP_CheckExcept({result = (op);}); \
CheckResult(result); \
FGR<T>(regs.cop0.status, FD(instr)) = result; \
FGR_D<T>(regs.cop0.status, FD(instr)) = result; \
} while(0)
template <typename T>
@@ -375,42 +423,42 @@ void Cop1::addd(u32 instr) {
void Cop1::ceills(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::ceilws(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::ceilld(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::ceilwd(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::ceil(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cfc1(u32 instr) const {
@@ -452,36 +500,36 @@ void Cop1::ctc1(u32 instr) {
void Cop1::cvtds(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckArg(fs);
double result;
OP_CheckExcept({ result = double(fs); });
CheckResult(result);
FGR<double>(regs.cop0.status, FD(instr)) = result;
FGR_D<double>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtsd(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckArg(fs);
float result;
OP_CheckExcept({ result = float(fs); });
CheckResult(result);
FGR<float>(regs.cop0.status, FD(instr)) = result;
FGR_D<float>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtsw(u32 instr) {
CheckFPUUsable();
auto fs = FGR<s32>(regs.cop0.status, FS(instr));
auto fs = FGR_S<s32>(regs.cop0.status, FS(instr));
float result;
OP_CheckExcept({ result = float(fs); });
CheckResult(result);
FGR<float>(regs.cop0.status, FD(instr)) = result;
FGR_D<float>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtsl(u32 instr) {
CheckFPUUsable();
auto fs = FGR<s64>(regs.cop0.status, FS(instr));
auto fs = FGR_S<s64>(regs.cop0.status, FS(instr));
if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) {
SetCauseUnimplemented();
CheckFPUException();
@@ -489,57 +537,57 @@ void Cop1::cvtsl(u32 instr) {
float result;
OP_CheckExcept({ result = float(fs); });
CheckResult(result);
FGR<float>(regs.cop0.status, FD(instr)) = result;
FGR_D<float>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtwd(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); });
POPROUNDING;
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtws(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); });
POPROUNDING;
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtls(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); });
POPROUNDING;
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtdw(u32 instr) {
CheckFPUUsable();
auto fs = FGR<s32>(regs.cop0.status, FS(instr));
auto fs = FGR_S<s32>(regs.cop0.status, FS(instr));
double result;
OP_CheckExcept({ result = double(fs); });
CheckResult(result);
FGR<double>(regs.cop0.status, FD(instr)) = result;
FGR_D<double>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtdl(u32 instr) {
CheckFPUUsable();
auto fs = FGR<s64>(regs.cop0.status, FS(instr));
auto fs = FGR_S<s64>(regs.cop0.status, FS(instr));
if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) {
SetCauseUnimplemented();
@@ -548,26 +596,26 @@ void Cop1::cvtdl(u32 instr) {
double result;
OP_CheckExcept({ result = double(fs); });
CheckResult(result);
FGR<double>(regs.cop0.status, FD(instr)) = result;
FGR_D<double>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::cvtld(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
PUSHROUNDING;
CVT_OP_CheckExcept({ result = std::rint(fs); });
POPROUNDING;
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
template <typename T>
void Cop1::cf(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = false;
}
@@ -575,8 +623,8 @@ void Cop1::cf(u32 instr) {
template <typename T>
void Cop1::cun(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = any_unordered(fs, ft);
}
@@ -584,8 +632,8 @@ void Cop1::cun(u32 instr) {
template <typename T>
void Cop1::ceq(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs == ft;
}
@@ -593,8 +641,8 @@ void Cop1::ceq(u32 instr) {
template <typename T>
void Cop1::cueq(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs == ft || any_unordered(fs, ft);
}
@@ -602,8 +650,8 @@ void Cop1::cueq(u32 instr) {
template <typename T>
void Cop1::colt(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs < ft;
}
@@ -611,8 +659,8 @@ void Cop1::colt(u32 instr) {
template <typename T>
void Cop1::cult(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs < ft || any_unordered(fs, ft);
}
@@ -620,8 +668,8 @@ void Cop1::cult(u32 instr) {
template <typename T>
void Cop1::cole(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs <= ft;
}
@@ -629,8 +677,8 @@ void Cop1::cole(u32 instr) {
template <typename T>
void Cop1::cule(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checkqnanregs(fs, ft);
fcr31.compare = fs <= ft || any_unordered(fs, ft);
}
@@ -638,8 +686,8 @@ void Cop1::cule(u32 instr) {
template <typename T>
void Cop1::csf(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = false;
}
@@ -647,8 +695,8 @@ void Cop1::csf(u32 instr) {
template <typename T>
void Cop1::cngle(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = any_unordered(fs, ft);
}
@@ -656,8 +704,8 @@ void Cop1::cngle(u32 instr) {
template <typename T>
void Cop1::cseq(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs == ft;
}
@@ -665,8 +713,8 @@ void Cop1::cseq(u32 instr) {
template <typename T>
void Cop1::cngl(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs == ft || any_unordered(fs, ft);
}
@@ -674,8 +722,8 @@ void Cop1::cngl(u32 instr) {
template <typename T>
void Cop1::clt(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs < ft;
}
@@ -683,8 +731,8 @@ void Cop1::clt(u32 instr) {
template <typename T>
void Cop1::cnge(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs < ft || any_unordered(fs, ft);
}
@@ -692,8 +740,8 @@ void Cop1::cnge(u32 instr) {
template <typename T>
void Cop1::cle(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs <= ft;
}
@@ -701,8 +749,8 @@ void Cop1::cle(u32 instr) {
template <typename T>
void Cop1::cngt(u32 instr) {
CheckFPUUsable();
T fs = FGR<T>(regs.cop0.status, FS(instr));
T ft = FGR<T>(regs.cop0.status, FT(instr));
T fs = FGR_S<T>(regs.cop0.status, FS(instr));
T ft = FGR_T<T>(regs.cop0.status, FT(instr));
checknanregs(fs, ft);
fcr31.compare = fs <= ft || any_unordered(fs, ft);
}
@@ -766,14 +814,14 @@ void Cop1::subd(u32 instr) {
void Cop1::movs(u32 instr) {
CheckFPUUsable_PreserveCause();
auto val = FGR<u64>(regs.cop0.status, FS(instr));
FGR<u64>(regs.cop0.status, FD(instr)) = val;
auto val = FGR_S<u64>(regs.cop0.status, FS(instr));
FGR_D<u64>(regs.cop0.status, FD(instr)) = val;
}
void Cop1::movd(u32 instr) {
CheckFPUUsable_PreserveCause();
auto val = FGR<double>(regs.cop0.status, FS(instr));
FGR<double>(regs.cop0.status, FD(instr)) = val;
auto val = FGR_S<double>(regs.cop0.status, FS(instr));
FGR_D<double>(regs.cop0.status, FD(instr)) = val;
}
void Cop1::negs(u32 instr) {
@@ -794,122 +842,122 @@ void Cop1::sqrtd(u32 instr) {
void Cop1::roundls(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::roundld(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::roundws(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::roundwd(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::nearbyint(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::floorls(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::floorld(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::floorws(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::floorwd(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::floor(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::truncws(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::truncwd(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckWCVTArg(fs);
s32 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result);
FGR<s32>(regs.cop0.status, FD(instr)) = result;
FGR_D<s32>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::truncls(u32 instr) {
CheckFPUUsable();
auto fs = FGR<float>(regs.cop0.status, FS(instr));
auto fs = FGR_S<float>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
void Cop1::truncld(u32 instr) {
CheckFPUUsable();
auto fs = FGR<double>(regs.cop0.status, FS(instr));
auto fs = FGR_S<double>(regs.cop0.status, FS(instr));
CheckLCVTArg(fs);
s64 result;
CVT_OP_CheckExcept({ result = std::trunc(fs); });
CheckRound(fs, result);
FGR<s64>(regs.cop0.status, FD(instr)) = result;
FGR_D<s64>(regs.cop0.status, FD(instr)) = result;
}
template<class T>
@@ -981,7 +1029,7 @@ void Cop1::lwc1Interp(Mem& mem, u32 instr) {
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
u32 data = mem.Read<u32>(regs, physical);
FGR<u32>(regs.cop0.status, FT(instr)) = data;
FGR_T<u32>(regs.cop0.status, FT(instr)) = data;
}
}
@@ -993,7 +1041,7 @@ void Cop1::swc1Interp(Mem& mem, u32 instr) {
regs.cop0.HandleTLBException(addr);
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write<u32>(regs, physical, FGR<u32>(regs.cop0.status, FT(instr)));
mem.Write<u32>(regs, physical, FGR_T<u32>(regs.cop0.status, FT(instr)));
}
}
@@ -1012,7 +1060,7 @@ void Cop1::ldc1Interp(Mem& mem, u32 instr) {
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else {
u64 data = mem.Read<u64>(regs, physical);
FGR<u64>(regs.cop0.status, FT(instr)) = data;
FGR_T<u64>(regs.cop0.status, FT(instr)) = data;
}
}
@@ -1024,28 +1072,28 @@ void Cop1::sdc1Interp(Mem& mem, u32 instr) {
regs.cop0.HandleTLBException(addr);
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else {
mem.Write(regs, physical, FGR<u64>(regs.cop0.status, FT(instr)));
mem.Write(regs, physical, FGR_T<u64>(regs.cop0.status, FT(instr)));
}
}
void Cop1::mfc1(u32 instr) {
CheckFPUUsable_PreserveCause();
regs.gpr[RT(instr)] = FGR<s32>(regs.cop0.status, FS(instr));
regs.gpr[RT(instr)] = FGR_S<s32>(regs.cop0.status, FS(instr));
}
void Cop1::dmfc1(u32 instr) {
CheckFPUUsable_PreserveCause();
regs.gpr[RT(instr)] = FGR<s64>(regs.cop0.status, FS(instr));
regs.gpr[RT(instr)] = FGR_S<s64>(regs.cop0.status, FS(instr));
}
void Cop1::mtc1(u32 instr) {
CheckFPUUsable_PreserveCause();
FGR<u32>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
FGR_S<u32>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
}
void Cop1::dmtc1(u32 instr) {
CheckFPUUsable_PreserveCause();
FGR<u64>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
FGR_S<u64>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
}
}