qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 14/60] AArch64: Add orr instruction emulation


From: Alexander Graf
Subject: [Qemu-devel] [PATCH 14/60] AArch64: Add orr instruction emulation
Date: Fri, 27 Sep 2013 02:48:08 +0200

This patch adds emulation support for the orr instruction.

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

diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 8105fb5..da72b7f 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -24,3 +24,31 @@
 #include "sysemu/sysemu.h"
 #include "qemu/bitops.h"
 
+uint32_t HELPER(pstate_add)(uint32_t pstate, uint64_t a1, uint64_t a2,
+                            uint64_t ar)
+{
+    int64_t s1 = a1;
+    int64_t s2 = a2;
+    int64_t sr = ar;
+
+    pstate &= ~(PSTATE_N | PSTATE_Z | PSTATE_C | PSTATE_V);
+
+    if (sr < 0) {
+        pstate |= PSTATE_N;
+    }
+
+    if (!ar) {
+        pstate |= PSTATE_Z;
+    }
+
+    if (ar && (ar < a1)) {
+        pstate |= PSTATE_C;
+    }
+
+    if ((s1 > 0 && s2 > 0 && sr < 0) ||
+        (s1 < 0 && s2 < 0 && sr > 0)) {
+        pstate |= PSTATE_V;
+    }
+
+    return pstate;
+}
diff --git a/target-arm/helper-a64.h b/target-arm/helper-a64.h
index 30ecf78..1492b15 100644
--- a/target-arm/helper-a64.h
+++ b/target-arm/helper-a64.h
@@ -17,3 +17,4 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+DEF_HELPER_FLAGS_4(pstate_add, TCG_CALL_NO_RWG_SE, i32, i32, i64, i64, i64)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 039e73a..2a80715 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -484,6 +484,123 @@ static void handle_ldarx(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_addr);
 }
 
+static TCGv_i64 get_shift(int reg, int shift_type, TCGv_i64 tcg_shift,
+                          int is_32bit)
+{
+    TCGv_i64 r;
+
+    r = tcg_temp_new_i64();
+
+    /* XXX carry_out */
+    switch (shift_type) {
+    case 0: /* LSL */
+        tcg_gen_shl_i64(r, cpu_reg(reg), tcg_shift);
+        break;
+    case 1: /* LSR */
+        tcg_gen_shr_i64(r, cpu_reg(reg), tcg_shift);
+        break;
+    case 2: /* ASR */
+        if (is_32bit) {
+            TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+            tcg_gen_ext32s_i64(tcg_tmp, cpu_reg(reg));
+            tcg_gen_sar_i64(r, tcg_tmp, tcg_shift);
+            tcg_temp_free_i64(tcg_tmp);
+        } else {
+            tcg_gen_sar_i64(r, cpu_reg(reg), tcg_shift);
+        }
+        break;
+    case 3:
+        tcg_gen_rotr_i64(r, cpu_reg(reg), tcg_shift);
+        break;
+    }
+
+    return r;
+}
+
+static TCGv_i64 get_shifti(int reg, int shift_type, int shift, int is_32bit)
+{
+    TCGv_i64 tcg_shift;
+    TCGv_i64 r;
+
+    if (!shift) {
+        r = tcg_temp_new_i64();
+        tcg_gen_mov_i64(r, cpu_reg(reg));
+        return r;
+    }
+
+    tcg_shift = tcg_const_i64(shift);
+    r = get_shift(reg, shift_type, tcg_shift, is_32bit);
+    tcg_temp_free_i64(tcg_shift);
+
+    return r;
+}
+
+static void handle_orr(DisasContext *s, uint32_t insn)
+{
+    int is_32bit = !get_bits(insn, 31, 1);
+    int dest = get_reg(insn);
+    int source = get_bits(insn, 5, 5);
+    int rm = get_bits(insn, 16, 5);
+    int shift_amount = get_sbits(insn, 10, 6);
+    int is_n = get_bits(insn, 21, 1);
+    int shift_type = get_bits(insn, 22, 2);
+    int opc = get_bits(insn, 29, 2);
+    bool setflags = (opc == 0x3);
+    TCGv_i64 tcg_op2;
+    TCGv_i64 tcg_dest;
+
+    if (is_32bit && (shift_amount < 0)) {
+        /* reserved value */
+        unallocated_encoding(s);
+    }
+
+    /* MOV is dest = xzr & (source & ~0) */
+    if (!shift_amount && source == 0x1f) {
+        if (is_32bit) {
+            tcg_gen_ext32u_i64(cpu_reg_sp(dest), cpu_reg(rm));
+        } else {
+            tcg_gen_mov_i64(cpu_reg_sp(dest), cpu_reg(rm));
+        }
+        if (is_n) {
+            tcg_gen_not_i64(cpu_reg_sp(dest), cpu_reg_sp(dest));
+        }
+        if (is_32bit) {
+            tcg_gen_ext32u_i64(cpu_reg_sp(dest), cpu_reg_sp(dest));
+        }
+        return;
+    }
+
+    tcg_op2 = get_shifti(rm, shift_type, shift_amount & (is_32bit ? 31 : 63),
+                         is_32bit);
+    if (is_n) {
+        tcg_gen_not_i64(tcg_op2, tcg_op2);
+    }
+
+    tcg_dest = cpu_reg(dest);
+    switch (opc) {
+    case 0x0:
+    case 0x3:
+        tcg_gen_and_i64(tcg_dest, cpu_reg(source), tcg_op2);
+        break;
+    case 0x1:
+        tcg_gen_or_i64(tcg_dest, cpu_reg(source), tcg_op2);
+        break;
+    case 0x2:
+        tcg_gen_xor_i64(tcg_dest, cpu_reg(source), tcg_op2);
+        break;
+    }
+
+    if (is_32bit) {
+        tcg_gen_ext32u_i64(tcg_dest, tcg_dest);
+    }
+
+    if (setflags) {
+        gen_helper_pstate_add(pstate, pstate, tcg_dest, cpu_reg(31), tcg_dest);
+    }
+
+    tcg_temp_free_i64(tcg_op2);
+}
+
 void disas_a64_insn(CPUARMState *env, DisasContext *s)
 {
     uint32_t insn;
@@ -516,6 +633,9 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s)
             handle_ldarx(s, insn);
         }
         break;
+    case 0x0a:
+        handle_orr(s, insn);
+        break;
     case 0x0c:
         if (get_bits(insn, 29, 1)) {
             handle_stp(s, insn);
-- 
1.7.12.4




reply via email to

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