Add Arm926 core support.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1765 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 052634c..75a1f13 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -72,6 +72,7 @@
 
     /* System control coprocessor (cp15) */
     struct {
+        uint32_t c0_cpuid;
         uint32_t c1_sys; /* System control register.  */
         uint32_t c1_coproc; /* Coprocessor access register.  */
         uint32_t c2; /* MMU translation table base.  */
@@ -85,7 +86,10 @@
         uint32_t c13_fcse; /* FCSE PID.  */
         uint32_t c13_context; /* Context ID.  */
     } cp15;
-    
+
+    /* Internal CPU feature flags.  */
+    uint32_t features;
+
     /* exception/interrupt handling */
     jmp_buf jmp_env;
     int exception_index;
@@ -97,12 +101,11 @@
     struct {
         float64 regs[16];
 
+        uint32_t xregs[16];
         /* We store these fpcsr fields separately for convenience.  */
         int vec_len;
         int vec_stride;
 
-        uint32_t fpscr;
-
         /* Temporary variables if we don't have spare fp regs.  */
         float32 tmp0s, tmp1s;
         float64 tmp0d, tmp1d;
@@ -187,6 +190,29 @@
   ARM_CPU_MODE_SYS = 0x1f
 };
 
+/* VFP system registers.  */
+#define ARM_VFP_FPSID   0
+#define ARM_VFP_FPSCR   1
+#define ARM_VFP_FPEXC   8
+#define ARM_VFP_FPINST  9
+#define ARM_VFP_FPINST2 10
+
+
+enum arm_features {
+    ARM_FEATURE_VFP,
+    ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register.  */
+};
+
+static inline int arm_feature(CPUARMState *env, int feature)
+{
+    return (env->features & (1u << feature)) != 0;
+}
+
+void cpu_arm_set_model(CPUARMState *env, uint32_t id);
+
+#define ARM_CPUID_ARM1026 0x4106a262
+#define ARM_CPUID_ARM926  0x41069265
+
 #if defined(CONFIG_USER_ONLY)
 #define TARGET_PAGE_BITS 12
 #else
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5804df8..d0cd6d8 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5,6 +5,61 @@
 #include "cpu.h"
 #include "exec-all.h"
 
+void cpu_reset(CPUARMState *env)
+{
+#if defined (CONFIG_USER_ONLY)
+    env->uncached_cpsr = ARM_CPU_MODE_USR;
+    env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
+#else
+    /* SVC mode with interrupts disabled.  */
+    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+    env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+#endif
+    env->regs[15] = 0;
+}
+
+CPUARMState *cpu_arm_init(void)
+{
+    CPUARMState *env;
+
+    env = qemu_mallocz(sizeof(CPUARMState));
+    if (!env)
+        return NULL;
+    cpu_exec_init(env);
+    cpu_reset(env);
+    tlb_flush(env, 1);
+    return env;
+}
+
+static inline void set_feature(CPUARMState *env, int feature)
+{
+    env->features |= 1u << feature;
+}
+
+void cpu_arm_set_model(CPUARMState *env, uint32_t id)
+{
+    env->cp15.c0_cpuid = id;
+    switch (id) {
+    case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_VFP);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
+        break;
+    case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
+        break;
+    default:
+        cpu_abort(env, "Bad CPU ID: %x\n", id);
+        break;
+    }
+}
+
+void cpu_arm_close(CPUARMState *env)
+{
+    free(env);
+}
+
 #if defined(CONFIG_USER_ONLY) 
 
 void do_interrupt (CPUState *env)
@@ -469,7 +524,7 @@
     case 0: /* ID codes.  */
         switch (op2) {
         default: /* Device ID.  */
-            return 0x4106a262;
+            return env->cp15.c0_cpuid;
         case 1: /* Cache Type.  */
             return 0x1dd20d2;
         case 2: /* TCM status.  */
@@ -480,7 +535,9 @@
         case 0: /* Control register.  */
             return env->cp15.c1_sys;
         case 1: /* Auxiliary control register.  */
-            return 1;
+            if (arm_feature(env, ARM_FEATURE_AUXCR))
+                return 1;
+            goto bad_reg;
         case 2: /* Coprocessor access register.  */
             return env->cp15.c1_coproc;
         default:
@@ -506,6 +563,8 @@
         case 0:
             return env->cp15.c6_data;
         case 1:
+            /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
+               do any harm.  */
             return env->cp15.c6_insn;
         default:
             goto bad_reg;
diff --git a/target-arm/op.c b/target-arm/op.c
index f06b06b..619066d 100644
--- a/target-arm/op.c
+++ b/target-arm/op.c
@@ -1094,7 +1094,7 @@
 
 void OPPROTO op_vfp_movl_T0_fpscr_flags(void)
 {
-    T0 = env->vfp.fpscr & (0xf << 28);
+    T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28);
 }
 
 void OPPROTO op_vfp_movl_fpscr_T0(void)
@@ -1102,6 +1102,16 @@
     do_vfp_set_fpscr();
 }
 
+void OPPROTO op_vfp_movl_T0_xreg(void)
+{
+    T0 = env->vfp.xregs[PARAM1];
+}
+
+void OPPROTO op_vfp_movl_xreg_T0(void)
+{
+    env->vfp.xregs[PARAM1] = T0;
+}
+
 /* Move between FT0s to T0  */
 void OPPROTO op_vfp_mrs(void)
 {
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index c075b53..af5c61d 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -72,7 +72,8 @@
     case 1: flags = 0x2; break;\
     default: case 2: flags = 0x3; break;\
     }\
