From b5df8d1ef83437a0ce98701ee91b6f89a99c14e8 Mon Sep 17 00:00:00 2001
From: Lioncash <mathew1800@gmail.com>
Date: Tue, 23 Jun 2020 01:54:31 -0400
Subject: [PATCH] A32: Implement ASIMD VQDMULL (scalar)

---
 src/frontend/A32/decoder/asimd.inc            |  2 +-
 .../translate/impl/asimd_two_regs_scalar.cpp  | 24 +++++++++++++++++++
 .../A32/translate/impl/translate_arm.h        |  1 +
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/frontend/A32/decoder/asimd.inc b/src/frontend/A32/decoder/asimd.inc
index 51467c95..876363e8 100644
--- a/src/frontend/A32/decoder/asimd.inc
+++ b/src/frontend/A32/decoder/asimd.inc
@@ -74,7 +74,7 @@ INST(asimd_VMLAL_scalar,    "VMLAL (scalar)",           "1111001U1dzznnnndddd0o1
 //INST(asimd_VQDMLAL_scalar,  "VQDMLAL/VQDMLSL (scalar)", "111100101-BB--------0x11-1-0----") // ASIMD
 INST(asimd_VMUL_scalar,     "VMUL (scalar)",            "1111001Q1Dzznnnndddd100FN1M0mmmm") // ASIMD
 INST(asimd_VMULL_scalar,    "VMULL (scalar)",           "1111001U1Dzznnnndddd1010N1M0mmmm") // ASIMD
-//INST(asimd_VQDMULL_scalar,  "VQDMULL (scalar)",         "111100101-BB--------1011-1-0----") // ASIMD
+INST(asimd_VQDMULL_scalar,  "VQDMULL (scalar)",         "111100101Dzznnnndddd1011N1M0mmmm") // ASIMD
 INST(asimd_VQDMULH_scalar,  "VQDMULH (scalar)",         "1111001Q1Dzznnnndddd1100N1M0mmmm") // ASIMD
 INST(asimd_VQRDMULH_scalar, "VQRDMULH (scalar)",        "1111001Q1Dzznnnndddd1101N1M0mmmm") // ASIMD
 
diff --git a/src/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp b/src/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp
index 9e94b428..9d31dfad 100644
--- a/src/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp
+++ b/src/frontend/A32/translate/impl/asimd_two_regs_scalar.cpp
@@ -169,6 +169,30 @@ bool ArmTranslatorVisitor::asimd_VMULL_scalar(bool U, bool D, size_t sz, size_t
     return ScalarMultiplyLong(*this, U, D, sz, Vn, Vd, N, M, Vm, MultiplyBehavior::Multiply);
 }
 
+bool ArmTranslatorVisitor::asimd_VQDMULL_scalar(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm) {
+    if (sz == 0b11) {
+        // TODO: This should be a decode error.
+        return UndefinedInstruction();
+    }
+
+    if (sz == 0b00 || Common::Bit<0>(Vd)) {
+        return UndefinedInstruction();
+    }
+
+    const size_t esize = 8U << sz;
+    const auto d = ToVector(true, Vd, D);
+    const auto n = ToVector(false, Vn, N);
+    const auto [m, index] = GetScalarLocation(esize, M, Vm);
+
+    const auto scalar = ir.VectorGetElement(esize, ir.GetVector(m), index);
+    const auto reg_n = ir.GetVector(n);
+    const auto reg_m = ir.VectorBroadcast(esize, scalar);
+    const auto result = ir.VectorSignedSaturatedDoublingMultiplyLong(esize, reg_m, reg_n);
+
+    ir.SetVector(d, result);
+    return true;
+}
+
 bool ArmTranslatorVisitor::asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm) {
     return ScalarMultiplyReturnHigh(*this, Q, D, sz, Vn, Vd, N, M, Vm, Rounding::None);
 }
diff --git a/src/frontend/A32/translate/impl/translate_arm.h b/src/frontend/A32/translate/impl/translate_arm.h
index 260888a1..ed7e2630 100644
--- a/src/frontend/A32/translate/impl/translate_arm.h
+++ b/src/frontend/A32/translate/impl/translate_arm.h
@@ -510,6 +510,7 @@ struct ArmTranslatorVisitor final {
     bool asimd_VMLAL_scalar(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool op, bool N, bool M, size_t Vm);
     bool asimd_VMUL_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool F, bool N, bool M, size_t Vm);
     bool asimd_VMULL_scalar(bool U, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
+    bool asimd_VQDMULL_scalar(bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
     bool asimd_VQDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);
     bool asimd_VQRDMULH_scalar(bool Q, bool D, size_t sz, size_t Vn, size_t Vd, bool N, bool M, size_t Vm);