From be57608353ad4605ea6fdc569039891a36be94d7 Mon Sep 17 00:00:00 2001
From: MerryMage <MerryMage@users.noreply.github.com>
Date: Tue, 20 Feb 2018 18:45:28 +0000
Subject: [PATCH] A64: Partially implement FCVTZU (scalar, fixed-point) and
 FCVTZS (scalar, fixed-point)

---
 src/CMakeLists.txt                            |  1 +
 src/frontend/A64/decoder/a64.inc              |  4 +-
 .../floating_point_conversion_fixed_point.cpp | 87 +++++++++++++++++++
 tests/A64/fuzz_with_unicorn.cpp               |  2 +
 4 files changed, 92 insertions(+), 2 deletions(-)
 create mode 100644 src/frontend/A64/translate/impl/floating_point_conversion_fixed_point.cpp

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 <boost/optional.hpp>
+
+#include "frontend/A64/translate/impl/impl.h"
+
+namespace Dynarmic::A64 {
+
+static boost::optional<size_t> 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<u8>();
+
+    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<u8>();
+
+    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<u64, 31>& regs, const std::array<Ve
     jit.SetVectors(vecs);
     jit.SetPC(instructions_offset * 4);
     jit.SetSP(0x08000000);
+    jit.SetFpcr(0);
     jit.SetPstate(pstate);
     jit.ClearCache();
     uni.SetRegisters(regs);
     uni.SetVectors(vecs);
     uni.SetPC(instructions_offset * 4);
     uni.SetSP(0x08000000);
+    uni.SetFpcr(0);
     uni.SetPstate(pstate);
     uni.ClearPageCache();