fp: Implement FPUnpack
This commit is contained in:
parent
4875658917
commit
4ab029c114
5 changed files with 135 additions and 0 deletions
|
@ -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
|
||||||
|
|
54
src/common/fp/unpacked.cpp
Normal file
54
src/common/fp/unpacked.cpp
Normal 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
43
src/common/fp/unpacked.h
Normal 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
|
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
35
tests/fp/unpacked_tests.cpp
Normal file
35
tests/fp/unpacked_tests.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue