All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] ARM7TDMI emulation
@ 2007-07-02 13:27 Ulrich Hecht
  2007-07-02 13:40 ` Paul Brook
  0 siblings, 1 reply; 13+ messages in thread
From: Ulrich Hecht @ 2007-07-02 13:27 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 204 bytes --]

Hi!

This patch adds ARM7TDMI emulation with Thumb v1 (no BLX, no BKPT, ignore 
bit 0 on POP PC) and without CP15.

CU
Uli

-- 
SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nürnberg)

[-- Attachment #2: qemu-arm7tdmi.patch --]
[-- Type: text/x-diff, Size: 4341 bytes --]

Index: cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-arm/cpu.h,v
retrieving revision 1.28
diff -u -r1.28 cpu.h
--- cpu.h	24 Jun 2007 12:09:48 -0000	1.28
+++ cpu.h	2 Jul 2007 13:16:12 -0000
@@ -247,7 +247,9 @@
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
     ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
     ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
-    ARM_FEATURE_MPU     /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_MPU,    /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_THUMB1, /* Thumb v1 (ARM v4 with Thumb) */
+    ARM_FEATURE_NO_CP15 /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -262,6 +264,7 @@
                        ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
                        void *opaque);
 
+#define ARM_CPUID_ARM7TDMI  0x41807000 /* guess; no CP15 on ARM7TDMI */
 #define ARM_CPUID_ARM1026   0x4106a262
 #define ARM_CPUID_ARM926    0x41069265
 #define ARM_CPUID_ARM946    0x41059461
Index: helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-arm/helper.c,v
retrieving revision 1.17
diff -u -r1.17 helper.c
--- helper.c	24 Jun 2007 12:09:48 -0000	1.17
+++ helper.c	2 Jul 2007 13:16:12 -0000
@@ -14,6 +14,11 @@
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM7TDMI:
+        set_feature(env, ARM_FEATURE_THUMB1);
+        set_feature(env, ARM_FEATURE_NO_CP15);
+        /* no CP15 here */
+        break;
     case ARM_CPUID_ARM926:
         set_feature(env, ARM_FEATURE_VFP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
@@ -98,6 +103,7 @@
 };
 
 static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
Index: translate.c
===================================================================
RCS file: /sources/qemu/qemu/target-arm/translate.c,v
retrieving revision 1.53
diff -u -r1.53 translate.c
--- translate.c	11 Jun 2007 18:59:35 -0000	1.53
+++ translate.c	2 Jul 2007 13:16:13 -0000
@@ -1589,7 +1589,7 @@
     uint32_t rd;
 
     /* ??? Some cp15 registers are accessible from userspace.  */
-    if (IS_USER(s)) {
+    if (IS_USER(s) || arm_feature(env, ARM_FEATURE_NO_CP15)) {
         return 1;
     }
     if ((insn & 0x0fff0fff) == 0x0e070f90
@@ -2958,7 +2958,7 @@
     }
 }
 
-static void disas_thumb_insn(DisasContext *s)
+static void disas_thumb_insn(CPUState *env, DisasContext *s)
 {
     uint32_t val, insn, op, rm, rn, rd, shift, cond;
     int32_t offset;
@@ -3058,6 +3058,7 @@
                 break;
             case 3:/* branch [and link] exchange thumb register */
                 if (insn & (1 << 7)) {
+                    if(arm_feature(env, ARM_FEATURE_THUMB1)) goto undef;
                     val = (uint32_t)s->pc | 1;
                     gen_op_movl_T1_im(val);
                     gen_movl_reg_T1(s, 14);
@@ -3367,11 +3368,16 @@
             /* write back the new stack pointer */
             gen_movl_reg_T1(s, 13);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s);
+            if ((insn & 0x0900) == 0x0900) {
+                if(arm_feature(env, ARM_FEATURE_THUMB1))
+                  gen_movl_reg_T0(s, 15);
+                else
+                  gen_bx(s);
+            }
             break;
 
         case 0xe: /* bkpt */
+            if(arm_feature(env, ARM_FEATURE_THUMB1)) goto undef;
             gen_op_movl_T0_im((long)s->pc - 2);
             gen_op_movl_reg_TN[0][15]();
             gen_op_bkpt();
@@ -3442,6 +3448,7 @@
         /* unconditional branch */
         if (insn & (1 << 11)) {
             /* Second half of blx.  */
+            if(arm_feature(env, ARM_FEATURE_THUMB1)) goto undef;
             offset = ((insn & 0x7ff) << 1);
             gen_movl_T0_reg(s, 14);
             gen_op_movl_T1_im(offset);
@@ -3571,7 +3578,7 @@
         }
 
         if (env->thumb)
-          disas_thumb_insn(dc);
+          disas_thumb_insn(env, dc);
         else
           disas_arm_insn(env, dc);
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2007-07-02 13:27 [Qemu-devel] [PATCH] ARM7TDMI emulation Ulrich Hecht
@ 2007-07-02 13:40 ` Paul Brook
  2007-07-02 16:14   ` Ulrich Hecht
  0 siblings, 1 reply; 13+ messages in thread
From: Paul Brook @ 2007-07-02 13:40 UTC (permalink / raw)
  To: qemu-devel

On Monday 02 July 2007, Ulrich Hecht wrote:
> Hi!
>
> This patch adds ARM7TDMI emulation with Thumb v1 (no BLX, no BKPT, ignore
> bit 0 on POP PC) and without CP15.

ARM_FEATURE_THUMB1 is a bad name for this. Thumb-1 covers both v4t and v5t. 
Thumb-2 is a completely new architecture revision which adds 32-bit 
instructions. 

You should add/use ARM_FEATURE_V5/ARCH(5) instead.

For added confusion some older documentation refers to v5t as "thumb2", or the 
second revision of the Thumb ISA. This should be ignored :-)

The ARM7TDMI implements the base updated abort model. You should either 
implement that, or pick a core (eg. 920t) that uses the base restored abort 
model.

Paul

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2007-07-02 13:40 ` Paul Brook
@ 2007-07-02 16:14   ` Ulrich Hecht
  2007-07-03 14:45     ` Ulrich Hecht
  0 siblings, 1 reply; 13+ messages in thread
From: Ulrich Hecht @ 2007-07-02 16:14 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 417 bytes --]

On Monday 02 July 2007 15:40, Paul Brook wrote:
> You should add/use ARM_FEATURE_V5/ARCH(5) instead.

Alright.

> The ARM7TDMI implements the base updated abort model.

Er, yes, but there is no MMU that could actually cause an abort, right?

Anyway, here's the 920T version. The magic numbers may or may not be 
correct.

CU
Uli

-- 
SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nürnberg)

[-- Attachment #2: qemu-arm920t.patch --]
[-- Type: text/x-diff, Size: 5758 bytes --]

Index: target-arm/cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-arm/cpu.h,v
retrieving revision 1.28
diff -u -r1.28 cpu.h
--- target-arm/cpu.h	24 Jun 2007 12:09:48 -0000	1.28
+++ target-arm/cpu.h	2 Jul 2007 15:09:41 -0000
@@ -247,7 +247,9 @@
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
     ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
     ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
-    ARM_FEATURE_MPU     /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_MPU,    /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_V5,     /* ARM v5 instruction set */
+    ARM_FEATURE_NO_CP15 /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -262,7 +264,9 @@
                        ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
                        void *opaque);
 
+#define ARM_CPUID_ARM7TDMI  0x41807000 /* guess; no CP15 on ARM7TDMI */
 #define ARM_CPUID_ARM1026   0x4106a262
+#define ARM_CPUID_ARM920T   0x41129200
 #define ARM_CPUID_ARM926    0x41069265
 #define ARM_CPUID_ARM946    0x41059461
 #define ARM_CPUID_PXA250    0x69052100
Index: target-arm/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-arm/helper.c,v
retrieving revision 1.17
diff -u -r1.17 helper.c
--- target-arm/helper.c	24 Jun 2007 12:09:48 -0000	1.17
+++ target-arm/helper.c	2 Jul 2007 15:09:41 -0000
@@ -14,20 +14,27 @@
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM920T:
+        env->cp15.c0_cachetype = 0x0d172172;
+        env->cp15.c1_sys = 0x00000078;
+        break;
     case ARM_CPUID_ARM926:
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_V5);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
         set_feature(env, ARM_FEATURE_MPU);
