/* This file is part of the dynarmic project. * Copyright (c) 2018 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #pragma once #include "common/bit_util.h" #include "common/common_types.h" namespace Dynarmic::FP { template struct FPInfo {}; template<> struct FPInfo { static constexpr size_t total_width = 16; static constexpr size_t exponent_width = 5; static constexpr size_t explicit_mantissa_width = 10; static constexpr size_t mantissa_width = explicit_mantissa_width + 1; static constexpr u32 implicit_leading_bit = u32(1) << explicit_mantissa_width; static constexpr u32 sign_mask = 0x8000; static constexpr u32 exponent_mask = 0x7C00; static constexpr u32 mantissa_mask = 0x3FF; static constexpr u32 mantissa_msb = 0x200; static constexpr int exponent_min = -14; static constexpr int exponent_max = 15; static constexpr int exponent_bias = 15; static constexpr u16 Zero(bool sign) { return sign ? static_cast(sign_mask) : u16{0}; } static constexpr u16 Infinity(bool sign) { return static_cast(exponent_mask | Zero(sign)); } static constexpr u16 MaxNormal(bool sign) { return static_cast((exponent_mask - 1) | Zero(sign)); } static constexpr u16 DefaultNaN() { return static_cast(exponent_mask | (u32(1) << (explicit_mantissa_width - 1))); } }; template<> struct FPInfo { static constexpr size_t total_width = 32; static constexpr size_t exponent_width = 8; static constexpr size_t explicit_mantissa_width = 23; static constexpr size_t mantissa_width = explicit_mantissa_width + 1; static constexpr u32 implicit_leading_bit = u32(1) << explicit_mantissa_width; static constexpr u32 sign_mask = 0x80000000; static constexpr u32 exponent_mask = 0x7F800000; static constexpr u32 mantissa_mask = 0x007FFFFF; static constexpr u32 mantissa_msb = 0x00400000; static constexpr int exponent_min = -126; static constexpr int exponent_max = 127; static constexpr int exponent_bias = 127; static constexpr u32 Zero(bool sign) { return sign ? sign_mask : 0; } 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)); } }; template<> struct FPInfo { static constexpr size_t total_width = 64; static constexpr size_t exponent_width = 11; static constexpr size_t explicit_mantissa_width = 52; static constexpr size_t mantissa_width = explicit_mantissa_width + 1; static constexpr u64 implicit_leading_bit = u64(1) << explicit_mantissa_width; static constexpr u64 sign_mask = 0x8000'0000'0000'0000; static constexpr u64 exponent_mask = 0x7FF0'0000'0000'0000; static constexpr u64 mantissa_mask = 0x000F'FFFF'FFFF'FFFF; static constexpr u64 mantissa_msb = 0x0008'0000'0000'0000; static constexpr int exponent_min = -1022; static constexpr int exponent_max = 1023; static constexpr int exponent_bias = 1023; static constexpr u64 Zero(bool sign) { return sign ? sign_mask : 0; } 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)); } }; /// 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::explicit_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 FPT(FPInfo::Zero(sign) | mantissa | (biased_exponent << FPInfo::explicit_mantissa_width)); } } // namespace Dynarmic::FP