Patchwork target-arm: Don't update base register on abort in Thumb T1 LDM

login
register
mail settings
Submitter Peter Maydell
Date April 26, 2011, 5:17 p.m.
Message ID <1303838240-13582-1-git-send-email-peter.maydell@linaro.org>
Download mbox | patch
Permalink /patch/92942/
State New
Headers show

Comments

Peter Maydell - April 26, 2011, 5:17 p.m.
Make sure the base register isn't updated if it is in the load list
for a Thumb LDM (T1 encoding) which aborts partway through the load.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)
Aurelien Jarno - April 27, 2011, 6:18 p.m.
On Tue, Apr 26, 2011 at 06:17:20PM +0100, Peter Maydell wrote:
> Make sure the base register isn't updated if it is in the load list
> for a Thumb LDM (T1 encoding) which aborts partway through the load.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/translate.c |   17 ++++++++++++++---
>  1 files changed, 14 insertions(+), 3 deletions(-)

Thanks, applied.

> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index d8da514..a1af436 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -9454,7 +9454,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
>          break;
>  
>      case 12:
> +    {
>          /* load/store multiple */
> +        TCGv loaded_var;
> +        TCGV_UNUSED(loaded_var);
>          rn = (insn >> 8) & 0x7;
>          addr = load_reg(s, rn);
>          for (i = 0; i < 8; i++) {
> @@ -9462,7 +9465,11 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
>                  if (insn & (1 << 11)) {
>                      /* load */
>                      tmp = gen_ld32(addr, IS_USER(s));
> -                    store_reg(s, i, tmp);
> +                    if (i == rn) {
> +                        loaded_var = tmp;
> +                    } else {
> +                        store_reg(s, i, tmp);
> +                    }
>                  } else {
>                      /* store */
>                      tmp = load_reg(s, i);
> @@ -9472,14 +9479,18 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
>                  tcg_gen_addi_i32(addr, addr, 4);
>              }
>          }
> -        /* Base register writeback.  */
>          if ((insn & (1 << rn)) == 0) {
> +            /* base reg not in list: base register writeback */
>              store_reg(s, rn, addr);
>          } else {
> +            /* base reg in list: if load, complete it now */
> +            if (insn & (1 << 11)) {
> +                store_reg(s, rn, loaded_var);
> +            }
>              tcg_temp_free_i32(addr);
>          }
>          break;
> -
> +    }
>      case 13:
>          /* conditional branch or swi */
>          cond = (insn >> 8) & 0xf;
> -- 
> 1.7.1
> 
> 
>

Patch

diff --git a/target-arm/translate.c b/target-arm/translate.c
index d8da514..a1af436 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -9454,7 +9454,10 @@  static void disas_thumb_insn(CPUState *env, DisasContext *s)
         break;
 
     case 12:
+    {
         /* load/store multiple */
+        TCGv loaded_var;
+        TCGV_UNUSED(loaded_var);
         rn = (insn >> 8) & 0x7;
         addr = load_reg(s, rn);
         for (i = 0; i < 8; i++) {
@@ -9462,7 +9465,11 @@  static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 if (insn & (1 << 11)) {
                     /* load */
                     tmp = gen_ld32(addr, IS_USER(s));
-                    store_reg(s, i, tmp);
+                    if (i == rn) {
+                        loaded_var = tmp;
+                    } else {
+                        store_reg(s, i, tmp);
+                    }
                 } else {
                     /* store */
                     tmp = load_reg(s, i);
@@ -9472,14 +9479,18 @@  static void disas_thumb_insn(CPUState *env, DisasContext *s)
                 tcg_gen_addi_i32(addr, addr, 4);
             }
         }
-        /* Base register writeback.  */
         if ((insn & (1 << rn)) == 0) {
+            /* base reg not in list: base register writeback */
             store_reg(s, rn, addr);
         } else {
+            /* base reg in list: if load, complete it now */
+            if (insn & (1 << 11)) {
+                store_reg(s, rn, loaded_var);
+            }
             tcg_temp_free_i32(addr);
         }
         break;
-
+    }
     case 13:
         /* conditional branch or swi */
         cond = (insn >> 8) & 0xf;