diff --git a/src/common/fp/info.h b/src/common/fp/info.h index b78f1382..df3de71f 100644 --- a/src/common/fp/info.h +++ b/src/common/fp/info.h @@ -6,6 +6,7 @@ #pragma once +#include "common/bit_util.h" #include "common/common_types.h" namespace Dynarmic::FP { @@ -33,8 +34,6 @@ struct FPInfo { static constexpr u32 Infinity(bool sign) { return exponent_mask | Zero(sign); } static constexpr u32 MaxNormal(bool sign) { return (exponent_mask - 1) | Zero(sign); } static constexpr u32 DefaultNaN() { return exponent_mask | (u32(1) << (explicit_mantissa_width - 1)); } - static constexpr u32 OnePointFive(bool sign) { return Zero(sign) | (u32(1) << (explicit_mantissa_width - 1)) | (u32(exponent_bias) << explicit_mantissa_width); } - static constexpr u32 Two(bool sign) { return Zero(sign) | (u32(exponent_bias + 1) << explicit_mantissa_width); } }; template<> @@ -57,8 +56,26 @@ struct FPInfo { static constexpr u64 Infinity(bool sign) { return exponent_mask | Zero(sign); } static constexpr u64 MaxNormal(bool sign) { return (exponent_mask - 1) | Zero(sign); } static constexpr u64 DefaultNaN() { return exponent_mask | (u64(1) << (explicit_mantissa_width - 1)); } - static constexpr u64 OnePointFive(bool sign) { return Zero(sign) | (u64(1) << (explicit_mantissa_width - 1)) | (u64(exponent_bias) << explicit_mantissa_width); } - static constexpr u64 Two(bool sign) { return Zero(sign) | (u64(exponent_bias + 1) << explicit_mantissa_width); } }; +/// value = (sign ? -1 : +1) * 2^exponent * value +/// @note We do not handle denormals. Denormals will static_assert. +template +constexpr FPT FPValue() { + if constexpr (value == 0) { + return FPInfo::Zero(sign); + } + + constexpr int point_position = static_cast(FPInfo::mantissa_width); + constexpr int highest_bit = Common::HighestSetBit(value); + constexpr int offset = point_position - highest_bit; + constexpr int normalized_exponent = exponent - offset + point_position; + static_assert(offset >= 0); + static_assert(normalized_exponent >= FPInfo::exponent_min && normalized_exponent <= FPInfo::exponent_max); + + constexpr FPT mantissa = (value << offset) & FPInfo::mantissa_mask; + constexpr FPT biased_exponent = static_cast(normalized_exponent + FPInfo::exponent_bias); + return FPInfo::Zero(sign) | mantissa | (biased_exponent << FPInfo::explicit_mantissa_width); +} + } // namespace Dynarmic::FP diff --git a/src/common/fp/op/FPRSqrtStepFused.cpp b/src/common/fp/op/FPRSqrtStepFused.cpp index e83db7b2..5e5ab742 100644 --- a/src/common/fp/op/FPRSqrtStepFused.cpp +++ b/src/common/fp/op/FPRSqrtStepFused.cpp @@ -33,7 +33,8 @@ FPT FPRSqrtStepFused(FPT op1, FPT op2, FPCR fpcr, FPSR& fpsr) { const bool zero2 = type2 == FPType::Zero; if ((inf1 && zero2) || (zero1 && inf2)) { - return FPInfo::OnePointFive(false); + // return +1.5 + return FPValue(); } if (inf1 || inf2) { diff --git a/src/common/fp/op/FPRecipStepFused.cpp b/src/common/fp/op/FPRecipStepFused.cpp index da849c0a..2cb09c06 100644 --- a/src/common/fp/op/FPRecipStepFused.cpp +++ b/src/common/fp/op/FPRecipStepFused.cpp @@ -33,7 +33,8 @@ FPT FPRecipStepFused(FPT op1, FPT op2, FPCR fpcr, FPSR& fpsr) { const bool zero2 = type2 == FPType::Zero; if ((inf1 && zero2) || (zero1 && inf2)) { - return FPInfo::Two(false); + // return +2.0 + return FPValue(); } if (inf1 || inf2) {