-    env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \
+    env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\
+        | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \
     FORCE_RET();                          \
 }\
 \
@@ -85,7 +86,8 @@
     case 1: flags = 0x2; break;\
     default: case 2: flags = 0x3; break;\
     }\
-    env->vfp.fpscr = (flags << 28) | (env->vfp.fpscr & 0x0fffffff); \
+    env->vfp.xregs[ARM_VFP_FPSCR] = (flags << 28)\
+        | (env->vfp.xregs[ARM_VFP_FPSCR] & 0x0fffffff); \
     FORCE_RET();                          \
 }
 DO_VFP_cmp(s, 32)
@@ -133,8 +135,8 @@
     int i;
     uint32_t changed;
 
-    changed = env->vfp.fpscr;
-    env->vfp.fpscr = (T0 & 0xffc8ffff);
+    changed = env->vfp.xregs[ARM_VFP_FPSCR];
+    env->vfp.xregs[ARM_VFP_FPSCR] = (T0 & 0xffc8ffff);
     env->vfp.vec_len = (T0 >> 16) & 7;
     env->vfp.vec_stride = (T0 >> 20) & 3;
 
@@ -167,7 +169,7 @@
 {
     int i;
 
-    T0 = (env->vfp.fpscr & 0xffc8ffff) | (env->vfp.vec_len << 16)
+    T0 = (env->vfp.xregs[ARM_VFP_FPSCR] & 0xffc8ffff) | (env->vfp.vec_len << 16)
           | (env->vfp.vec_stride << 20);
     i = get_float_exception_flags(&env->vfp.fp_status);
     T0 |= vfp_exceptbits_from_host(i);
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 9390579..1f8a485 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -526,6 +526,17 @@
     uint32_t rd, rn, rm, op, i, n, offset, delta_d, delta_m, bank_mask;
     int dp, veclen;
 
+    if (!arm_feature(env, ARM_FEATURE_VFP))
+        return 1;
+
+    if ((env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) == 0) {
+        /* VFP disabled.  Only allow fmxr/fmrx to/from fpexc and fpsid.  */
+        if ((insn & 0x0fe00fff) != 0x0ee00a10)
+            return 1;
+        rn = (insn >> 16) & 0xf;
+        if (rn != 0 && rn != 8)
+            return 1;
+    }
     dp = ((insn & 0xf00) == 0xb00);
     switch ((insn >> 24) & 0xf) {
     case 0xe:
@@ -563,11 +574,15 @@
                     /* vfp->arm */
                     if (insn & (1 << 21)) {
                         /* system register */
+                        rn >>= 1;
                         switch (rn) {
-                        case 0: /* fpsid */
-                            n = 0x0091A0000;
+                        case ARM_VFP_FPSID:
+                        case ARM_VFP_FPEXC:
+                        case ARM_VFP_FPINST:
+                        case ARM_VFP_FPINST2:
+                            gen_op_vfp_movl_T0_xreg(rn);
                             break;
-                        case 2: /* fpscr */
+                        case ARM_VFP_FPSCR:
 			    if (rd == 15)
 				gen_op_vfp_movl_T0_fpscr_flags();
 			    else
@@ -589,17 +604,24 @@
                     /* arm->vfp */
                     gen_movl_T0_reg(s, rd);
                     if (insn & (1 << 21)) {
+                        rn >>= 1;
                         /* system register */
                         switch (rn) {
-                        case 0: /* fpsid */
+                        case ARM_VFP_FPSID:
                             /* Writes are ignored.  */
                             break;
-                        case 2: /* fpscr */
+                        case ARM_VFP_FPSCR:
                             gen_op_vfp_movl_fpscr_T0();
-                            /* This could change vector settings, so jump to
-                               the next instuction.  */
                             gen_lookup_tb(s);
                             break;
+                        case ARM_VFP_FPEXC:
+                            gen_op_vfp_movl_xreg_T0(rn);
+                            gen_lookup_tb(s);
+                            break;
+                        case ARM_VFP_FPINST:
+                        case ARM_VFP_FPINST2:
+                            gen_op_vfp_movl_xreg_T0(rn);
+                            break;
                         default:
                             return 1;
                         }
@@ -2456,35 +2478,6 @@
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
-void cpu_reset(CPUARMState *env)
-{
-#if defined (CONFIG_USER_ONLY)
-    env->uncached_cpsr = ARM_CPU_MODE_USR;
-#else
-    /* SVC mode with interrupts disabled.  */
-    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
-#endif
-    env->regs[15] = 0;
-}
-
-CPUARMState *cpu_arm_init(void)
-{
-    CPUARMState *env;
-
-    env = qemu_mallocz(sizeof(CPUARMState));
-    if (!env)
-        return NULL;
-    cpu_exec_init(env);
-    cpu_reset(env);
-    tlb_flush(env, 1);
-    return env;
-}
-
-void cpu_arm_close(CPUARMState *env)
-{
-    free(env);
-}
-
 static const char *cpu_mode_names[16] = {
   "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
   "???", "???", "???", "und", "???", "???", "???", "sys"
@@ -2528,6 +2521,6 @@
                     i, (int)(uint32_t)d.l.upper, (int)(uint32_t)d.l.lower,
                     d.d);
     }
-    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
+    cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
 }