qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 49/60] AArch64: Add "Data-processing (3 source)" ins


From: Alexander Graf
Subject: [Qemu-devel] [PATCH 49/60] AArch64: Add "Data-processing (3 source)" instruction
Date: Fri, 27 Sep 2013 02:48:43 +0200

This patch adds emulation for most of the "Data-processing (3 source)" family
of instructions, namely MADD, MSUB, SMADDL, SMSUBL, SMULH, UMADDL, UMSUBL,
UMULH.

Signed-off-by: Alexander Graf <address@hidden>
---
 target-arm/helper-a64.c    | 14 ++++++++
 target-arm/helper-a64.h    |  2 ++
 target-arm/translate-a64.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+)

diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index a8a8499..a46b00e 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -261,3 +261,17 @@ uint64_t HELPER(clz64)(uint64_t x)
 {
     return clz64(x);
 }
+
+uint64_t HELPER(umulh)(uint64_t n, uint64_t m)
+{
+    uint64_t rl, rh;
+    mulu64(&rl, &rh, n, m);
+    return rh;
+}
+
+uint64_t HELPER(smulh)(uint64_t n, uint64_t m)
+{
+    uint64_t rl, rh;
+    muls64(&rl, &rh, n, m);
+    return rh;
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index 607ba8a..41dedd7 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -28,3 +28,5 @@ DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
 DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
 DEF_HELPER_FLAGS_1(clz64, TCG_CALL_NO_RWG_SE, i64, i64)
+DEF_HELPER_FLAGS_2(umulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(smulh, TCG_CALL_NO_RWG_SE, i64, i64, i64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 32cfab3..5985c01 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1631,6 +1631,93 @@ static void handle_clz(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_val);
 }
 
+static void handle_mulh(DisasContext *s, uint32_t insn)
+{
+    int rd = get_reg(insn);
+    int rn = get_bits(insn, 5, 5);
+    int rm = get_bits(insn, 16, 5);
+    bool is_signed = !get_bits(insn, 23, 1);
+
+    if (is_signed) {
+        gen_helper_smulh(cpu_reg(rd), cpu_reg(rn), cpu_reg(rm));
+    } else {
+        gen_helper_umulh(cpu_reg(rd), cpu_reg(rn), cpu_reg(rm));
+    }
+}
+
+/* Data-processing (3 source) */
+static void handle_dp3s(DisasContext *s, uint32_t insn)
+{
+    int rd = get_reg(insn);
+    int rn = get_bits(insn, 5, 5);
+    int ra = get_bits(insn, 10, 5);
+    int rm = get_bits(insn, 16, 5);
+    int op_id = (get_bits(insn, 29, 3) << 4) |
+                (get_bits(insn, 21, 3) << 1) |
+                get_bits(insn, 15, 1);
+    bool is_32bit = !(op_id & 0x40);
+    bool is_sub = op_id & 0x1;
+    bool is_signed = (op_id >= 0x42) && (op_id <= 0x44);
+    bool is_high = op_id & 0x4;
+    TCGv_i64 tcg_op1;
+    TCGv_i64 tcg_op2;
+    TCGv_i64 tcg_tmp;
+
+    switch (op_id) {
+    case 0x0: /* MADD (32bit) */
+    case 0x1: /* MSUB (32bit) */
+    case 0x40: /* MADD (64bit) */
+    case 0x41: /* MSUB (64bit) */
+    case 0x42: /* SMADDL */
+    case 0x43: /* SMSUBL */
+    case 0x44: /* SMULH */
+    case 0x4a: /* UMADDL */
+    case 0x4b: /* UMSUBL */
+    case 0x4c: /* UMULH */
+        break;
+    default:
+        unallocated_encoding(s);
+    }
+
+    if (is_high) {
+        handle_mulh(s, insn);
+        return;
+    }
+
+    tcg_op1 = tcg_temp_new_i64();
+    tcg_op2 = tcg_temp_new_i64();
+    tcg_tmp = tcg_temp_new_i64();
+
+    if (op_id < 0x42) {
+        tcg_gen_mov_i64(tcg_op1, cpu_reg(rn));
+        tcg_gen_mov_i64(tcg_op2, cpu_reg(rm));
+    } else {
+        if (is_signed) {
+            tcg_gen_ext32s_i64(tcg_op1, cpu_reg(rn));
+            tcg_gen_ext32s_i64(tcg_op2, cpu_reg(rm));
+        } else {
+            tcg_gen_ext32u_i64(tcg_op1, cpu_reg(rn));
+            tcg_gen_ext32u_i64(tcg_op2, cpu_reg(rm));
+        }
+    }
+
+    tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
+
+    if (is_sub) {
+        tcg_gen_sub_i64(cpu_reg(rd), cpu_reg(ra), tcg_tmp);
+    } else {
+        tcg_gen_add_i64(cpu_reg(rd), cpu_reg(ra), tcg_tmp);
+    }
+
+    if (is_32bit) {
+        tcg_gen_ext32u_i64(cpu_reg(rd), cpu_reg(rd));
+    }
+
+    tcg_temp_free_i64(tcg_op1);
+    tcg_temp_free_i64(tcg_op2);
+    tcg_temp_free_i64(tcg_tmp);
+}
+
 /* SIMD ORR */
 static void handle_simdorr(DisasContext *s, uint32_t insn)
 {
@@ -2207,6 +2294,9 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s)
             unallocated_encoding(s);
         }
         break;
+    case 0x1b:
+        handle_dp3s(s, insn);
+        break;
     default:
         unallocated_encoding(s);
         break;
-- 
1.7.12.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]