+        set_feature(env, ARM_FEATURE_V5);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_V5);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
@@ -38,6 +45,7 @@
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
         set_feature(env, ARM_FEATURE_XSCALE);
+        set_feature(env, ARM_FEATURE_V5);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
@@ -49,6 +57,7 @@
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
         set_feature(env, ARM_FEATURE_XSCALE);
+        set_feature(env, ARM_FEATURE_V5);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         set_feature(env, ARM_FEATURE_IWMMXT);
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
@@ -98,6 +107,7 @@
 };
 
 static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM920T, "arm920t"},
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
Index: target-arm/translate.c
===================================================================
RCS file: /sources/qemu/qemu/target-arm/translate.c,v
retrieving revision 1.53
diff -u -r1.53 translate.c
--- target-arm/translate.c	11 Jun 2007 18:59:35 -0000	1.53
+++ target-arm/translate.c	2 Jul 2007 15:09:41 -0000
@@ -1589,7 +1589,7 @@
     uint32_t rd;
 
     /* ??? Some cp15 registers are accessible from userspace.  */
-    if (IS_USER(s)) {
+    if (IS_USER(s) || arm_feature(env, ARM_FEATURE_NO_CP15)) {
         return 1;
     }
     if ((insn & 0x0fff0fff) == 0x0e070f90
@@ -2958,7 +2958,7 @@
     }
 }
 
