|
|
|
@@ -7,6 +7,56 @@
|
|
|
|
#include <cfenv>
|
|
|
|
#include <cfenv>
|
|
|
|
|
|
|
|
|
|
|
|
namespace n64 {
|
|
|
|
namespace n64 {
|
|
|
|
|
|
|
|
template<> auto Cop1::FGR<s32>(Cop0Status& status, u32 index) -> s32& {
|
|
|
|
|
|
|
|
if (status.fr) {
|
|
|
|
|
|
|
|
return fgr[index].int32;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (index & 1) {
|
|
|
|
|
|
|
|
return fgr[index & ~1].int32h;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
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<float>(Cop0Status& status, u32 index) -> float& {
|
|
|
|
|
|
|
|
if (status.fr) {
|
|
|
|
|
|
|
|
return fgr[index].float32;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (index & 1) {
|
|
|
|
|
|
|
|
return fgr[index & ~1].float32h;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
return fgr[index & ~1].float32;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<> auto Cop1::FGR<s64>(Cop0Status& status, u32 index) -> s64& {
|
|
|
|
|
|
|
|
if (status.fr) {
|
|
|
|
|
|
|
|
return fgr[index].int64;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
return fgr[index & ~1].int64;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<> auto Cop1::FGR<u64>(Cop0Status& status, u32 index) -> u64& {
|
|
|
|
|
|
|
|
return (u64&)FGR<s64>(status, index);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<> auto Cop1::FGR<double>(Cop0Status& status, u32 index) -> double& {
|
|
|
|
|
|
|
|
if (status.fr) {
|
|
|
|
|
|
|
|
return fgr[index].float64;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
return fgr[index & ~1].float64;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FORCE_INLINE bool FireFPUException(Registers& regs) {
|
|
|
|
FORCE_INLINE bool FireFPUException(Registers& regs) {
|
|
|
|
FCR31& fcr31 = regs.cop1.fcr31;
|
|
|
|
FCR31& fcr31 = regs.cop1.fcr31;
|
|
|
|
u32 enable = fcr31.enable | (1 << 5);
|
|
|
|
u32 enable = fcr31.enable | (1 << 5);
|
|
|
|
@@ -22,7 +72,7 @@ FORCE_INLINE bool FireFPUException(Registers& regs) {
|
|
|
|
|
|
|
|
|
|
|
|
FORCE_INLINE int PushRoundingMode(const FCR31& fcr31) {
|
|
|
|
FORCE_INLINE int PushRoundingMode(const FCR31& fcr31) {
|
|
|
|
int og = fegetround();
|
|
|
|
int og = fegetround();
|
|
|
|
switch(fcr31.rounding_mode) {
|
|
|
|
switch (fcr31.rounding_mode) {
|
|
|
|
case 0: fesetround(FE_TONEAREST); break;
|
|
|
|
case 0: fesetround(FE_TONEAREST); break;
|
|
|
|
case 1: fesetround(FE_TOWARDZERO); break;
|
|
|
|
case 1: fesetround(FE_TOWARDZERO); break;
|
|
|
|
case 2: fesetround(FE_UPWARD); break;
|
|
|
|
case 2: fesetround(FE_UPWARD); break;
|
|
|
|
@@ -71,21 +121,21 @@ void Cop1::SetCauseInvalid(Registers& regs) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define PUSHROUNDING int orig_round = PushRoundingMode(regs.cop1.fcr31)
|
|
|
|
#define PUSHROUNDING int orig_round = PushRoundingMode(fcr31)
|
|
|
|
#define POPROUNDING fesetround(orig_round)
|
|
|
|
#define POPROUNDING fesetround(orig_round)
|
|
|
|
#define OP_CheckExcept(op) do { PUSHROUNDING; feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0)
|
|
|
|
#define OP_CheckExcept(op) do { PUSHROUNDING; feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseRaised(regs, fetestexcept(FE_ALL_EXCEPT)); POPROUNDING; } while(0)
|
|
|
|
#define CVT_OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseCVTRaised(regs, fetestexcept(FE_ALL_EXCEPT)); CheckFPUException(); } while(0)
|
|
|
|
#define CVT_OP_CheckExcept(op) do { feclearexcept(FE_ALL_EXCEPT); op; SetFPUCauseCVTRaised(regs, fetestexcept(FE_ALL_EXCEPT)); CheckFPUException(); } while(0)
|
|
|
|
|
|
|
|
|
|
|
|
#define OP(T, op) do { \
|
|
|
|
#define OP(T, op) do { \
|
|
|
|
CheckFPUUsable(); \
|
|
|
|
CheckFPUUsable(); \
|
|
|
|
auto fs = GetFGR_FS<T>(regs.cop0, FS(instr)); \
|
|
|
|
auto fs = FGR<T>(regs.cop0.status, FS(instr)); \
|
|
|
|
auto ft = GetFGR_FT<T>(FT(instr)); \
|
|
|
|
auto ft = FGR<T>(regs.cop0.status, FT(instr)); \
|
|
|
|
CheckArg(fs); \
|
|
|
|
CheckArg(fs); \
|
|
|
|
CheckArg(ft); \
|
|
|
|
CheckArg(ft); \
|
|
|
|
T result; \
|
|
|
|
T result; \
|
|
|
|
OP_CheckExcept({result = (op);}); \
|
|
|
|
OP_CheckExcept({result = (op);}); \
|
|
|
|
CheckResult(result); \
|
|
|
|
CheckResult(result); \
|
|
|
|
SetFGR_Raw<T>(FD(instr), result); \
|
|
|
|
FGR<T>(regs.cop0.status, FD(instr)) = result; \
|
|
|
|
} while(0)
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
@@ -322,42 +372,42 @@ 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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cfc1(Registers& regs, u32 instr) const {
|
|
|
|
void Cop1::cfc1(Registers& regs, u32 instr) const {
|
|
|
|
@@ -381,7 +431,16 @@ void Cop1::ctc1(Registers& regs, u32 instr) {
|
|
|
|
switch(fs) {
|
|
|
|
switch(fs) {
|
|
|
|
case 0: break;
|
|
|
|
case 0: break;
|
|
|
|
case 31: {
|
|
|
|
case 31: {
|
|
|
|
|
|
|
|
u32 prevRound = fcr31.rounding_mode;
|
|
|
|
fcr31.write(val);
|
|
|
|
fcr31.write(val);
|
|
|
|
|
|
|
|
if (prevRound != fcr31.rounding_mode) {
|
|
|
|
|
|
|
|
switch (fcr31.rounding_mode) {
|
|
|
|
|
|
|
|
case 0: fesetround(FE_TONEAREST); break;
|
|
|
|
|
|
|
|
case 1: fesetround(FE_TOWARDZERO); break;
|
|
|
|
|
|
|
|
case 2: fesetround(FE_UPWARD); break;
|
|
|
|
|
|
|
|
case 3: fesetround(FE_DOWNWARD); break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
CheckFPUException();
|
|
|
|
CheckFPUException();
|
|
|
|
} break;
|
|
|
|
} break;
|
|
|
|
default: Util::panic("Undefined CTC1 with rd != 0 or 31");
|
|
|
|
default: Util::panic("Undefined CTC1 with rd != 0 or 31");
|
|
|
|
@@ -390,36 +449,36 @@ void Cop1::ctc1(Registers& regs, u32 instr) {
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cvtds(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cvtds(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
auto fs = GetFGR_FS<float>(regs.cop0, FS(instr));
|
|
|
|
auto fs = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckArg(fs);
|
|
|
|
CheckArg(fs);
|
|
|
|
double result;
|
|
|
|
double result;
|
|
|
|
OP_CheckExcept({ result = double(fs); });
|
|
|
|
OP_CheckExcept({ result = double(fs); });
|
|
|
|
CheckResult(result);
|
|
|
|
CheckResult(result);
|
|
|
|
SetFGR_Raw(FD(instr), result);
|
|
|
|
FGR<double>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cvtsd(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cvtsd(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
auto fs = GetFGR_FS<double>(regs.cop0, FS(instr));
|
|
|
|
auto fs = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckArg(fs);
|
|
|
|
CheckArg(fs);
|
|
|
|
float result;
|
|
|
|
float result;
|
|
|
|
OP_CheckExcept({ result = float(fs); });
|
|
|
|
OP_CheckExcept({ result = float(fs); });
|
|
|
|
CheckResult(result);
|
|
|
|
CheckResult(result);
|
|
|
|
SetFGR_Raw(FD(instr), result);
|
|
|
|
FGR<float>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cvtsw(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cvtsw(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
auto fs = GetFGR_FS<s32>(regs.cop0, FS(instr));
|
|
|
|
auto fs = FGR<s32>(regs.cop0.status, FS(instr));
|
|
|
|
float result;
|
|
|
|
float result;
|
|
|
|
OP_CheckExcept({ result = float(fs); });
|
|
|
|
OP_CheckExcept({ result = float(fs); });
|
|
|
|
CheckResult(result);
|
|
|
|
CheckResult(result);
|
|
|
|
SetFGR_Raw(FD(instr), result);
|
|
|
|
FGR<float>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cvtsl(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cvtsl(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
auto fs = GetFGR_FR<s64>(regs.cop0, FS(instr));
|
|
|
|
auto fs = FGR<s64>(regs.cop0.status, FS(instr));
|
|
|
|
if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) {
|
|
|
|
if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) {
|
|
|
|
SetCauseUnimplemented(regs);
|
|
|
|
SetCauseUnimplemented(regs);
|
|
|
|
CheckFPUException();
|
|
|
|
CheckFPUException();
|
|
|
|
@@ -427,57 +486,57 @@ void Cop1::cvtsl(Registers& regs, u32 instr) {
|
|
|
|
float result;
|
|
|
|
float result;
|
|
|
|
OP_CheckExcept({ result = float(fs); });
|
|
|
|
OP_CheckExcept({ result = float(fs); });
|
|
|
|
CheckResult(result);
|
|
|
|
CheckResult(result);
|
|
|
|
SetFGR_Raw(FD(instr), result);
|
|
|
|
FGR<float>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(fs);
|
|
|
|
CheckWCVTArg(fs);
|
|
|
|
s32 result;
|
|
|
|
s32 result;
|
|
|
|
PUSHROUNDING;
|
|
|
|
PUSHROUNDING;
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
POPROUNDING;
|
|
|
|
POPROUNDING;
|
|
|
|
CheckRound(fs, result);
|
|
|
|
CheckRound(fs, result);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(fs);
|
|
|
|
CheckWCVTArg(fs);
|
|
|
|
s32 result;
|
|
|
|
s32 result;
|
|
|
|
PUSHROUNDING;
|
|
|
|
PUSHROUNDING;
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
POPROUNDING;
|
|
|
|
POPROUNDING;
|
|
|
|
CheckRound(fs, result);
|
|
|
|
CheckRound(fs, result);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(fs);
|
|
|
|
CheckLCVTArg(fs);
|
|
|
|
s64 result;
|
|
|
|
s64 result;
|
|
|
|
PUSHROUNDING;
|
|
|
|
PUSHROUNDING;
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
POPROUNDING;
|
|
|
|
POPROUNDING;
|
|
|
|
CheckRound(fs, result);
|
|
|
|
CheckRound(fs, result);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cvtdw(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cvtdw(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
auto fs = GetFGR_FS<s32>(regs.cop0, FS(instr));
|
|
|
|
auto fs = FGR<s32>(regs.cop0.status, FS(instr));
|
|
|
|
double result;
|
|
|
|
double result;
|
|
|
|
OP_CheckExcept({ result = double(fs); });
|
|
|
|
OP_CheckExcept({ result = double(fs); });
|
|
|
|
CheckResult(result);
|
|
|
|
CheckResult(result);
|
|
|
|
SetFGR_Raw(FD(instr), result);
|
|
|
|
FGR<double>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::cvtdl(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cvtdl(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
auto fs = GetFGR_FR<s64>(regs.cop0, FS(instr));
|
|
|
|
auto fs = FGR<s64>(regs.cop0.status, FS(instr));
|
|
|
|
|
|
|
|
|
|
|
|
if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) {
|
|
|
|
if (fs >= s64(0x0080000000000000) || fs < s64(0xff80000000000000)) {
|
|
|
|
SetCauseUnimplemented(regs);
|
|
|
|
SetCauseUnimplemented(regs);
|
|
|
|
@@ -486,26 +545,26 @@ void Cop1::cvtdl(Registers& regs, u32 instr) {
|
|
|
|
double result;
|
|
|
|
double result;
|
|
|
|
OP_CheckExcept({ result = double(fs); });
|
|
|
|
OP_CheckExcept({ result = double(fs); });
|
|
|
|
CheckResult(result);
|
|
|
|
CheckResult(result);
|
|
|
|
SetFGR_Raw(FD(instr), result);
|
|
|
|
FGR<double>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(fs);
|
|
|
|
CheckLCVTArg(fs);
|
|
|
|
s64 result;
|
|
|
|
s64 result;
|
|
|
|
PUSHROUNDING;
|
|
|
|
PUSHROUNDING;
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
CVT_OP_CheckExcept({ result = std::rint(fs); });
|
|
|
|
POPROUNDING;
|
|
|
|
POPROUNDING;
|
|
|
|
CheckRound(fs, result);
|
|
|
|
CheckRound(fs, result);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cf(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cf(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = false;
|
|
|
|
fcr31.compare = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -513,8 +572,8 @@ void Cop1::cf(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cun(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cun(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = any_unordered(fs, ft);
|
|
|
|
fcr31.compare = any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -522,8 +581,8 @@ void Cop1::cun(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::ceq(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::ceq(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = fs == ft;
|
|
|
|
fcr31.compare = fs == ft;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -531,8 +590,8 @@ void Cop1::ceq(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cueq(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cueq(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = fs == ft || any_unordered(fs, ft);
|
|
|
|
fcr31.compare = fs == ft || any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -540,8 +599,8 @@ void Cop1::cueq(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::colt(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::colt(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = fs < ft;
|
|
|
|
fcr31.compare = fs < ft;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -549,8 +608,8 @@ void Cop1::colt(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cult(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cult(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = fs < ft || any_unordered(fs, ft);
|
|
|
|
fcr31.compare = fs < ft || any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -558,8 +617,8 @@ void Cop1::cult(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cole(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cole(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = fs <= ft;
|
|
|
|
fcr31.compare = fs <= ft;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -567,8 +626,8 @@ void Cop1::cole(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cule(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cule(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
checkqnanregs(fs, ft);
|
|
|
|
fcr31.compare = fs <= ft || any_unordered(fs, ft);
|
|
|
|
fcr31.compare = fs <= ft || any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -576,8 +635,8 @@ void Cop1::cule(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::csf(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::csf(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = false;
|
|
|
|
fcr31.compare = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -585,8 +644,8 @@ void Cop1::csf(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cngle(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cngle(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = any_unordered(fs, ft);
|
|
|
|
fcr31.compare = any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -594,8 +653,8 @@ void Cop1::cngle(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cseq(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cseq(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = fs == ft;
|
|
|
|
fcr31.compare = fs == ft;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -603,8 +662,8 @@ void Cop1::cseq(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cngl(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cngl(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = fs == ft || any_unordered(fs, ft);
|
|
|
|
fcr31.compare = fs == ft || any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -612,8 +671,8 @@ void Cop1::cngl(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::clt(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::clt(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = fs < ft;
|
|
|
|
fcr31.compare = fs < ft;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -621,8 +680,8 @@ void Cop1::clt(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cnge(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cnge(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = fs < ft || any_unordered(fs, ft);
|
|
|
|
fcr31.compare = fs < ft || any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -630,8 +689,8 @@ void Cop1::cnge(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cle(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cle(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = fs <= ft;
|
|
|
|
fcr31.compare = fs <= ft;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -639,8 +698,8 @@ void Cop1::cle(Registers& regs, u32 instr) {
|
|
|
|
template <typename T>
|
|
|
|
template <typename T>
|
|
|
|
void Cop1::cngt(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::cngt(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable();
|
|
|
|
CheckFPUUsable();
|
|
|
|
T fs = GetFGR_FS<T>(regs.cop0, FS(instr));
|
|
|
|
T fs = FGR<T>(regs.cop0.status, FS(instr));
|
|
|
|
T ft = GetFGR_FT<T>(FT(instr));
|
|
|
|
T ft = FGR<T>(regs.cop0.status, FT(instr));
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
checknanregs(fs, ft);
|
|
|
|
fcr31.compare = fs <= ft || any_unordered(fs, ft);
|
|
|
|
fcr31.compare = fs <= ft || any_unordered(fs, ft);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -704,14 +763,14 @@ void Cop1::subd(Registers ®s, u32 instr) {
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::movs(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::movs(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
auto val = GetFGR_FR<u64>(regs.cop0, FS(instr));
|
|
|
|
auto val = FGR<u64>(regs.cop0.status, FS(instr));
|
|
|
|
SetFGR(FD(instr), val);
|
|
|
|
FGR<u64>(regs.cop0.status, FD(instr)) = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::movd(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::movd(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
auto val = GetFGR_FS<double>(regs.cop0, FS(instr));
|
|
|
|
auto val = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
SetFGR_Raw(FD(instr), val);
|
|
|
|
FGR<double>(regs.cop0.status, FD(instr)) = val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::negs(Registers ®s, u32 instr) {
|
|
|
|
void Cop1::negs(Registers ®s, u32 instr) {
|
|
|
|
@@ -732,122 +791,122 @@ void Cop1::sqrtd(Registers ®s, 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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckWCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s32>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<float>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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 = FGR<double>(regs.cop0.status, FS(instr));
|
|
|
|
CheckLCVTArg(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);
|
|
|
|
SetFGR(FD(instr), result);
|
|
|
|
FGR<s64>(regs.cop0.status, FD(instr)) = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<class T>
|
|
|
|
template<class T>
|
|
|
|
@@ -923,7 +982,7 @@ void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
u32 data = mem.Read32(regs, physical);
|
|
|
|
u32 data = mem.Read32(regs, physical);
|
|
|
|
SetFGR_FR<u32>(regs.cop0, FT(instr), data);
|
|
|
|
FGR<u32>(regs.cop0.status, FT(instr)) = data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -935,7 +994,7 @@ void Cop1::swc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|
|
|
HandleTLBException(regs, addr);
|
|
|
|
HandleTLBException(regs, addr);
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
mem.Write32(regs, physical, GetFGR_FR<u32>(regs.cop0, FT(instr)));
|
|
|
|
mem.Write32(regs, physical, FGR<u32>(regs.cop0.status, FT(instr)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -954,7 +1013,7 @@ void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
u64 data = mem.Read64(regs, physical);
|
|
|
|
u64 data = mem.Read64(regs, physical);
|
|
|
|
SetFGR_FR<u64>(regs.cop0, FT(instr), data);
|
|
|
|
FGR<u64>(regs.cop0.status, FT(instr)) = data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -966,28 +1025,28 @@ void Cop1::sdc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
|
|
|
HandleTLBException(regs, addr);
|
|
|
|
HandleTLBException(regs, addr);
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
|
|
|
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
mem.Write64(regs, physical, GetFGR_FR<u64>(regs.cop0, FT(instr)));
|
|
|
|
mem.Write64(regs, physical, FGR<u64>(regs.cop0.status, FT(instr)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::mfc1(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::mfc1(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
regs.gpr[RT(instr)] = (s32)GetFGR_FR<u32>(regs.cop0, FS(instr));
|
|
|
|
regs.gpr[RT(instr)] = FGR<s32>(regs.cop0.status, FS(instr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::dmfc1(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::dmfc1(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
regs.gpr[RT(instr)] = (s64)GetFGR_FR<u64>(regs.cop0, FS(instr));
|
|
|
|
regs.gpr[RT(instr)] = FGR<s64>(regs.cop0.status, FS(instr));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::mtc1(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::mtc1(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
SetFGR_FR<u32>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
|
|
|
FGR<u32>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Cop1::dmtc1(Registers& regs, u32 instr) {
|
|
|
|
void Cop1::dmtc1(Registers& regs, u32 instr) {
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
CheckFPUUsable_PreserveCause();
|
|
|
|
SetFGR_FR<u64>(regs.cop0, FS(instr), regs.gpr[RT(instr)]);
|
|
|
|
FGR<u64>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|