Such a stupid bug

This commit is contained in:
SimoneN64
2024-06-24 00:20:33 +02:00
parent b6385684bc
commit f0273aec34
2 changed files with 24 additions and 66 deletions

View File

@@ -118,8 +118,6 @@ struct Cop1 {
template <typename T>
bool CheckCVTArg(double &f);
template <typename T>
void SetCauseByArg(T f);
template <bool cvt = false>
bool TestExceptions();
bool SetCauseUnimplemented();

View File

@@ -273,22 +273,23 @@ bool Cop1::CheckFPUException() {
template <typename T>
FORCE_INLINE T FlushResult(T f, u32 round) {
switch (round) {
case 0: case 1: return std::copysign(T(), f);
case 2: return std::signbit(f) ? -T() : std::numeric_limits<T>::min();
case 3: return std::signbit(f) ? -std::numeric_limits<T>::min() : T();
case FE_TONEAREST: case FE_TOWARDZERO: return std::copysign(T(), f);
case FE_UPWARD: return std::signbit(f) ? -T() : std::numeric_limits<T>::min();
case FE_DOWNWARD: return std::signbit(f) ? -std::numeric_limits<T>::min() : T();
}
}
template <> bool Cop1::CheckResult<float>(float& f) {
template <>
bool Cop1::CheckResult<float>(float& f) {
switch (fpclassify(f)) {
case FP_SUBNORMAL:
if(!fcr31.fs || fcr31.enable_underflow || fcr31.enable_inexact_operation) {
if(SetCauseUnimplemented()) FireException();
if(SetCauseUnimplemented()) regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
return false;
}
SetCauseUnderflow();
SetCauseInexact();
f = FlushResult(f, fegetround());
f = FlushResult(f, std::fegetround());
return true;
case FP_NAN: {
uint32_t v = 0x7fbf'ffff;
@@ -299,7 +300,8 @@ template <> bool Cop1::CheckResult<float>(float& f) {
return true;
}
template <> bool Cop1::CheckResult<double>(double& f) {
template <>
bool Cop1::CheckResult<double>(double& f) {
switch (fpclassify(f)) {
case FP_SUBNORMAL:
if(!fcr31.fs || fcr31.enable_underflow || fcr31.enable_inexact_operation) {
@@ -356,78 +358,37 @@ bool Cop1::SetCauseUnimplemented() {
bool Cop1::SetCauseUnderflow() {
fcr31.cause_underflow = true;
if(!fcr31.enable_underflow) {
if(fcr31.enable_underflow) return true;
fcr31.flag_underflow = true;
return false;
}
return true;
}
bool Cop1::SetCauseInexact() {
fcr31.cause_inexact_operation = true;
if(!fcr31.enable_inexact_operation) {
if(fcr31.enable_inexact_operation) return true;
fcr31.flag_inexact_operation = true;
return false;
}
return true;
}
bool Cop1::SetCauseDivisionByZero() {
fcr31.cause_division_by_zero = true;
if(!fcr31.enable_division_by_zero) {
if(fcr31.enable_division_by_zero) return true;
fcr31.flag_division_by_zero = true;
return false;
}
return true;
}
bool Cop1::SetCauseOverflow() {
fcr31.cause_overflow = true;
if(!fcr31.enable_overflow) {
if(fcr31.enable_overflow) return true;
fcr31.flag_overflow = true;
return false;
}
return true;
}
bool Cop1::SetCauseInvalid() {
fcr31.cause_invalid_operation = true;
if(!fcr31.enable_invalid_operation) {
if(fcr31.enable_invalid_operation) return true;
fcr31.flag_invalid_operation = true;
return false;
}
return true;
}
template <typename T>
void Cop1::SetCauseByArg(T f) {
auto fp_class = std::fpclassify(f);
switch(fp_class) {
case FP_NAN:
if(isqnan(f)) {
SetCauseInvalid();
//CheckFPUException();
} else {
SetCauseUnimplemented();
//CheckFPUException();
}
break;
case FP_SUBNORMAL:
SetCauseUnimplemented();
//CheckFPUException();
break;
case FP_INFINITE:
case FP_ZERO:
case FP_NORMAL:
break; // No-op, these are fine.
default:
Util::panic("Unknown floating point classification: {}", fp_class);
}
}
#define CHECK_FPE_IMPL(type, res, operation, convert) \
@@ -1179,5 +1140,4 @@ void Cop1::dmtc1(u32 instr) {
if(!CheckFPUUsable<true>()) return;
FGR_S<u64>(regs.cop0.status, FS(instr)) = regs.gpr[RT(instr)];
}
}