-static void disas_thumb_insn(DisasContext *s)
+static void disas_thumb_insn(CPUState *env, DisasContext *s)
 {
     uint32_t val, insn, op, rm, rn, rd, shift, cond;
     int32_t offset;
@@ -3058,6 +3058,7 @@
                 break;
             case 3:/* branch [and link] exchange thumb register */
                 if (insn & (1 << 7)) {
+                    if(!arm_feature(env, ARM_FEATURE_V5)) goto undef;
                     val = (uint32_t)s->pc | 1;
                     gen_op_movl_T1_im(val);
                     gen_movl_reg_T1(s, 14);
@@ -3367,11 +3368,16 @@
             /* write back the new stack pointer */
             gen_movl_reg_T1(s, 13);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s);
+            if ((insn & 0x0900) == 0x0900) {
+                if(!arm_feature(env, ARM_FEATURE_V5))
+                  gen_movl_reg_T0(s, 15);
+                else
+                  gen_bx(s);
+            }
             break;
 
         case 0xe: /* bkpt */
+            if(!arm_feature(env, ARM_FEATURE_V5)) goto undef;
             gen_op_movl_T0_im((long)s->pc - 2);
             gen_op_movl_reg_TN[0][15]();
             gen_op_bkpt();
@@ -3442,6 +3448,7 @@
         /* unconditional branch */
         if (insn & (1 << 11)) {
             /* Second half of blx.  */
+            if(!arm_feature(env, ARM_FEATURE_V5)) goto undef;
             offset = ((insn & 0x7ff) << 1);
             gen_movl_T0_reg(s, 14);
             gen_op_movl_T1_im(offset);
@@ -3571,7 +3578,7 @@
         }
 
         if (env->thumb)
-          disas_thumb_insn(dc);
+          disas_thumb_insn(env, dc);
         else
           disas_arm_insn(env, dc);
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2007-07-02 16:14   ` Ulrich Hecht
@ 2007-07-03 14:45     ` Ulrich Hecht
  2009-06-15 19:11       ` Filip Navara
  0 siblings, 1 reply; 13+ messages in thread
From: Ulrich Hecht @ 2007-07-03 14:45 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 323 bytes --]

On Monday 02 July 2007 18:14, Ulrich Hecht wrote:
> Anyway, here's the 920T version. The magic numbers may or may not be
> correct.

And here's an even better version that implements both 920T and 7TDMI 
(with base-updated aborts).

CU
Uli

-- 
SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nürnberg)

[-- Attachment #2: qemu-arm7tdmi920t.patch --]
[-- Type: text/x-diff, Size: 10154 bytes --]

Index: target-arm/cpu.h
===================================================================
RCS file: /sources/qemu/qemu/target-arm/cpu.h,v
retrieving revision 1.28
diff -u -r1.28 cpu.h
--- target-arm/cpu.h	24 Jun 2007 12:09:48 -0000	1.28
+++ target-arm/cpu.h	3 Jul 2007 14:36:00 -0000
@@ -247,7 +247,10 @@
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
     ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
     ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
-    ARM_FEATURE_MPU     /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_MPU,    /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_V5,     /* ARM v5 instruction set */
+    ARM_FEATURE_NO_CP15, /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
+    ARM_FEATURE_ABORT_BU /* base updated abort model, e.g. ARMxTDMI */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -262,7 +265,9 @@
                        ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
                        void *opaque);
 
+#define ARM_CPUID_ARM7TDMI  0x41807000 /* guess; no CP15 on ARM7TDMI */
 #define ARM_CPUID_ARM1026   0x4106a262
+#define ARM_CPUID_ARM920T   0x41129200
 #define ARM_CPUID_ARM926    0x41069265
 #define ARM_CPUID_ARM946    0x41059461
 #define ARM_CPUID_PXA250    0x69052100
Index: target-arm/helper.c
===================================================================
RCS file: /sources/qemu/qemu/target-arm/helper.c,v
retrieving revision 1.17
diff -u -r1.17 helper.c
--- target-arm/helper.c	24 Jun 2007 12:09:48 -0000	1.17
+++ target-arm/helper.c	3 Jul 2007 14:36:00 -0000
@@ -14,20 +14,31 @@
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM7TDMI:
+        set_feature(env, ARM_FEATURE_ABORT_BU);
+        set_feature(env, ARM_FEATURE_NO_CP15);
+        break;
+    case ARM_CPUID_ARM920T:
+        env->cp15.c0_cachetype = 0x0d172172;
+        env->cp15.c1_sys = 0x00000078;
+        break;
     case ARM_CPUID_ARM926:
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_V5);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
         set_feature(env, ARM_FEATURE_MPU);
+        set_feature(env, ARM_FEATURE_V5);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
         set_feature(env, ARM_FEATURE_VFP);
         set_feature(env, ARM_FEATURE_AUXCR);
+        set_feature(env, ARM_FEATURE_V5);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
@@ -38,6 +49,7 @@
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
         set_feature(env, ARM_FEATURE_XSCALE);
+        set_feature(env, ARM_FEATURE_V5);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
@@ -49,6 +61,7 @@
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
         set_feature(env, ARM_FEATURE_XSCALE);
+        set_feature(env, ARM_FEATURE_V5);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         set_feature(env, ARM_FEATURE_IWMMXT);
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
@@ -98,6 +111,8 @@
 };
 
 static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
+    { ARM_CPUID_ARM920T, "arm920t"},
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
Index: target-arm/translate.c
===================================================================
RCS file: /sources/qemu/qemu/target-arm/translate.c,v
retrieving revision 1.53
diff -u -r1.53 translate.c
--- target-arm/translate.c	11 Jun 2007 18:59:35 -0000	1.53
+++ target-arm/translate.c	3 Jul 2007 14:36:00 -0000
@@ -1589,7 +1589,7 @@
     uint32_t rd;
 
     /* ??? Some cp15 registers are accessible from userspace.  */
-    if (IS_USER(s)) {
+    if (IS_USER(s) || arm_feature(env, ARM_FEATURE_NO_CP15)) {
         return 1;
     }
     if ((insn & 0x0fff0fff) == 0x0e070f90
@@ -2780,6 +2780,7 @@
         case 0x09:
             {
                 int j, n, user, loaded_base;
+                int crement;
                 /* load/store multiple words */
                 /* XXX: store correct base if write back */
                 user = 0;
@@ -2819,6 +2820,36 @@
                     }
                 }
                 j = 0;
+
+                crement = 0;
+                if(insn & (1 << 21)) {
+                    /* write back */
+                    if(insn & (1 << 23)) {
+                        if(insn & (1 << 24)) {
+                            /* pre increment */
+                        } else {
+                            /* post increment */
+                          crement += 4;
+                        }
+                    } else {
+                        if(insn & (1 << 24)) {
+                            /* pre decrement */
+                            if(n!=1) crement -= (n-1)*4;
+                        } else {
+                            /* post decrement */
+                            crement -= n*4;
+                        }
+                    }
+                    if(arm_feature(env, ARM_FEATURE_ABORT_BU)) {
+                        /* base-updated abort model: update base register
+                           before an abort can happen */
+                        crement += (n - 1) * 4;
+                        gen_op_addl_T1_im(crement);
+                        gen_movl_reg_T1(s, rn);
+                        gen_op_addl_T1_im(-crement);
+                    }
+                }
+
                 for(i=0;i<16;i++) {
                     if (insn & (1 << i)) {
                         if (insn & (1 << 20)) {
@@ -2853,25 +2884,10 @@
                             gen_op_addl_T1_im(4);
                     }
                 }
-                if (insn & (1 << 21)) {
-                    /* write back */
-                    if (insn & (1 << 23)) {
-                        if (insn & (1 << 24)) {
-                            /* pre increment */
-                        } else {
-                            /* post increment */
-                            gen_op_addl_T1_im(4);
-                        }
-                    } else {
-                        if (insn & (1 << 24)) {
-                            /* pre decrement */
-                            if (n != 1)
-                                gen_op_addl_T1_im(-((n - 1) * 4));
-                        } else {
-                            /* post decrement */
-                            gen_op_addl_T1_im(-(n * 4));
-                        }
-                    }
+                if(!loaded_base && (insn & (1 << 21)) && !arm_feature(env, ARM_FEATURE_ABORT_BU)) {
+                    /* base-restored abort model: only update base register
+                       after all memory accesses went through */
+                    gen_op_addl_T1_im(crement);
                     gen_movl_reg_T1(s, rn);
                 }
                 if (loaded_base) {
@@ -2958,11 +2974,12 @@
     }
 }
 
-static void disas_thumb_insn(DisasContext *s)
+static void disas_thumb_insn(CPUState *env, DisasContext *s)
 {
     uint32_t val, insn, op, rm, rn, rd, shift, cond;
     int32_t offset;
     int i;
+    int crement;
 
     insn = lduw_code(s->pc);
     s->pc += 2;
@@ -3058,6 +3075,7 @@
                 break;
             case 3:/* branch [and link] exchange thumb register */
                 if (insn & (1 << 7)) {
+                    if(!arm_feature(env, ARM_FEATURE_V5)) goto undef;
                     val = (uint32_t)s->pc | 1;
                     gen_op_movl_T1_im(val);
                     gen_movl_reg_T1(s, 14);
@@ -3367,11 +3385,16 @@
             /* write back the new stack pointer */
             gen_movl_reg_T1(s, 13);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s);
+            if ((insn & 0x0900) == 0x0900) {
+                if(!arm_feature(env, ARM_FEATURE_V5))
+                  gen_movl_reg_T0(s, 15);
+                else
+                  gen_bx(s);
+            }
             break;
 
         case 0xe: /* bkpt */
+            if(!arm_feature(env, ARM_FEATURE_V5)) goto undef;
             gen_op_movl_T0_im((long)s->pc - 2);
             gen_op_movl_reg_TN[0][15]();
             gen_op_bkpt();
@@ -3387,6 +3410,17 @@
         /* load/store multiple */
         rn = (insn >> 8) & 0x7;
         gen_movl_T1_reg(s, rn);
+        crement = 0;
+        for (i = 0; i < 8; i++) {
+            if (insn & (1 << i)) crement += 4;
+        }
+        if(arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
+            /* base-updated abort model: update base register
+               before an abort can happen */
+            gen_op_addl_T1_im(crement);
+            gen_movl_reg_T1(s, rn);
+            gen_op_addl_T1_im(-crement);
+        }
         gen_op_movl_T2_im(4);
         for (i = 0; i < 8; i++) {
             if (insn & (1 << i)) {
@@ -3403,8 +3437,8 @@
                 gen_op_addl_T1_T2();
             }
         }
-        /* Base register writeback.  */
-        if ((insn & (1 << rn)) == 0)
+        /* Base register writeback, base-restored abort model  */
+        if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0)
             gen_movl_reg_T1(s, rn);
         break;
 
@@ -3442,6 +3476,7 @@
         /* unconditional branch */
         if (insn & (1 << 11)) {
             /* Second half of blx.  */
+            if(!arm_feature(env, ARM_FEATURE_V5)) goto undef;
             offset = ((insn & 0x7ff) << 1);
             gen_movl_T0_reg(s, 14);
             gen_op_movl_T1_im(offset);
@@ -3571,7 +3606,7 @@
         }
 
         if (env->thumb)
-          disas_thumb_insn(dc);
+          disas_thumb_insn(env, dc);
         else
           disas_arm_insn(env, dc);
 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2007-07-03 14:45     ` Ulrich Hecht
@ 2009-06-15 19:11       ` Filip Navara
  2009-06-16 17:25         ` Paul Brook
  0 siblings, 1 reply; 13+ messages in thread
From: Filip Navara @ 2009-06-15 19:11 UTC (permalink / raw)
  To: qemu-devel; +Cc: paul


[-- Attachment #1.1: Type: text/plain, Size: 731 bytes --]

On Tue, Jul 3, 2007 at 4:45 PM, Ulrich Hecht <uli@suse.de> wrote:

> On Monday 02 July 2007 18:14, Ulrich Hecht wrote:
> > Anyway, here's the 920T version. The magic numbers may or may not be
> > correct.
>
> And here's an even better version that implements both 920T and 7TDMI
> (with base-updated aborts).
>
> CU
> Uli
>
> --
> SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nürnberg)
>

Hello,

this is a rewritten version of the original patch to work on the latest qemu
git. Anything that needs to be done to get this merged?

ARM7TDMI emulation (ignore bit 0 on POP PC, no BLX, no CP15, base-updated
data aborts).
Based on patch by Ulrich Hecht <uli@suse.de>.

Best regards,
Filip Navara

[-- Attachment #1.2: Type: text/html, Size: 1232 bytes --]

[-- Attachment #2: 0001-ARM7TDMI-emulation-ignore-bit-0-on-POP-PC-no-BLX-no-.patch --]
[-- Type: application/octet-stream, Size: 13064 bytes --]

From b49a01d876d65d9ef456ebbcd8ac219e6d49ab0a Mon Sep 17 00:00:00 2001
From: Filip Navara <filip.navara@gmail.com>
Date: Mon, 15 Jun 2009 21:05:19 +0200
Subject: [PATCH] ARM7TDMI emulation (ignore bit 0 on POP PC, no BLX, no CP15, base-updated data aborts).
 Based on patch by Ulrich Hecht <uli@suse.de>.

---
 target-arm/cpu.h       |    6 +++-
 target-arm/helper.c    |   24 +++++++++++++
 target-arm/translate.c |   87 ++++++++++++++++++++++++++++++++++-------------
 3 files changed, 92 insertions(+), 25 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f98655f..d004777 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -331,6 +331,7 @@ enum arm_features {
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
     ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
     ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
+    ARM_FEATURE_V5,
     ARM_FEATURE_V6,
     ARM_FEATURE_V6K,
     ARM_FEATURE_V7,
@@ -341,7 +342,9 @@ enum arm_features {
     ARM_FEATURE_DIV,
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
-    ARM_FEATURE_THUMB2EE
+    ARM_FEATURE_THUMB2EE,
+    ARM_FEATURE_CP15, /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
+    ARM_FEATURE_ABORT_BU /* base updated abort model, e.g. ARMxTDMI */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -367,6 +370,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define IS_M(env) arm_feature(env, ARM_FEATURE_M)
 #define ARM_CPUID(env) (env->cp15.c0_cpuid)
 
+#define ARM_CPUID_ARM7TDMI    0x41807000 /* guess; no CP15 on ARM7TDMI */
 #define ARM_CPUID_ARM1026     0x4106a262
 #define ARM_CPUID_ARM926      0x41069265
 #define ARM_CPUID_ARM946      0x41059461
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 701629a..38875d4 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -37,19 +37,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM7TDMI:
+        set_feature(env, ARM_FEATURE_ABORT_BU);
+        break;
     case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_MPU);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
@@ -57,8 +66,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -68,9 +79,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_ARM11MPCORE:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -80,9 +93,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_VFP);
@@ -101,6 +116,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXM3:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_V7);
@@ -108,6 +124,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_DIV);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
@@ -120,6 +137,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_OMAPCP);
         env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
         env->cp15.c0_cachetype = 0x5109149;
