diff --git a/ares/n64/cpu/cpu.hpp b/ares/n64/cpu/cpu.hpp index f39ed36a55..6abad3678c 100644 --- a/ares/n64/cpu/cpu.hpp +++ b/ares/n64/cpu/cpu.hpp @@ -700,8 +700,10 @@ struct CPU : Thread { auto fpeInvalidOperation() -> bool; auto fpeUnimplemented() -> bool; auto fpuCheckStart() -> bool; - auto fpuCheckInput(f32& f) -> bool; - auto fpuCheckInput(f64& f) -> bool; + template + auto fpuCheckInput(T& f) -> bool; + template + auto fpuCheckInputs(T& f1, T& f2) -> bool; auto fpuCheckOutput(f32& f) -> bool; auto fpuCheckOutput(f64& f) -> bool; auto fpuClearCause() -> void; diff --git a/ares/n64/cpu/interpreter-fpu.cpp b/ares/n64/cpu/interpreter-fpu.cpp index 031f296b0a..5da902a278 100644 --- a/ares/n64/cpu/interpreter-fpu.cpp +++ b/ares/n64/cpu/interpreter-fpu.cpp @@ -281,7 +281,9 @@ auto CPU::fpuCheckStart() -> bool { return true; } -auto CPU::fpuCheckInput(f32& f) -> bool { +template +auto CPU::fpuCheckInput(T& f) -> bool { + static_assert(std::is_same_v || std::is_same_v); switch (fpclassify(f)) { case FP_SUBNORMAL: if(fpeUnimplemented()) return exception.floatingPoint(), false; @@ -294,19 +296,23 @@ auto CPU::fpuCheckInput(f32& f) -> bool { return true; } -auto CPU::fpuCheckInput(f64& f) -> bool { - switch (fpclassify(f)) { - case FP_SUBNORMAL: +template +auto CPU::fpuCheckInputs(T& f1, T& f2) -> bool { + static_assert(std::is_same_v || std::is_same_v); + int cl1 = fpclassify(f1), cl2 = fpclassify(f2); + if((cl1 == FP_NAN && !qnan(f1)) || (cl2 == FP_NAN && !qnan(f2))) { if(fpeUnimplemented()) return exception.floatingPoint(), false; - return true; - case FP_NAN: - if(qnan(f) ? fpeInvalidOperation() : fpeUnimplemented()) - return exception.floatingPoint(), false; - return true; + } + if(cl1 == FP_SUBNORMAL || cl2 == FP_SUBNORMAL) { + if(fpeUnimplemented()) return exception.floatingPoint(), false; + } + if((cl1 == FP_NAN && qnan(f1)) || (cl2 == FP_NAN && qnan(f2))) { + if(fpeInvalidOperation()) return exception.floatingPoint(), false; } return true; } + template auto fpuFlushResult(T f, u32 roundMode) -> T { @@ -457,8 +463,7 @@ auto CPU::FABS_D(u8 fd, u8 fs) -> void { auto CPU::FADD_S(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; f32 ffs = FS(f32), fft = FT(f32); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f32, ffd, FS(f32) + FT(f32)); if(!fpuCheckOutput(ffd)) return; FD(f32) = ffd; @@ -468,8 +473,7 @@ auto CPU::FADD_S(u8 fd, u8 fs, u8 ft) -> void { auto CPU::FADD_D(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f64), fft = FT(f64); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f64, ffd, ffs + fft); if(!fpuCheckOutput(ffd)) return; FD(f64) = ffd; @@ -799,8 +803,7 @@ auto CPU::FCVT_W_D(u8 fd, u8 fs) -> void { auto CPU::FDIV_S(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f32), fft = FT(f32); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f32, ffd, ffs / fft); if(!fpuCheckOutput(ffd)) return; FD(f32) = ffd; @@ -810,8 +813,7 @@ auto CPU::FDIV_S(u8 fd, u8 fs, u8 ft) -> void { auto CPU::FDIV_D(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f64), fft = FT(f64); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f64, ffd, ffs / fft); if(!fpuCheckOutput(ffd)) return; FD(f64) = ffd; @@ -866,8 +868,7 @@ auto CPU::FMOV_D(u8 fd, u8 fs) -> void { auto CPU::FMUL_S(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f32), fft = FT(f32); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f32, ffd, ffs * fft); if(!fpuCheckOutput(ffd)) return; FD(f32) = ffd; @@ -877,8 +878,7 @@ auto CPU::FMUL_S(u8 fd, u8 fs, u8 ft) -> void { auto CPU::FMUL_D(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f64), fft = FT(f64); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f64, ffd, ffs * fft); if(!fpuCheckOutput(ffd)) return; FD(f64) = ffd; @@ -966,8 +966,7 @@ auto CPU::FSQRT_D(u8 fd, u8 fs) -> void { auto CPU::FSUB_S(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f32), fft = FT(f32); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f32, ffd, ffs - fft); if(!fpuCheckOutput(ffd)) return; FD(f32) = ffd; @@ -977,8 +976,7 @@ auto CPU::FSUB_S(u8 fd, u8 fs, u8 ft) -> void { auto CPU::FSUB_D(u8 fd, u8 fs, u8 ft) -> void { if(!fpuCheckStart()) return; auto ffs = FS(f64), fft = FT(f64); - if(!fpuCheckInput(ffs)) return; - if(!fpuCheckInput(fft)) return; + if(!fpuCheckInputs(ffs, fft)) return; CHECK_FPE(f64, ffd, ffs - fft); if(!fpuCheckOutput(ffd)) return; FD(f64) = ffd;