diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 909dd394..b3b249e1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,7 @@ add_library(dynarmic frontend/A64/translate/impl/data_processing_shift.cpp frontend/A64/translate/impl/exception_generating.cpp frontend/A64/translate/impl/floating_point_compare.cpp + frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp frontend/A64/translate/impl/floating_point_conversion_integer.cpp frontend/A64/translate/impl/floating_point_conditional_compare.cpp frontend/A64/translate/impl/floating_point_conditional_select.cpp diff --git a/src/frontend/A64/decoder/a64.inc b/src/frontend/A64/decoder/a64.inc index b020dd5a..226a0643 100644 --- a/src/frontend/A64/decoder/a64.inc +++ b/src/frontend/A64/decoder/a64.inc @@ -876,8 +876,8 @@ INST(USHLL, "USHLL, USHLL2", "0Q101 // Data Processing - FP and SIMD - Conversion between floating point and fixed point //INST(SCVTF_float_fix, "SCVTF (scalar, fixed-point)", "z0011110yy000010ppppppnnnnnddddd") //INST(UCVTF_float_fix, "UCVTF (scalar, fixed-point)", "z0011110yy000011ppppppnnnnnddddd") -//INST(FCVTZS_float_fix, "FCVTZS (scalar, fixed-point)", "z0011110yy011000ppppppnnnnnddddd") -//INST(FCVTZU_float_fix, "FCVTZU (scalar, fixed-point)", "z0011110yy011001ppppppnnnnnddddd") +INST(FCVTZS_float_fix, "FCVTZS (scalar, fixed-point)", "z0011110yy011000ppppppnnnnnddddd") +INST(FCVTZU_float_fix, "FCVTZU (scalar, fixed-point)", "z0011110yy011001ppppppnnnnnddddd") // Data Processing - FP and SIMD - Conversion between floating point and integer //INST(FCVTNS_float, "FCVTNS (scalar)", "z0011110yy100000000000nnnnnddddd") diff --git a/src/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp b/src/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp new file mode 100644 index 00000000..a86fbb10 --- /dev/null +++ b/src/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp @@ -0,0 +1,87 @@ +/* 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 + +#include "frontend/A64/translate/impl/impl.h" + +namespace Dynarmic::A64 { + +static boost::optional GetDataSize(Imm<2> type) { + switch (type.ZeroExtend()) { + case 0b00: + return 32; + case 0b01: + return 64; + case 0b11: + return 16; + } + return boost::none; +} + +bool TranslatorVisitor::FCVTZS_float_fix(bool sf, Imm<2> type, Imm<6> scale, Vec Vn, Reg Rd) { + const size_t intsize = sf ? 64 : 32; + const auto fltsize = GetDataSize(type); + if (!fltsize || *fltsize == 16) { + return UnallocatedEncoding(); + } + if (!sf && !scale.Bit<5>()) { + return UnallocatedEncoding(); + } + const u8 fracbits = 64 - scale.ZeroExtend(); + + const IR::U32U64 fltscale = I(*fltsize, u64(fracbits + (*fltsize == 32 ? 127 : 1023)) << (*fltsize == 32 ? 23 : 52)); + const IR::U32U64 fltval = ir.FPMul(V_scalar(*fltsize, Vn), fltscale, true); + + IR::U32U64 intval; + if (intsize == 32 && *fltsize == 32) { + intval = ir.FPSingleToS32(fltval, true, true); + } else if (intsize == 32 && *fltsize == 64) { + intval = ir.FPDoubleToS32(fltval, true, true); + } else if (intsize == 64 && *fltsize == 32) { + return InterpretThisInstruction(); + } else if (intsize == 64 && *fltsize == 64) { + return InterpretThisInstruction(); + } else { + UNREACHABLE(); + } + + X(intsize, Rd, intval); + return true; +} + +bool TranslatorVisitor::FCVTZU_float_fix(bool sf, Imm<2> type, Imm<6> scale, Vec Vn, Reg Rd) { + const size_t intsize = sf ? 64 : 32; + const auto fltsize = GetDataSize(type); + if (!fltsize || *fltsize == 16) { + return UnallocatedEncoding(); + } + if (!sf && !scale.Bit<5>()) { + return UnallocatedEncoding(); + } + const u8 fracbits = 64 - scale.ZeroExtend(); + + const IR::U32U64 fltscale = I(*fltsize, u64(fracbits + (*fltsize == 32 ? 127 : 1023)) << (*fltsize == 32 ? 23 : 52)); + const IR::U32U64 fltval = ir.FPMul(V_scalar(*fltsize, Vn), fltscale, true); + + IR::U32U64 intval; + if (intsize == 32 && *fltsize == 32) { + intval = ir.FPSingleToU32(fltval, true, true); + } else if (intsize == 32 && *fltsize == 64) { + intval = ir.FPDoubleToU32(fltval, true, true); + } else if (intsize == 64 && *fltsize == 32) { + return InterpretThisInstruction(); + } else if (intsize == 64 && *fltsize == 64) { + return InterpretThisInstruction(); + } else { + UNREACHABLE(); + } + + X(intsize, Rd, intval); + return true; +} + +} // namespace Dynarmic::A64 diff --git a/tests/A64/fuzz_with_unicorn.cpp b/tests/A64/fuzz_with_unicorn.cpp index fce2771d..5c1416e3 100644 --- a/tests/A64/fuzz_with_unicorn.cpp +++ b/tests/A64/fuzz_with_unicorn.cpp @@ -162,12 +162,14 @@ static void RunTestInstance(const std::array& regs, const std::array