@@ -132,6 +151,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA260:
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
@@ -143,6 +164,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         set_feature(env, ARM_FEATURE_IWMMXT);
@@ -277,6 +300,7 @@ struct arm_cpu_t {
 };
 
 static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
diff --git a/target-arm/translate.c b/target-arm/translate.c
index adac19a..c1d908c 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2596,8 +2596,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
     TCGv tmp;
 
     /* M profile cores use memory mapped registers instead of cp15.  */
-    if (arm_feature(env, ARM_FEATURE_M))
-	return 1;
+    if (arm_feature(env, ARM_FEATURE_M) ||
+        !arm_feature(env, ARM_FEATURE_CP15)) {
+	    return 1;
+    }
 
     if ((insn & (1 << 25)) == 0) {
         if (insn & (1 << 20)) {
@@ -6786,6 +6788,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x09:
             {
                 int j, n, user, loaded_base;
+                int crement = 0;
                 TCGv loaded_var;
                 /* load/store multiple words */
                 /* XXX: store correct base if write back */
@@ -6826,6 +6829,37 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
                     }
                 }
+
+                if (insn & (1 << 21)) {
+                    /* write back */
+                    if (insn & (1 << 23)) {
+                        if (insn & (1 << 24)) {
+                            /* pre increment */
+                        } else {
+                            /* post increment */
+                            crement = 4;
+                        }
+                    } else {
+                        if (insn & (1 << 24)) {
+                            /* pre decrement */
+                            if (n != 1) {
+                                crement = -((n - 1) * 4);
+                            }
+                        } else {
+                            /* post decrement */
+                            crement = -(n * 4);
+                        }
+                    }
+                    if (arm_feature(env, ARM_FEATURE_ABORT_BU)) {
+                        /* base-updated abort model: update base register
+                           before an abort can happen */
+                        crement += (n - 1) * 4;
+                        tmp = new_tmp();
+                        tcg_gen_addi_i32(tmp, addr, crement);
+                        store_reg(s, rn, tmp);
+                    }
+                }
+
                 j = 0;
                 for(i=0;i<16;i++) {
                     if (insn & (1 << i)) {
@@ -6864,25 +6898,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             tcg_gen_addi_i32(addr, addr, 4);
                     }
                 }
-                if (insn & (1 << 21)) {
-                    /* write back */
-                    if (insn & (1 << 23)) {
-                        if (insn & (1 << 24)) {
-                            /* pre increment */
-                        } else {
-                            /* post increment */
-                            tcg_gen_addi_i32(addr, addr, 4);
-                        }
-                    } else {
-                        if (insn & (1 << 24)) {
-                            /* pre decrement */
-                            if (n != 1)
-                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
-                        } else {
-                            /* post decrement */
-                            tcg_gen_addi_i32(addr, addr, -(n * 4));
-                        }
-                    }
+                if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << 21))) {
+                    tcg_gen_addi_i32(addr, addr, crement);
                     store_reg(s, rn, addr);
                 } else {
                     dead_tmp(addr);
@@ -8050,6 +8067,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
     TCGv tmp;
     TCGv tmp2;
     TCGv addr;
+    int crement;
 
     if (s->condexec_mask) {
         cond = s->condexec_cond;
@@ -8171,6 +8189,9 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             case 3:/* branch [and link] exchange thumb register */
                 tmp = load_reg(s, rm);
                 if (insn & (1 << 7)) {
+                    if (!arm_feature(env, ARM_FEATURE_V5)) {
+                        goto undef;
+                    }
                     val = (uint32_t)s->pc | 1;
                     tmp2 = new_tmp();
                     tcg_gen_movi_i32(tmp2, val);
@@ -8523,8 +8544,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             /* write back the new stack pointer */
             store_reg(s, 13, addr);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s, tmp);
+            if ((insn & 0x0900) == 0x0900) {
+                if (!arm_feature(env, ARM_FEATURE_V5)) {
+                    store_cpu_field(tmp, regs[15]);
+                } else {
+                    gen_bx(s, tmp);
+                }
+            }
             break;
 
         case 1: case 3: case 9: case 11: /* czb */
@@ -8613,6 +8639,19 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         /* load/store multiple */
         rn = (insn >> 8) & 0x7;
         addr = load_reg(s, rn);
+        if (arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
+            /* base-updated abort model: update base register
+               before an abort can happen */
+            crement = 0;
+            for (i = 0; i < 8; i++) {
+                if (insn & (1 << i)) {
+                    crement += 4;
+                }
+            }
+            tmp = new_tmp();
+            tcg_gen_addi_i32(tmp, addr, crement);
+            store_reg(s, rn, tmp);
+        }
         for (i = 0; i < 8; i++) {
             if (insn & (1 << i)) {
                 if (insn & (1 << 11)) {
@@ -8629,7 +8668,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             }
         }
         /* Base register writeback.  */
-        if ((insn & (1 << rn)) == 0) {
+        if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
             store_reg(s, rn, addr);
         } else {
             dead_tmp(addr);
-- 
1.6.3.msysgit.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-15 19:11       ` Filip Navara
@ 2009-06-16 17:25         ` Paul Brook
  2009-06-16 19:02           ` Jamie Lokier
  0 siblings, 1 reply; 13+ messages in thread
From: Paul Brook @ 2009-06-16 17:25 UTC (permalink / raw)
  To: qemu-devel; +Cc: Filip Navara

> this is a rewritten version of the original patch to work on the latest
> qemu git. Anything that needs to be done to get this merged?

You're missing quite a few bits here. For example load pc should do the same 
as pop pc, and there are many other instructions that aren't valid on 
v5t/v5te. See the recent arm920t patches (and corresponding discussion).

Paul

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-16 17:25         ` Paul Brook
@ 2009-06-16 19:02           ` Jamie Lokier
  2009-06-16 19:05             ` Paul Brook
  2009-06-16 20:49             ` Filip Navara
  0 siblings, 2 replies; 13+ messages in thread
From: Jamie Lokier @ 2009-06-16 19:02 UTC (permalink / raw)
  To: Paul Brook; +Cc: Filip Navara, qemu-devel

Paul Brook wrote:
> > this is a rewritten version of the original patch to work on the latest
> > qemu git. Anything that needs to be done to get this merged?
> 
> You're missing quite a few bits here. For example load pc should do the same 
> as pop pc, and there are many other instructions that aren't valid on 
> v5t/v5te. See the recent arm920t patches (and corresponding discussion).

I'm thinking of adding ARMv4 (not v4T) support, so I can test that
code needing to run on a real ARMv4 does not accidentally have any
unsupported instructions.

While looking into that, I found it quite difficult to find which
instructions are supported by different ARM architecture levels, and
especially how PC is treated by different instructions on the
different architectures.

Do you know of a good summary reference which lists which instructions
are available in each ARM architecture level from ARMv4 up to ARMv7
and it's variants?

(Preferably without an ARM licensing agreement or NDA).

-- Jamie

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-16 19:02           ` Jamie Lokier
@ 2009-06-16 19:05             ` Paul Brook
  2009-06-16 20:49             ` Filip Navara
  1 sibling, 0 replies; 13+ messages in thread
From: Paul Brook @ 2009-06-16 19:05 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Filip Navara, qemu-devel

> Do you know of a good summary reference which lists which instructions
> are available in each ARM architecture level from ARMv4 up to ARMv7
> and it's variants?

Other than the details I've already sent to this list, no.

Paul

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-16 19:02           ` Jamie Lokier
  2009-06-16 19:05             ` Paul Brook
@ 2009-06-16 20:49             ` Filip Navara
  2009-06-16 21:47               ` Filip Navara
  2009-06-17  9:55               ` Filip Navara
  1 sibling, 2 replies; 13+ messages in thread
From: Filip Navara @ 2009-06-16 20:49 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Paul Brook, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 733 bytes --]

>
> Do you know of a good summary reference which lists which instructions
> are available in each ARM architecture level from ARMv4 up to ARMv7
> and it's variants?
>

My main reference are the technical reference manuals for ARM processors
downloaded from Atmel site. I'm not sure about the license, but it states
"This document is Open Access. This document has no restriction on
distribution." Other reference sources are Skyeye emulation (has to be taken
with grain of salt and checked against the manuals, but it makes distinction
between v4, v5 and v5e) and Paul Brook.

I've certainly missed handling BLX (at least on three places) in the patch
and possibly more. I'll post an updated patch soon.

Best regards,
Filip Navara

[-- Attachment #2: Type: text/html, Size: 1015 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-16 20:49             ` Filip Navara
@ 2009-06-16 21:47               ` Filip Navara
  2009-06-17  9:55               ` Filip Navara
  1 sibling, 0 replies; 13+ messages in thread
From: Filip Navara @ 2009-06-16 21:47 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Paul Brook, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1603 bytes --]

On Tue, Jun 16, 2009 at 10:49 PM, Filip Navara <filip.navara@gmail.com>wrote:

> Do you know of a good summary reference which lists which instructions
>>  are available in each ARM architecture level from ARMv4 up to ARMv7
>> and it's variants?
>>
>
> My main reference are the technical reference manuals for ARM processors
> downloaded from Atmel site. I'm not sure about the license, but it states
> "This document is Open Access. This document has no restriction on
> distribution." Other reference sources are Skyeye emulation (has to be taken
> with grain of salt and checked against the manuals, but it makes distinction
> between v4, v5 and v5e) and Paul Brook.
>
> I've certainly missed handling BLX (at least on three places) in the patch
> and possibly more. I'll post an updated patch soon.
>

The list may not be complete, but this is what I compiled from various
sources, including ARM official documentation. For the ARMv4t emulation I'd
need to do the following:

- Treat CDP2, LDC2, STC2, BLX, MRC2, MCR2, MCRR, SMUL, SMLA, SMULW,
SMLAW, SMLAL, QADD, QSUB, QDADD, QDSUB, BKPT, 64-bit LDR/STR, PLD as
undefined instructions.
- Do not change to/from Thumb mode on LDR/LDM/POP to r15 depending on the
bit 0 of the value.
- Add the base updated data-abort model.

Other changes between ARMv5 and ARMv4 include:

- MULS, MLAS corrupt C flag
- UMULLS, UMLALS, SMULLS and SMLALS corrupt the C and V flags

I don't plan to implement corrupting the flags. Implementing ARMv4 instead
of ARMv4t would then be matter of disabling the BX instruction. Anything I
missed?

Best regards,
Filip Navara

[-- Attachment #2: Type: text/html, Size: 2320 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-16 20:49             ` Filip Navara
  2009-06-16 21:47               ` Filip Navara
@ 2009-06-17  9:55               ` Filip Navara
  2009-06-17 10:24                 ` Filip Navara
  1 sibling, 1 reply; 13+ messages in thread
From: Filip Navara @ 2009-06-17  9:55 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Paul Brook, qemu-devel

[-- Attachment #1: Type: text/plain, Size: 1035 bytes --]

On Tue, Jun 16, 2009 at 10:49 PM, Filip Navara <filip.navara@gmail.com>wrote:

> Do you know of a good summary reference which lists which instructions
>>  are available in each ARM architecture level from ARMv4 up to ARMv7
>> and it's variants?
>>
>
> My main reference are the technical reference manuals for ARM processors
> downloaded from Atmel site. I'm not sure about the license, but it states
> "This document is Open Access. This document has no restriction on
> distribution." Other reference sources are Skyeye emulation (has to be taken
> with grain of salt and checked against the manuals, but it makes distinction
> between v4, v5 and v5e) and Paul Brook.
>
> I've certainly missed handling BLX (at least on three places) in the patch
> and possibly more. I'll post an updated patch soon.
>

... and here's the updated patch. Comments welcome.

I've added more checks for V5+ instructions and fixed about every LDR/LDM
place I found to not call gen_bx to set r15.

Best regards,
Filip Navara

Best regards,
Filip Navara

[-- Attachment #2: Type: text/html, Size: 1630 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Qemu-devel] [PATCH] ARM7TDMI emulation
  2009-06-17  9:55               ` Filip Navara
@ 2009-06-17 10:24                 ` Filip Navara
  0 siblings, 0 replies; 13+ messages in thread
From: Filip Navara @ 2009-06-17 10:24 UTC (permalink / raw)
  To: Jamie Lokier; +Cc: Paul Brook, qemu-devel


[-- Attachment #1.1: Type: text/plain, Size: 1166 bytes --]

On Wed, Jun 17, 2009 at 11:55 AM, Filip Navara <filip.navara@gmail.com>wrote:

> On Tue, Jun 16, 2009 at 10:49 PM, Filip Navara <filip.navara@gmail.com>wrote:
>
>> Do you know of a good summary reference which lists which instructions
>>>  are available in each ARM architecture level from ARMv4 up to ARMv7
>>> and it's variants?
>>>
>>
>> My main reference are the technical reference manuals for ARM processors
>> downloaded from Atmel site. I'm not sure about the license, but it states
>> "This document is Open Access. This document has no restriction on
>> distribution." Other reference sources are Skyeye emulation (has to be taken
>> with grain of salt and checked against the manuals, but it makes distinction
>> between v4, v5 and v5e) and Paul Brook.
>>
>> I've certainly missed handling BLX (at least on three places) in the patch
>> and possibly more. I'll post an updated patch soon.
>>
>
> ... and here's the updated patch. Comments welcome.
>
> I've added more checks for V5+ instructions and fixed about every LDR/LDM
> place I found to not call gen_bx to set r15.
>
> Best regards,
> Filip Navara
>

Damn it, forgot to attach it. Thanks Laurent!

[-- Attachment #1.2: Type: text/html, Size: 2018 bytes --]

[-- Attachment #2: 0001-ARM7TDMI-emulation-ignore-bit-0-on-POP-PC-no-BLX-no-.patch --]
[-- Type: application/octet-stream, Size: 18442 bytes --]

From e4ad4939178a464d50edcbdf7f1faa98e3e9cc3a Mon Sep 17 00:00:00 2001
From: Filip Navara <filip.navara@gmail.com>
Date: Mon, 15 Jun 2009 21:05:19 +0200
Subject: [PATCH] ARM7TDMI emulation (ignore bit 0 on POP PC, no BLX, no CP15, base-updated data aborts). Based on patch by Ulrich Hecht <uli@suse.de>.

---
 target-arm/cpu.h       |    6 ++-
 target-arm/helper.c    |   24 ++++++++++
 target-arm/translate.c |  116 ++++++++++++++++++++++++++++++++++--------------
 3 files changed, 112 insertions(+), 34 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f98655f..d004777 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -331,6 +331,7 @@ enum arm_features {
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
     ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
     ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
+    ARM_FEATURE_V5,
     ARM_FEATURE_V6,
     ARM_FEATURE_V6K,
     ARM_FEATURE_V7,
@@ -341,7 +342,9 @@ enum arm_features {
     ARM_FEATURE_DIV,
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
-    ARM_FEATURE_THUMB2EE
+    ARM_FEATURE_THUMB2EE,
+    ARM_FEATURE_CP15, /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
+    ARM_FEATURE_ABORT_BU /* base updated abort model, e.g. ARMxTDMI */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -367,6 +370,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define IS_M(env) arm_feature(env, ARM_FEATURE_M)
 #define ARM_CPUID(env) (env->cp15.c0_cpuid)
 
+#define ARM_CPUID_ARM7TDMI    0x41807000 /* guess; no CP15 on ARM7TDMI */
 #define ARM_CPUID_ARM1026     0x4106a262
 #define ARM_CPUID_ARM926      0x41069265
 #define ARM_CPUID_ARM946      0x41059461
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 701629a..38875d4 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -37,19 +37,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM7TDMI:
+        set_feature(env, ARM_FEATURE_ABORT_BU);
+        break;
     case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_MPU);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
@@ -57,8 +66,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -68,9 +79,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_ARM11MPCORE:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -80,9 +93,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_VFP);
@@ -101,6 +116,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXM3:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_V7);
@@ -108,6 +124,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_DIV);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
@@ -120,6 +137,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_OMAPCP);
         env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
         env->cp15.c0_cachetype = 0x5109149;
@@ -132,6 +151,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA260:
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
@@ -143,6 +164,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         set_feature(env, ARM_FEATURE_IWMMXT);
@@ -277,6 +300,7 @@ struct arm_cpu_t {
 };
 
 static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
diff --git a/target-arm/translate.c b/target-arm/translate.c
index adac19a..8c601b1 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -35,9 +35,10 @@
 #define GEN_HELPER 1
 #include "helpers.h"
 
+#define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
 #define ENABLE_ARCH_5J    0
 #define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
-#define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
+#define ENABLE_ARCH_6K    arm_feature(env, ARM_FEATURE_V6K)
 #define ENABLE_ARCH_6T2   arm_feature(env, ARM_FEATURE_THUMB2)
 #define ENABLE_ARCH_7     arm_feature(env, ARM_FEATURE_V7)
 
@@ -2596,8 +2597,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
     TCGv tmp;
 
     /* M profile cores use memory mapped registers instead of cp15.  */
-    if (arm_feature(env, ARM_FEATURE_M))
-	return 1;
+    if (arm_feature(env, ARM_FEATURE_M) ||
+        !arm_feature(env, ARM_FEATURE_CP15)) {
+	    return 1;
+    }
 
     if ((insn & (1 << 25)) == 0) {
         if (insn & (1 << 20)) {
@@ -5754,9 +5757,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 goto illegal_op;
             return;
         }
-        if ((insn & 0x0d70f000) == 0x0550f000)
+        if ((insn & 0x0d70f000) == 0x0550f000) {
+            ARCH(5);
             return; /* PLD */
-        else if ((insn & 0x0ffffdff) == 0x01010000) {
+        } else if ((insn & 0x0ffffdff) == 0x01010000) {
             ARCH(6);
             /* setend */
             if (insn & (1 << 9)) {
@@ -5868,7 +5872,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         } else if ((insn & 0x0e000000) == 0x0a000000) {
             /* branch link and change to thumb (blx <offset>) */
             int32_t offset;
-
+            ARCH(5);
             val = (uint32_t)s->pc;
             tmp = new_tmp();
             tcg_gen_movi_i32(tmp, val);
@@ -5890,8 +5894,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             }
         } else if ((insn & 0x0fe00000) == 0x0c400000) {
             /* Coprocessor double register transfer.  */
+            ARCH(5);
         } else if ((insn & 0x0f000010) == 0x0e000010) {
             /* Additional coprocessor register transfer.  */
+            ARCH(5);
         } else if ((insn & 0x0ff10020) == 0x01000000) {
             uint32_t mask;
             uint32_t val;
@@ -6017,7 +6023,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x3:
             if (op1 != 1)
               goto illegal_op;
-
+            ARCH(5);
             /* branch link/exchange thumb (blx) */
             tmp = load_reg(s, rm);
             tmp2 = new_tmp();
@@ -6040,6 +6046,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             store_reg(s, rd, tmp);
             break;
         case 7: /* bkpt */
+            ARCH(5);
             gen_set_condexec(s);
             gen_set_pc_im(s->pc - 4);
             gen_exception(EXCP_BKPT);
@@ -6776,7 +6783,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             }
             if (insn & (1 << 20)) {
                 /* Complete the load.  */
-                if (rd == 15)
+                if (rd == 15 && ENABLE_ARCH_5)
                     gen_bx(s, tmp);
                 else
                     store_reg(s, rd, tmp);
@@ -6786,6 +6793,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x09:
             {
                 int j, n, user, loaded_base;
+                int crement = 0;
                 TCGv loaded_var;
                 /* load/store multiple words */
                 /* XXX: store correct base if write back */
@@ -6826,6 +6834,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
                     }
                 }
+
+                if (insn & (1 << 21)) {
+                    /* write back */
+                    if (insn & (1 << 23)) {
+                        if (insn & (1 << 24)) {
+                            /* pre increment */
+                        } else {
+                            /* post increment */
+                            crement = 4;
+                        }
+                    } else {
+                        if (insn & (1 << 24)) {
+                            /* pre decrement */
+                            if (n != 1) {
+                                crement = -((n - 1) * 4);
+                            }
+                        } else {
+                            /* post decrement */
+                            crement = -(n * 4);
+                        }
+                    }
+                    if (arm_feature(env, ARM_FEATURE_ABORT_BU)) {
+                        /* base-updated abort model: update base register                          
+                           before an abort can happen */
+                        crement += (n - 1) * 4;
+                        tmp = new_tmp();
+                        tcg_gen_addi_i32(tmp, addr, crement);
+                        store_reg(s, rn, tmp);
+                    }
+
+                }
+
                 j = 0;
                 for(i=0;i<16;i++) {
                     if (insn & (1 << i)) {
@@ -6833,7 +6873,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             /* load */
                             tmp = gen_ld32(addr, IS_USER(s));
                             if (i == 15) {
-                                gen_bx(s, tmp);
+                                if (ENABLE_ARCH_5) {
+                                    gen_bx(s, tmp);
+                                } else {
+                                    store_reg(s, i, tmp);
+                                }
                             } else if (user) {
                                 gen_helper_set_user_reg(tcg_const_i32(i), tmp);
                                 dead_tmp(tmp);
@@ -6864,25 +6908,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             tcg_gen_addi_i32(addr, addr, 4);
                     }
                 }
-                if (insn & (1 << 21)) {
-                    /* write back */
-                    if (insn & (1 << 23)) {
-                        if (insn & (1 << 24)) {
-                            /* pre increment */
-                        } else {
-                            /* post increment */
-                            tcg_gen_addi_i32(addr, addr, 4);
-                        }
-                    } else {
-                        if (insn & (1 << 24)) {
-                            /* pre decrement */
-                            if (n != 1)
-                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
-                        } else {
-                            /* post decrement */
-                            tcg_gen_addi_i32(addr, addr, -(n * 4));
-                        }
-                    }
+                if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << 21))) {
+                    tcg_gen_addi_i32(addr, addr, crement);
                     store_reg(s, rn, addr);
                 } else {
                     dead_tmp(addr);
@@ -7043,6 +7070,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
            16-bit instructions to get correct prefetch abort behavior.  */
         insn = insn_hw1;
         if ((insn & (1 << 12)) == 0) {
+            ARCH(5);
             /* Second half of blx.  */
             offset = ((insn & 0x7ff) << 1);
             tmp = load_reg(s, 14);
@@ -7100,6 +7128,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             /* Other load/store, table branch.  */
             if (insn & 0x01200000) {
                 /* Load/store doubleword.  */
+                ARCH(5);
                 if (rn == 15) {
                     addr = new_tmp();
                     tcg_gen_movi_i32(addr, s->pc & ~3);
@@ -7313,7 +7342,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     if (insn & (1 << 20)) {
                         /* Load.  */
                         tmp = gen_ld32(addr, IS_USER(s));
-                        if (i == 15) {
+                        if (i == 15 && ENABLE_ARCH_5) {
                             gen_bx(s, tmp);
                         } else {
                             store_reg(s, i, tmp);
@@ -7652,6 +7681,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     gen_jmp(s, offset);
                 } else {
                     /* blx */
+                    ARCH(5);
                     offset &= ~(uint32_t)2;
                     gen_bx_im(s, offset);
                 }
@@ -8007,7 +8037,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 case 2: tmp = gen_ld32(addr, user); break;
                 default: goto illegal_op;
                 }
-                if (rs == 15) {
+                if (rs == 15 && ENABLE_ARCH_5) {
                     gen_bx(s, tmp);
                 } else {
                     store_reg(s, rs, tmp);
@@ -8050,6 +8080,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
     TCGv tmp;
     TCGv tmp2;
     TCGv addr;
+    int crement;
 
     if (s->condexec_mask) {
         cond = s->condexec_cond;
@@ -8171,6 +8202,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             case 3:/* branch [and link] exchange thumb register */
                 tmp = load_reg(s, rm);
                 if (insn & (1 << 7)) {
+                    ARCH(5);
                     val = (uint32_t)s->pc | 1;
                     tmp2 = new_tmp();
                     tcg_gen_movi_i32(tmp2, val);
@@ -8523,8 +8555,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             /* write back the new stack pointer */
             store_reg(s, 13, addr);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s, tmp);
+            if ((insn & 0x0900) == 0x0900) {
+                if (ENABLE_ARCH_5) {
+                    gen_bx(s, tmp);
+                } else {
+                    store_reg(s, 15, tmp);
+                }
+            }
             break;
 
         case 1: case 3: case 9: case 11: /* czb */
@@ -8613,6 +8650,19 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         /* load/store multiple */
         rn = (insn >> 8) & 0x7;
         addr = load_reg(s, rn);
+        if (arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
+            /* base-updated abort model: update base register
+               before an abort can happen */
+            crement = 0;
+            for (i = 0; i < 8; i++) {
+                if (insn & (1 << i)) {
+                    crement += 4;
+                }
+            }
+            tmp = new_tmp();
+            tcg_gen_addi_i32(tmp, addr, crement);
+            store_reg(s, rn, tmp);
+        }
         for (i = 0; i < 8; i++) {
             if (insn & (1 << i)) {
                 if (insn & (1 << 11)) {
@@ -8629,7 +8679,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             }
         }
         /* Base register writeback.  */
-        if ((insn & (1 << rn)) == 0) {
+        if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
             store_reg(s, rn, addr);
         } else {
             dead_tmp(addr);
-- 
1.6.3.msysgit.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [Qemu-devel] [PATCH] ARM7TDMI emulation
@ 2009-07-15 12:08 Filip Navara
  0 siblings, 0 replies; 13+ messages in thread
From: Filip Navara @ 2009-07-15 12:08 UTC (permalink / raw)
  To: qemu-devel

While most of the ARMv5 instructions are backward compatible with ARMv4, there
are few important differences. Most notably the stack pop and load instructions
ignore the lowest bit, which is used by ARMv5 to switch to Thumb mode. A
base-updated data-abort model is used on ARM7TDMI, CP15 coprocessor is not
present and several instructions of later architectures are not implemented.

This patch introduces flags for the V5, CP15 and ABORT_BU (base-updated abort
model) features. When V5 feature is not set the bit 0 on POP, LD and LDM of PC
register is ignored and doesn't swith to/from Thumb mode and several
instructions are treated as unimplemented (BLX, PLD, BKPT, LDRD, STRD).

Based on patch by Ulrich Hecht <uli@suse.de>.

Signed-off-by: Filip Navara <filip.navara@gmail.com>
---
 target-arm/cpu.h       |    6 ++-
 target-arm/helper.c    |   24 ++++++++++
 target-arm/translate.c |  116 ++++++++++++++++++++++++++++++++++--------------
 3 files changed, 112 insertions(+), 34 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index f98655f..d004777 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -331,6 +331,7 @@ enum arm_features {
     ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
     ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
     ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
+    ARM_FEATURE_V5,
     ARM_FEATURE_V6,
     ARM_FEATURE_V6K,
     ARM_FEATURE_V7,
@@ -341,7 +342,9 @@ enum arm_features {
     ARM_FEATURE_DIV,
     ARM_FEATURE_M, /* Microcontroller profile.  */
     ARM_FEATURE_OMAPCP, /* OMAP specific CP15 ops handling.  */
-    ARM_FEATURE_THUMB2EE
+    ARM_FEATURE_THUMB2EE,
+    ARM_FEATURE_CP15, /* ARM7TDMI, ARM7TDMI-S, ARM7EJ-S, and ARM9TDMI cores do not have a CP15 */
+    ARM_FEATURE_ABORT_BU /* base updated abort model, e.g. ARMxTDMI */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -367,6 +370,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
 #define IS_M(env) arm_feature(env, ARM_FEATURE_M)
 #define ARM_CPUID(env) (env->cp15.c0_cpuid)
 
+#define ARM_CPUID_ARM7TDMI    0x41807000 /* guess; no CP15 on ARM7TDMI */
 #define ARM_CPUID_ARM1026     0x4106a262
 #define ARM_CPUID_ARM926      0x41069265
 #define ARM_CPUID_ARM946      0x41059461
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 701629a..38875d4 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -37,19 +37,28 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     env->cp15.c0_cpuid = id;
     switch (id) {
+    case ARM_CPUID_ARM7TDMI:
+        set_feature(env, ARM_FEATURE_ABORT_BU);
+        break;
     case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM946:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_MPU);
         env->cp15.c0_cachetype = 0x0f004006;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
@@ -57,8 +66,10 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_ARM1136_R2:
     case ARM_CPUID_ARM1136:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -68,9 +79,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_ARM11MPCORE:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
@@ -80,9 +93,11 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_cachetype = 0x1dd20d2;
         break;
     case ARM_CPUID_CORTEXA8:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_AUXCR);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_VFP);
@@ -101,6 +116,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c0_ccsid[2] = 0xf0000000; /* No L2 icache. */
         break;
     case ARM_CPUID_CORTEXM3:
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_THUMB2);
         set_feature(env, ARM_FEATURE_V7);
@@ -108,6 +124,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         set_feature(env, ARM_FEATURE_DIV);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
+        set_feature(env, ARM_FEATURE_V5);
         set_feature(env, ARM_FEATURE_V6);
         set_feature(env, ARM_FEATURE_V6K);
         set_feature(env, ARM_FEATURE_V7);
@@ -120,6 +137,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_OMAPCP);
         env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
         env->cp15.c0_cachetype = 0x5109149;
@@ -132,6 +151,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA260:
     case ARM_CPUID_PXA261:
     case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
@@ -143,6 +164,8 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
     case ARM_CPUID_PXA270_B1:
     case ARM_CPUID_PXA270_C0:
     case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_V5);
+        set_feature(env, ARM_FEATURE_CP15);
         set_feature(env, ARM_FEATURE_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         set_feature(env, ARM_FEATURE_IWMMXT);
@@ -277,6 +300,7 @@ struct arm_cpu_t {
 };
 
 static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM7TDMI, "arm7tdmi"},
     { ARM_CPUID_ARM926, "arm926"},
     { ARM_CPUID_ARM946, "arm946"},
     { ARM_CPUID_ARM1026, "arm1026"},
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 64956e4..f53d840 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -35,9 +35,10 @@
 #define GEN_HELPER 1
 #include "helpers.h"
 
+#define ENABLE_ARCH_5     arm_feature(env, ARM_FEATURE_V5)
 #define ENABLE_ARCH_5J    0
 #define ENABLE_ARCH_6     arm_feature(env, ARM_FEATURE_V6)
-#define ENABLE_ARCH_6K   arm_feature(env, ARM_FEATURE_V6K)
+#define ENABLE_ARCH_6K    arm_feature(env, ARM_FEATURE_V6K)
 #define ENABLE_ARCH_6T2   arm_feature(env, ARM_FEATURE_THUMB2)
 #define ENABLE_ARCH_7     arm_feature(env, ARM_FEATURE_V7)
 
@@ -2588,8 +2589,10 @@ static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
     TCGv tmp;
 
     /* M profile cores use memory mapped registers instead of cp15.  */
-    if (arm_feature(env, ARM_FEATURE_M))
-	return 1;
+    if (arm_feature(env, ARM_FEATURE_M) ||
+        !arm_feature(env, ARM_FEATURE_CP15)) {
+	    return 1;
+    }
 
     if ((insn & (1 << 25)) == 0) {
         if (insn & (1 << 20)) {
@@ -5746,9 +5749,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 goto illegal_op;
             return;
         }
-        if ((insn & 0x0d70f000) == 0x0550f000)
+        if ((insn & 0x0d70f000) == 0x0550f000) {
+            ARCH(5);
             return; /* PLD */
-        else if ((insn & 0x0ffffdff) == 0x01010000) {
+        } else if ((insn & 0x0ffffdff) == 0x01010000) {
             ARCH(6);
             /* setend */
             if (insn & (1 << 9)) {
@@ -5860,7 +5864,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         } else if ((insn & 0x0e000000) == 0x0a000000) {
             /* branch link and change to thumb (blx <offset>) */
             int32_t offset;
-
+            ARCH(5);
             val = (uint32_t)s->pc;
             tmp = new_tmp();
             tcg_gen_movi_i32(tmp, val);
@@ -5882,8 +5886,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             }
         } else if ((insn & 0x0fe00000) == 0x0c400000) {
             /* Coprocessor double register transfer.  */
+            ARCH(5);
         } else if ((insn & 0x0f000010) == 0x0e000010) {
             /* Additional coprocessor register transfer.  */
+            ARCH(5);
         } else if ((insn & 0x0ff10020) == 0x01000000) {
             uint32_t mask;
             uint32_t val;
@@ -6009,7 +6015,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x3:
             if (op1 != 1)
               goto illegal_op;
-
+            ARCH(5);
             /* branch link/exchange thumb (blx) */
             tmp = load_reg(s, rm);
             tmp2 = new_tmp();
@@ -6032,6 +6038,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             store_reg(s, rd, tmp);
             break;
         case 7: /* bkpt */
+            ARCH(5);
             gen_set_condexec(s);
             gen_set_pc_im(s->pc - 4);
             gen_exception(EXCP_BKPT);
@@ -6768,7 +6775,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             }
             if (insn & (1 << 20)) {
                 /* Complete the load.  */
-                if (rd == 15)
+                if (rd == 15 && ENABLE_ARCH_5)
                     gen_bx(s, tmp);
                 else
                     store_reg(s, rd, tmp);
@@ -6778,6 +6785,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x09:
             {
                 int j, n, user, loaded_base;
+                int crement = 0;
                 TCGv loaded_var;
                 /* load/store multiple words */
                 /* XXX: store correct base if write back */
@@ -6818,6 +6826,38 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
                     }
                 }
+
+                if (insn & (1 << 21)) {
+                    /* write back */
+                    if (insn & (1 << 23)) {
+                        if (insn & (1 << 24)) {
+                            /* pre increment */
+                        } else {
+                            /* post increment */
+                            crement = 4;
+                        }
+                    } else {
+                        if (insn & (1 << 24)) {
+                            /* pre decrement */
+                            if (n != 1) {
+                                crement = -((n - 1) * 4);
+                            }
+                        } else {
+                            /* post decrement */
+                            crement = -(n * 4);
+                        }
+                    }
+                    if (arm_feature(env, ARM_FEATURE_ABORT_BU)) {
+                        /* base-updated abort model: update base register
+                           before an abort can happen */
+                        crement += (n - 1) * 4;
+                        tmp = new_tmp();
+                        tcg_gen_addi_i32(tmp, addr, crement);
+                        store_reg(s, rn, tmp);
+                    }
+
+                }
+
                 j = 0;
                 for(i=0;i<16;i++) {
                     if (insn & (1 << i)) {
@@ -6825,7 +6865,11 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             /* load */
                             tmp = gen_ld32(addr, IS_USER(s));
                             if (i == 15) {
-                                gen_bx(s, tmp);
+                                if (ENABLE_ARCH_5) {
+                                    gen_bx(s, tmp);
+                                } else {
+                                    store_reg(s, i, tmp);
+                                }
                             } else if (user) {
                                 gen_helper_set_user_reg(tcg_const_i32(i), tmp);
                                 dead_tmp(tmp);
@@ -6856,25 +6900,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                             tcg_gen_addi_i32(addr, addr, 4);
                     }
                 }
-                if (insn & (1 << 21)) {
-                    /* write back */
-                    if (insn & (1 << 23)) {
-                        if (insn & (1 << 24)) {
-                            /* pre increment */
-                        } else {
-                            /* post increment */
-                            tcg_gen_addi_i32(addr, addr, 4);
-                        }
-                    } else {
-                        if (insn & (1 << 24)) {
-                            /* pre decrement */
-                            if (n != 1)
-                                tcg_gen_addi_i32(addr, addr, -((n - 1) * 4));
-                        } else {
-                            /* post decrement */
-                            tcg_gen_addi_i32(addr, addr, -(n * 4));
-                        }
-                    }
+                if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << 21))) {
+                    tcg_gen_addi_i32(addr, addr, crement);
                     store_reg(s, rn, addr);
                 } else {
                     dead_tmp(addr);
@@ -7035,6 +7062,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
            16-bit instructions to get correct prefetch abort behavior.  */
         insn = insn_hw1;
         if ((insn & (1 << 12)) == 0) {
+            ARCH(5);
             /* Second half of blx.  */
             offset = ((insn & 0x7ff) << 1);
             tmp = load_reg(s, 14);
@@ -7092,6 +7120,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
             /* Other load/store, table branch.  */
             if (insn & 0x01200000) {
                 /* Load/store doubleword.  */
+                ARCH(5);
                 if (rn == 15) {
                     addr = new_tmp();
                     tcg_gen_movi_i32(addr, s->pc & ~3);
@@ -7305,7 +7334,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     if (insn & (1 << 20)) {
                         /* Load.  */
                         tmp = gen_ld32(addr, IS_USER(s));
-                        if (i == 15) {
+                        if (i == 15 && ENABLE_ARCH_5) {
                             gen_bx(s, tmp);
                         } else {
                             store_reg(s, i, tmp);
@@ -7644,6 +7673,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                     gen_jmp(s, offset);
                 } else {
                     /* blx */
+                    ARCH(5);
                     offset &= ~(uint32_t)2;
                     gen_bx_im(s, offset);
                 }
@@ -7999,7 +8029,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1)
                 case 2: tmp = gen_ld32(addr, user); break;
                 default: goto illegal_op;
                 }
-                if (rs == 15) {
+                if (rs == 15 && ENABLE_ARCH_5) {
                     gen_bx(s, tmp);
                 } else {
                     store_reg(s, rs, tmp);
@@ -8042,6 +8072,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
     TCGv tmp;
     TCGv tmp2;
     TCGv addr;
+    int crement;
 
     if (s->condexec_mask) {
         cond = s->condexec_cond;
@@ -8163,6 +8194,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             case 3:/* branch [and link] exchange thumb register */
                 tmp = load_reg(s, rm);
                 if (insn & (1 << 7)) {
+                    ARCH(5);
                     val = (uint32_t)s->pc | 1;
                     tmp2 = new_tmp();
                     tcg_gen_movi_i32(tmp2, val);
@@ -8515,8 +8547,13 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             /* write back the new stack pointer */
             store_reg(s, 13, addr);
             /* set the new PC value */
-            if ((insn & 0x0900) == 0x0900)
-                gen_bx(s, tmp);
+            if ((insn & 0x0900) == 0x0900) {
+                if (ENABLE_ARCH_5) {
+                    gen_bx(s, tmp);
+                } else {
+                    store_reg(s, 15, tmp);
+                }
+            }
             break;
 
         case 1: case 3: case 9: case 11: /* czb */
@@ -8605,6 +8642,19 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
         /* load/store multiple */
         rn = (insn >> 8) & 0x7;
         addr = load_reg(s, rn);
+        if (arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
+            /* base-updated abort model: update base register
+               before an abort can happen */
+            crement = 0;
+            for (i = 0; i < 8; i++) {
+                if (insn & (1 << i)) {
+                    crement += 4;
+                }
+            }
+            tmp = new_tmp();
+            tcg_gen_addi_i32(tmp, addr, crement);
+            store_reg(s, rn, tmp);
+        }
         for (i = 0; i < 8; i++) {
             if (insn & (1 << i)) {
                 if (insn & (1 << 11)) {
@@ -8621,7 +8671,7 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s)
             }
         }
         /* Base register writeback.  */
-        if ((insn & (1 << rn)) == 0) {
+        if (!arm_feature(env, ARM_FEATURE_ABORT_BU) && (insn & (1 << rn)) == 0) {
             store_reg(s, rn, addr);
         } else {
             dead_tmp(addr);
-- 
1.6.3.msysgit.0

^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2009-07-15 12:08 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-07-02 13:27 [Qemu-devel] [PATCH] ARM7TDMI emulation Ulrich Hecht
2007-07-02 13:40 ` Paul Brook
2007-07-02 16:14   ` Ulrich Hecht
2007-07-03 14:45     ` Ulrich Hecht
2009-06-15 19:11       ` Filip Navara
2009-06-16 17:25         ` Paul Brook
2009-06-16 19:02           ` Jamie Lokier
2009-06-16 19:05             ` Paul Brook
2009-06-16 20:49             ` Filip Navara
2009-06-16 21:47               ` Filip Navara
2009-06-17  9:55               ` Filip Navara
2009-06-17 10:24                 ` Filip Navara
2009-07-15 12:08 Filip Navara

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.