fp: Implement FPUnpack

This commit is contained in:
MerryMage 2018-06-27 13:52:20 +01:00
parent 4875658917
commit 4ab029c114
5 changed files with 135 additions and 0 deletions

View file

@ -21,6 +21,8 @@ add_library(dynarmic
common/fp/process_exception.cpp common/fp/process_exception.cpp
common/fp/process_exception.h common/fp/process_exception.h
common/fp/rounding_mode.h common/fp/rounding_mode.h
common/fp/unpacked.cpp
common/fp/unpacked.h
common/fp/util.h common/fp/util.h
common/intrusive_list.h common/intrusive_list.h
common/iterator_util.h common/iterator_util.h

View file

@ -0,0 +1,54 @@
/* 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.
*/
#include "common/fp/info.h"
#include "common/fp/process_exception.h"
#include "common/fp/unpacked.h"
namespace Dynarmic::FP {
template<typename FPT>
std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr) {
constexpr size_t sign_bit = FPInfo<FPT>::exponent_width + FPInfo<FPT>::explicit_mantissa_width;
constexpr size_t exponent_high_bit = FPInfo<FPT>::exponent_width + FPInfo<FPT>::explicit_mantissa_width - 1;
constexpr size_t exponent_low_bit = FPInfo<FPT>::explicit_mantissa_width;
constexpr size_t mantissa_high_bit = FPInfo<FPT>::explicit_mantissa_width - 1;
constexpr size_t mantissa_low_bit = 0;
constexpr int denormal_exponent = FPInfo<FPT>::exponent_min - int(FPInfo<FPT>::explicit_mantissa_width);
const bool sign = Common::Bit<sign_bit>(op);
const FPT exp_raw = Common::Bits<exponent_low_bit, exponent_high_bit>(op);
const FPT frac_raw = Common::Bits<mantissa_low_bit, mantissa_high_bit>(op);
if (exp_raw == 0) {
if (frac_raw == 0 || fpcr.FZ()) {
if (frac_raw != 0) {
FPProcessException(FPExc::InputDenorm, fpcr, fpsr);
}
return {FPType::Zero, sign, {sign, 0, 0}};
}
return {FPType::Nonzero, sign, {sign, denormal_exponent, frac_raw}};
}
if (exp_raw == Common::Ones<FPT>(FPInfo<FPT>::exponent_width)) {
if (frac_raw == 0) {
return {FPType::Infinity, sign, {sign, 1000000, 1}};
}
const bool is_quiet = Common::Bit<mantissa_high_bit>(frac_raw);
return {is_quiet ? FPType::QNaN : FPType::SNaN, sign, {sign, 0, 0}};
}
const int exp = static_cast<int>(exp_raw) - FPInfo<FPT>::exponent_bias - FPInfo<FPT>::explicit_mantissa_width;
const u64 frac = frac_raw | FPInfo<FPT>::implicit_leading_bit;
return {FPType::Nonzero, sign, {sign, exp, frac}};
}
template std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack<u32>(u32 op, FPCR fpcr, FPSR& fpsr);
template std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack<u64>(u64 op, FPCR fpcr, FPSR& fpsr);
} // namespace Dynarmic::FP

43
src/common/fp/unpacked.h Normal file
View file

@ -0,0 +1,43 @@
/* 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 <tuple>
#include "common/common_types.h"
#include "common/fp/fpsr.h"
#include "frontend/A64/FPCR.h"
namespace Dynarmic::FP {
using FPCR = A64::FPCR;
enum class FPType {
Nonzero,
Zero,
Infinity,
QNaN,
SNaN,
};
/// value = (sign ? -1 : +1) * mantissa * 2^exponent
template<typename MantissaT>
struct FPUnpacked {
bool sign;
int exponent;
MantissaT mantissa;
};
template<typename MantissaT>
inline bool operator==(const FPUnpacked<MantissaT>& a, const FPUnpacked<MantissaT>& b) {
return std::tie(a.sign, a.exponent, a.mantissa) == std::tie(b.sign, b.exponent, b.mantissa);
}
template<typename FPT>
std::tuple<FPType, bool, FPUnpacked<u64>> FPUnpack(FPT op, FPCR fpcr, FPSR& fpsr);
} // namespace Dynarmic::FP

View file

@ -29,6 +29,7 @@ add_executable(dynarmic_tests
A64/inst_gen.cpp A64/inst_gen.cpp
A64/inst_gen.h A64/inst_gen.h
A64/testenv.h A64/testenv.h
fp/unpacked_tests.cpp
main.cpp main.cpp
rand_int.h rand_int.h
) )

View file

@ -0,0 +1,35 @@
/* 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.
*/
#include <catch.hpp>
#include "common/fp/unpacked.h"
using namespace Dynarmic;
using namespace Dynarmic::FP;
TEST_CASE("FPUnpack Tests", "[fp]") {
const static std::vector<std::tuple<u32, std::tuple<FPType, bool, FPUnpacked<u64>>, u32>> test_cases {
{0x00000000, {FPType::Zero, false, {false, 0, 0}}, 0},
{0x7F800000, {FPType::Infinity, false, {false, 1000000, 1}}, 0},
{0xFF800000, {FPType::Infinity, true, {true, 1000000, 1}}, 0},
{0x7F800001, {FPType::SNaN, false, {false, 0, 0}}, 0},
{0xFF800001, {FPType::SNaN, true, {true, 0, 0}}, 0},
{0x7FC00001, {FPType::QNaN, false, {false, 0, 0}}, 0},
{0xFFC00001, {FPType::QNaN, true, {true, 0, 0}}, 0},
{0x00000001, {FPType::Nonzero, false, {false, -149, 1}}, 0}, // Smallest single precision denormal is 2^-149.
};
const FPCR fpcr;
for (const auto& [input, expected_output, expected_fpsr] : test_cases) {
FPSR fpsr;
const auto output = FPUnpack<u32>(input, fpcr, fpsr);
INFO("Input: " << std::hex << input);
REQUIRE(output == expected_output);
REQUIRE(fpsr.Value() == expected_fpsr);
}
}