qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 2/3] target-arm: implement LDA/STL instructions


From: Mans Rullgard
Subject: [Qemu-devel] [PATCH 2/3] target-arm: implement LDA/STL instructions
Date: Fri, 7 Jun 2013 13:06:25 +0100

This adds support for the ARMv8 load acquire/store release instructions.
Since qemu does nothing special for memory barriers, these can be
emulated like their non-acquire/release counterparts.

Signed-off-by: Mans Rullgard <address@hidden>
---
 target-arm/translate.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 85 insertions(+), 6 deletions(-)

diff --git a/target-arm/translate.c b/target-arm/translate.c
index 96ac5bc..f529257 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -7274,14 +7274,54 @@ static void disas_arm_insn(CPUARMState * env, 
DisasContext *s)
                     rd = (insn >> 12) & 0xf;
                     if (insn & (1 << 23)) {
                         /* load/store exclusive */
+                        int excl = (insn >> 9) & 1;
                         op1 = (insn >> 21) & 0x3;
-                        if (op1)
+                        if (!excl)
+                            ARCH(8);
+                        else if (op1)
                             ARCH(6K);
                         else
                             ARCH(6);
                         addr = tcg_temp_local_new_i32();
                         load_reg_var(s, addr, rn);
-                        if (insn & (1 << 20)) {
+                        if (!excl) {
+                            if (op1 == 1)
+                                goto illegal_op;
+                            tmp = tcg_temp_new_i32();
+                            if (insn & (1 << 20)) {
+                                switch (op1) {
+                                case 0: /* lda */
+                                    tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
+                                    break;
+                                case 2: /* ldab */
+                                    tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
+                                    break;
+                                case 3: /* ldah */
+                                    tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
+                                    break;
+                                default:
+                                    abort();
+                                }
+                                store_reg(s, rd, tmp);
+                            } else {
+                                rm = insn & 0xf;
+                                tmp = load_reg(s, rm);
+                                switch (op1) {
+                                case 0: /* stl */
+                                    tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
+                                    break;
+                                case 2: /* stlb */
+                                    tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
+                                    break;
+                                case 3: /* stlh */
+                                    tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
+                                    break;
+                                default:
+                                    abort();
+                                }
+                                tcg_temp_free_i32(tmp);
+                            }
+                        } else if (insn & (1 << 20)) {
                             switch (op1) {
                             case 0: /* ldrex */
                                 gen_load_exclusive(s, rd, 15, addr, 2);
@@ -8126,7 +8166,7 @@ static int disas_thumb2_insn(CPUARMState *env, 
DisasContext *s, uint16_t insn_hw
                     gen_store_exclusive(s, rd, rs, 15, addr, 2);
                 }
                 tcg_temp_free_i32(addr);
-            } else if ((insn & (1 << 6)) == 0) {
+            } else if ((insn & (3 << 6)) == 0) {
                 /* Table Branch.  */
                 if (rn == 15) {
                     addr = tcg_temp_new_i32();
@@ -8153,14 +8193,53 @@ static int disas_thumb2_insn(CPUARMState *env, 
DisasContext *s, uint16_t insn_hw
                 store_reg(s, 15, tmp);
             } else {
                 /* Load/store exclusive byte/halfword/doubleword.  */
-                ARCH(7);
+                if (((insn >> 6) & 3) != 1)
+                    ARCH(8);
+                else
+                    ARCH(7);
                 op = (insn >> 4) & 0x3;
-                if (op == 2) {
+                if (((insn >> 7) & 1) == 0 && op == 2) {
                     goto illegal_op;
                 }
                 addr = tcg_temp_local_new_i32();
                 load_reg_var(s, addr, rn);
-                if (insn & (1 << 20)) {
+                if ((insn & (1 << 6)) == 0) {
+                    if (op == 3)
+                        goto illegal_op;
+                    tmp = tcg_temp_new_i32();
+                    if (insn & (1 << 20)) {
+                        switch (op) {
+                        case 0: /* ldab */
+                            tcg_gen_qemu_ld8u(tmp, addr, IS_USER(s));
+                            break;
+                        case 1: /* ldah */
+                            tcg_gen_qemu_ld16u(tmp, addr, IS_USER(s));
+                            break;
+                        case 2: /* lda */
+                            tcg_gen_qemu_ld32u(tmp, addr, IS_USER(s));
+                            break;
+                        default:
+                            abort();
+                        }
+                        store_reg(s, rs, tmp);
+                    } else {
+                        tmp = load_reg(s, rs);
+                        switch (op) {
+                        case 0: /* stlb */
+                            tcg_gen_qemu_st8(tmp, addr, IS_USER(s));
+                            break;
+                        case 1: /* stlh */
+                            tcg_gen_qemu_st16(tmp, addr, IS_USER(s));
+                            break;
+                        case 2: /* stl */
+                            tcg_gen_qemu_st32(tmp, addr, IS_USER(s));
+                            break;
+                        default:
+                            abort();
+                        }
+                        tcg_temp_free_i32(tmp);
+                    }
+                } else if (insn & (1 << 20)) {
                     gen_load_exclusive(s, rs, rd, addr, op);
                 } else {
                     gen_store_exclusive(s, rm, rs, rd, addr, op);
-- 
1.8.2.1




reply via email to

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