qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 31/60] AArch64: Add bfm family instruction emulation


From: Alexander Graf
Subject: [Qemu-devel] [PATCH 31/60] AArch64: Add bfm family instruction emulation
Date: Fri, 27 Sep 2013 02:48:25 +0200

This patch adds emulation support for BFM and friends (SBFM, UBFM).

Signed-off-by: Alexander Graf <address@hidden>
---
 target-arm/helper-a64.c    |  9 +++++
 target-arm/helper-a64.h    |  1 +
 target-arm/translate-a64.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 95 insertions(+), 1 deletion(-)

diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 2400b6e..bc575a2 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -137,3 +137,12 @@ uint32_t HELPER(pstate_sub32)(uint32_t pstate, uint64_t 
x1, uint64_t x2,
 
     return pstate;
 }
+
+uint64_t HELPER(sign_extend)(uint64_t x, uint64_t is_signed, uint64_t mask)
+{
+    if (x & is_signed) {
+        x |= mask;
+    }
+
+    return x;
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index 4deab64..7c5cdc6 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -21,3 +21,4 @@ DEF_HELPER_FLAGS_4(pstate_add, TCG_CALL_NO_RWG_SE, i32, i32, 
i64, i64, i64)
 DEF_HELPER_FLAGS_4(pstate_add32, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64)
 DEF_HELPER_FLAGS_4(pstate_sub, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64)
 DEF_HELPER_FLAGS_4(pstate_sub32, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64)
+DEF_HELPER_FLAGS_3(sign_extend, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index a314af0..583a68f 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1170,6 +1170,90 @@ static void handle_extr(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_res);
 }
 
+static void handle_bfm(DisasContext *s, uint32_t insn)
+{
+    bool is_32bit = !get_bits(insn, 31, 1);
+    int opc = get_bits(insn, 29, 2);
+    int dest = get_reg(insn);
+    int source = get_bits(insn, 5, 5);
+    int is_n = get_bits(insn, 22, 1);
+    int imms = get_bits(insn, 10, 6);
+    int immr = get_bits(insn, 16, 6);
+    TCGv_i64 tcg_newmask;
+    uint64_t mask, tmask, topmask;
+    uint64_t signbit = 1;
+    int bitsize = is_32bit ? 32 : 64;
+
+    if (!is_32bit && !is_n) {
+        /* reserved */
+        unallocated_encoding(s);
+    }
+
+    if (is_32bit && (is_n || (immr & (1 << 5)) || imms & (1 << 5))) {
+        /* reserved */
+        unallocated_encoding(s);
+    }
+
+    tcg_newmask = tcg_temp_new_i64();
+
+    if (imms == 0x3f) {
+        tmask = mask = ~0ULL;
+    } else {
+        tmask = mask = ((1ULL << (imms + 1)) - 1);
+    }
+
+    tcg_gen_andi_i64(tcg_newmask, cpu_reg(source), mask);
+    if (imms < immr) {
+        tcg_gen_shli_i64(tcg_newmask, tcg_newmask, bitsize - immr);
+        tmask <<= bitsize - immr;
+        signbit <<= bitsize + imms - immr;
+        if (signbit == 0x8000000000000000ULL) {
+            /* Can't pad anymore - highest bit is already set */
+            topmask = 0;
+        } else {
+            topmask = ~((1ULL << (bitsize + imms - immr + 1)) - 1);
+        }
+    } else {
+        tcg_gen_shri_i64(tcg_newmask, tcg_newmask, immr);
+        tmask >>= immr;
+        signbit <<= imms - immr;
+        topmask = ~tmask;
+    }
+
+    if (is_32bit) {
+        tcg_gen_ext32u_i64(tcg_newmask, tcg_newmask);
+    }
+
+    switch (opc) {
+    case 0: { /* SBFM */
+        TCGv_i64 tcg_mask = tcg_const_i64(topmask);
+        TCGv_i64 tcg_signbit = tcg_const_i64(signbit);
+        gen_helper_sign_extend(cpu_reg(dest), tcg_newmask, tcg_signbit,
+                               tcg_mask);
+        tcg_temp_free_i64(tcg_mask);
+        tcg_temp_free_i64(tcg_signbit);
+        break;
+    }
+    case 1: /* BFM */
+        /* replace the field inside dest */
+        tcg_gen_andi_i64(cpu_reg(dest), cpu_reg(dest), ~tmask);
+        tcg_gen_or_i64(cpu_reg(dest), cpu_reg(dest), tcg_newmask);
+        break;
+    case 2: /* UBFM */
+        tcg_gen_mov_i64(cpu_reg(dest), tcg_newmask);
+        break;
+    default:
+        unallocated_encoding(s);
+        return;
+    }
+
+    if (is_32bit) {
+        tcg_gen_ext32u_i64(cpu_reg(dest), cpu_reg(dest));
+    }
+
+    tcg_temp_free_i64(tcg_newmask);
+}
+
 /* SIMD ORR */
 static void handle_simdorr(DisasContext *s, uint32_t insn)
 {
@@ -1610,7 +1694,7 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s)
             !get_bits(insn, 29, 2)) {
             handle_extr(s, insn);
         } else {
-            unallocated_encoding(s);
+            handle_bfm(s, insn);
         }
         break;
     default:
-- 
1.7.12.4




reply via email to

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