diff mbox

[1/2] target-arm: Factor out handling of SRS instruction

Message ID 1360937918-13244-2-git-send-email-peter.maydell@linaro.org
State Accepted
Commit 81465888c5306cd94abb9847e560796fd13d3c2f
Headers show

Commit Message

Peter Maydell Feb. 15, 2013, 2:18 p.m. UTC
Factor out the handling of the SRS instruction rather than
duplicating it between the Thumb and ARM decoders. This in
passing fixes two bugs in the Thumb decoder's SRS handling
which didn't exist in the ARM decoder:
 * (LP:1079080) storing CPSR rather than SPSR (fixed in the
   ARM decoder in commit c67b6b71 in 2009)
 * failing to free the 'addr' TCG temp in the writeback case

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate.c |  136 ++++++++++++++++++++++++------------------------
 1 file changed, 69 insertions(+), 67 deletions(-)
diff mbox

Patch

diff --git a/target-arm/translate.c b/target-arm/translate.c
index a8893f7..62a4c15 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6561,6 +6561,70 @@  static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
 }
 #endif
 
+/* gen_srs:
+ * @env: CPUARMState
+ * @s: DisasContext
+ * @mode: mode field from insn (which stack to store to)
+ * @amode: addressing mode (DA/IA/DB/IB), encoded as per P,U bits in ARM insn
+ * @writeback: true if writeback bit set
+ *
+ * Generate code for the SRS (Store Return State) insn.
+ */
+static void gen_srs(DisasContext *s,
+                    uint32_t mode, uint32_t amode, bool writeback)
+{
+    int32_t offset;
+    TCGv_i32 addr = tcg_temp_new_i32();
+    TCGv_i32 tmp = tcg_const_i32(mode);
+    gen_helper_get_r13_banked(addr, cpu_env, tmp);
+    tcg_temp_free_i32(tmp);
+    switch (amode) {
+    case 0: /* DA */
+        offset = -4;
+        break;
+    case 1: /* IA */
+        offset = 0;
+        break;
+    case 2: /* DB */
+        offset = -8;
+        break;
+    case 3: /* IB */
+        offset = 4;
+        break;
+    default:
+        abort();
+    }
+    tcg_gen_addi_i32(addr, addr, offset);
+    tmp = load_reg(s, 14);
+    gen_st32(tmp, addr, 0);
+    tmp = load_cpu_field(spsr);
+    tcg_gen_addi_i32(addr, addr, 4);
+    gen_st32(tmp, addr, 0);
+    if (writeback) {
+        switch (amode) {
+        case 0:
+            offset = -8;
+            break;
+        case 1:
+            offset = 4;
+            break;
+        case 2:
+            offset = -4;
+            break;
+        case 3:
+            offset = 0;
+            break;
+        default:
+            abort();
+        }
+        tcg_gen_addi_i32(addr, addr, offset);
+        tmp = tcg_const_i32(mode);
+        gen_helper_set_r13_banked(cpu_env, tmp, addr);
+        tcg_temp_free_i32(tmp);
+    }
+    tcg_temp_free_i32(addr);
+}
+
 static void disas_arm_insn(CPUARMState * env, DisasContext *s)
 {
     unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
@@ -6653,49 +6717,11 @@  static void disas_arm_insn(CPUARMState * env, DisasContext *s)
             }
         } else if ((insn & 0x0e5fffe0) == 0x084d0500) {
             /* srs */
-            int32_t offset;
-            if (IS_USER(s))
+            if (IS_USER(s)) {
                 goto illegal_op;
-            ARCH(6);
-            op1 = (insn & 0x1f);
-            addr = tcg_temp_new_i32();
-            tmp = tcg_const_i32(op1);
-            gen_helper_get_r13_banked(addr, cpu_env, tmp);
-            tcg_temp_free_i32(tmp);
-            i = (insn >> 23) & 3;
-            switch (i) {
-            case 0: offset = -4; break; /* DA */
-            case 1: offset = 0; break; /* IA */
-            case 2: offset = -8; break; /* DB */
-            case 3: offset = 4; break; /* IB */
-            default: abort();
             }
-            if (offset)
-                tcg_gen_addi_i32(addr, addr, offset);
-            tmp = load_reg(s, 14);
-            gen_st32(tmp, addr, 0);
-            tmp = load_cpu_field(spsr);
-            tcg_gen_addi_i32(addr, addr, 4);
-            gen_st32(tmp, addr, 0);
-            if (insn & (1 << 21)) {
-                /* Base writeback.  */
-                switch (i) {
-                case 0: offset = -8; break;
-                case 1: offset = 4; break;
-                case 2: offset = -4; break;
-                case 3: offset = 0; break;
-                default: abort();
-                }
-                if (offset)
-                    tcg_gen_addi_i32(addr, addr, offset);
-                tmp = tcg_const_i32(op1);
-                gen_helper_set_r13_banked(cpu_env, tmp, addr);
-                tcg_temp_free_i32(tmp);
-                tcg_temp_free_i32(addr);
-            } else {
-                tcg_temp_free_i32(addr);
-            }
-            return;
+            ARCH(6);
+            gen_srs(s, (insn & 0x1f), (insn >> 23) & 3, insn & (1 << 21));
         } else if ((insn & 0x0e50ffe0) == 0x08100a00) {
             /* rfe */
             int32_t offset;
@@ -8135,32 +8161,8 @@  static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
                     gen_rfe(s, tmp, tmp2);
                 } else {
                     /* srs */
-                    op = (insn & 0x1f);
-                    addr = tcg_temp_new_i32();
-                    tmp = tcg_const_i32(op);
-                    gen_helper_get_r13_banked(addr, cpu_env, tmp);
-                    tcg_temp_free_i32(tmp);
-                    if ((insn & (1 << 24)) == 0) {
-                        tcg_gen_addi_i32(addr, addr, -8);
-                    }
-                    tmp = load_reg(s, 14);
-                    gen_st32(tmp, addr, 0);
-                    tcg_gen_addi_i32(addr, addr, 4);
-                    tmp = tcg_temp_new_i32();
-                    gen_helper_cpsr_read(tmp, cpu_env);
-                    gen_st32(tmp, addr, 0);
-                    if (insn & (1 << 21)) {
-                        if ((insn & (1 << 24)) == 0) {
-                            tcg_gen_addi_i32(addr, addr, -4);
-                        } else {
-                            tcg_gen_addi_i32(addr, addr, 4);
-                        }
-                        tmp = tcg_const_i32(op);
-                        gen_helper_set_r13_banked(cpu_env, tmp, addr);
-                        tcg_temp_free_i32(tmp);
-                    } else {
-                        tcg_temp_free_i32(addr);
-                    }
+                    gen_srs(s, (insn & 0x1f), (insn & (1 << 24)) ? 1 : 2,
+                            insn & (1 << 21));
                 }
             } else {
                 int i, loaded_base = 0;