diff mbox

[RFC,v3,08/21] target-arm: Move CPU feature flags out of CPUState

Message ID 1328237992-14953-9-git-send-email-afaerber@suse.de
State New
Headers show

Commit Message

Andreas Färber Feb. 3, 2012, 2:59 a.m. UTC
The internal CPU feature flags were only ever set in
cpu_reset_model_id(). Therefore move their initialization into
ARMCPUClass. We might want to tweak them in the future though (e.g.,
-cpu cortex-r4,+fpu), so keep a copy in ARMCPU. This in turn means we
need to infer features for both ARMCPUClass and ARMCPU, so move feature
inference to arm_infer_features() and use macros to simplify it.

Since cpu.h defines ARMCPUState, which has been incorporated into
ARMCPU, and tries to use arm_feature() in cpu_get_tb_cpu_state(),
move arm_feature() to cpu-core.h and add a forward declaration.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Cc: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu-core.h |   12 ++++
 target-arm/cpu.c      |  159 +++++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/cpu.h      |    9 +--
 target-arm/helper.c   |   95 -----------------------------
 target-arm/machine.c  |    6 +-
 5 files changed, 177 insertions(+), 104 deletions(-)

Comments

Peter Maydell Feb. 7, 2012, 5:28 p.m. UTC | #1
On 3 February 2012 02:59, Andreas Färber <afaerber@suse.de> wrote:
> +static void sa11xx_class_init(ARMCPUClass *k, const ARMCPUInfo *info)
> +{
> +    set_class_feature(k, ARM_FEATURE_STRONGARM);
> +}

>  static const ARMCPUInfo arm_cpus[] = {
>     {
>         .name = "arm926",
>         .id = 0x41069265,
> +        .features = ARM_FEATURE(V5) |
> +                    ARM_FEATURE(VFP),
>     },

>     {
>         .name = "sa1100",
>         .id = 0x4401A11B,
> +        .class_init = sa11xx_class_init,
>     },

So why are we handling some of these feature bits by setting them
in .features, and some of them via a .class_init which sets the
feature bit?

-- PMM
Andreas Färber Feb. 7, 2012, 5:43 p.m. UTC | #2
Am 07.02.2012 18:28, schrieb Peter Maydell:
> On 3 February 2012 02:59, Andreas Färber <afaerber@suse.de> wrote:
>> +static void sa11xx_class_init(ARMCPUClass *k, const ARMCPUInfo *info)
>> +{
>> +    set_class_feature(k, ARM_FEATURE_STRONGARM);
>> +}
> 
>>  static const ARMCPUInfo arm_cpus[] = {
>>     {
>>         .name = "arm926",
>>         .id = 0x41069265,
>> +        .features = ARM_FEATURE(V5) |
>> +                    ARM_FEATURE(VFP),
>>     },
> 
>>     {
>>         .name = "sa1100",
>>         .id = 0x4401A11B,
>> +        .class_init = sa11xx_class_init,
>>     },
> 
> So why are we handling some of these feature bits by setting them
> in .features, and some of them via a .class_init which sets the
> feature bit?

To avoid duplication. This corresponds to fall-throughs in the switch.

Eventually as suggested by you we would get rid of some of these
duplicate models and let the user (or an alias-like compatibility
mechanism) set the desired revision numbers on one base class via QOM
properties. Then those class_inits would no longer be needed.

Andreas
diff mbox

Patch

diff --git a/target-arm/cpu-core.h b/target-arm/cpu-core.h
index 4ba5ee0..9f090a8 100644
--- a/target-arm/cpu-core.h
+++ b/target-arm/cpu-core.h
@@ -44,6 +44,9 @@  typedef struct ARMCPUClass {
     struct {
         uint32_t c0_cpuid;
     } cp15;
+
+    /* Internal CPU feature flags. */
+    uint32_t features;
 } ARMCPUClass;
 
 /**
@@ -55,6 +58,9 @@  typedef struct ARMCPU {
     /*< private >*/
     CPU parent_obj;
 
+    /* Internal CPU feature flags. */
+    uint32_t features;
+
     /* TODO Inline this and split off common state */
     CPUARMState env;
 } ARMCPU;
@@ -66,5 +72,11 @@  static inline Object *arm_env_get_object(CPUARMState *env)
 
 #define ENV_GET_OBJECT(e) arm_env_get_object(e)
 
+static inline int arm_feature(CPUARMState *env, int feature)
+{
+    ARMCPU *cpu = ARM_CPU(ENV_GET_OBJECT(env));
+    return (cpu->features & (1u << feature)) != 0;
+}
+
 
 #endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index a6dbad3..07cbfe6 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -91,14 +91,88 @@  static void arm_cpu_reset(CPU *c)
     tlb_flush(env, 1);
 }
 
+/* CPU feature flags */
+
+#define ARM_FEATURE(x) (1u << ARM_FEATURE_ ## x)
+
+#define has_feature(x) ((*features & ARM_FEATURE(x)) != 0)
+#define set_feature(x) (*features |= ARM_FEATURE(x))
+
+/**
+ * arm_infer_features:
+ * @features: Pointer to the feature flags of #ARMCPUClass or #ARMCPU.
+ *
+ * Some features automatically imply others.
+ */
+static void arm_infer_features(uint32_t *features)
+{
+    if (has_feature(V7)) {
+        set_feature(VAPA);
+        set_feature(THUMB2);
+        if (!has_feature(M)) {
+            set_feature(V6K);
+        } else {
+            set_feature(V6);
+        }
+    }
+    if (has_feature(V6K)) {
+        set_feature(V6);
+    }
+    if (has_feature(V6)) {
+        set_feature(V5);
+        if (!has_feature(M)) {
+            set_feature(AUXCR);
+        }
+    }
+    if (has_feature(V5)) {
+        set_feature(V4T);
+    }
+    if (has_feature(M)) {
+        set_feature(THUMB_DIV);
+    }
+    if (has_feature(ARM_DIV)) {
+        set_feature(THUMB_DIV);
+    }
+    if (has_feature(VFP4)) {
+        set_feature(VFP3);
+    }
+    if (has_feature(VFP3)) {
+        set_feature(VFP);
+    }
+}
+
+#undef has_feature
+#undef set_feature
+
+static inline void set_class_feature(ARMCPUClass *klass, int feature)
+{
+    klass->features |= 1u << feature;
+}
+
+static inline void unset_class_feature(ARMCPUClass *klass, int feature)
+{
+    klass->features &= ~(1u << feature);
+}
+
 /* CPU models */
 
 typedef struct ARMCPUInfo {
     const char *name;
     uint32_t id;
+    uint32_t features;
     void (*class_init)(ARMCPUClass *klass, const struct ARMCPUInfo *info);
 } ARMCPUInfo;
 
+static void arm1136_r0_class_init(ARMCPUClass *k, const ARMCPUInfo *info)
+{
+    ARMCPUClass *r1_class;
+
+    r1_class = ARM_CPU_CLASS(object_class_by_name("arm1136"));
+
+    k->features = r1_class->features;
+    unset_class_feature(k, ARM_FEATURE_V6K);
+}
+
 static void ti925t_reset(CPU *c)
 {
     ARMCPU *cpu = ARM_CPU(c);
@@ -116,18 +190,43 @@  static void ti925t_class_init(ARMCPUClass *klass, const ARMCPUInfo *info)
     cpu_class->reset = ti925t_reset;
 }
 
+static void sa11xx_class_init(ARMCPUClass *k, const ARMCPUInfo *info)
+{
+    set_class_feature(k, ARM_FEATURE_STRONGARM);
+}
+
+static void pxa25x_class_init(ARMCPUClass *k, const ARMCPUInfo *info)
+{
+    set_class_feature(k, ARM_FEATURE_V5);
+    set_class_feature(k, ARM_FEATURE_XSCALE);
+}
+
+static void pxa270_class_init(ARMCPUClass *k, const ARMCPUInfo *info)
+{
+    set_class_feature(k, ARM_FEATURE_V5);
+    set_class_feature(k, ARM_FEATURE_XSCALE);
+    set_class_feature(k, ARM_FEATURE_IWMMXT);
+}
+
 static const ARMCPUInfo arm_cpus[] = {
     {
         .name = "arm926",
         .id = 0x41069265,
+        .features = ARM_FEATURE(V5) |
+                    ARM_FEATURE(VFP),
     },
     {
         .name = "arm946",
         .id = 0x41059461,
+        .features = ARM_FEATURE(V5) |
+                    ARM_FEATURE(MPU),
     },
     {
         .name = "arm1026",
         .id = 0x4106a262,
+        .features = ARM_FEATURE(V5) |
+                    ARM_FEATURE(VFP) |
+                    ARM_FEATURE(AUXCR),
     },
     /* What QEMU calls "arm1136-r2" is actually the 1136 r0p2, i.e. an
      * older core than plain "arm1136". In particular this does not
@@ -136,95 +235,150 @@  static const ARMCPUInfo arm_cpus[] = {
     {
         .name = "arm1136-r2",
         .id = 0x4107b362,
+        .class_init = arm1136_r0_class_init,
     },
     {
         .name = "arm1136",
         .id = 0x4117b363,
+        .features = ARM_FEATURE(V6) |
+                    ARM_FEATURE(VFP),
     },
     {
         .name = "arm1176",
         .id = 0x410fb767,
+        .features = ARM_FEATURE(V6K) |
+                    ARM_FEATURE(VFP) |
+                    ARM_FEATURE(VAPA),
     },
     {
         .name = "arm11mpcore",
         .id = 0x410fb022,
+        .features = ARM_FEATURE(V6K) |
+                    ARM_FEATURE(VFP) |
+                    ARM_FEATURE(VAPA),
     },
     {
         .name = "cortex-m3",
         .id = 0x410fc231,
+        .features = ARM_FEATURE(V7) |
+                    ARM_FEATURE(M),
     },
     {
         .name = "cortex-a8",
         .id = 0x410fc080,
+        .features = ARM_FEATURE(V7) |
+                    ARM_FEATURE(VFP3) |
+                    ARM_FEATURE(NEON) |
+                    ARM_FEATURE(THUMB2EE),
     },
     {
         .name = "cortex-a9",
         .id = 0x410fc090,
+        .features = ARM_FEATURE(V7) |
+                    ARM_FEATURE(VFP3) |
+                    ARM_FEATURE(VFP_FP16) |
+                    ARM_FEATURE(NEON) |
+                    ARM_FEATURE(THUMB2EE) |
+                    /* Note that A9 supports the MP extensions even for
+                     * A9UP and single-core A9MP (which are both different
+                     * and valid configurations; we don't model A9UP).
+                     */
+                    ARM_FEATURE(V7MP),
     },
     {
         .name = "cortex-a15",
         .id = 0x412fc0f1,
+        .features = ARM_FEATURE(V7) |
+                    ARM_FEATURE(VFP4) |
+                    ARM_FEATURE(VFP_FP16) |
+                    ARM_FEATURE(NEON) |
+                    ARM_FEATURE(THUMB2EE) |
+                    ARM_FEATURE(ARM_DIV) |
+                    ARM_FEATURE(V7MP) |
+                    ARM_FEATURE(GENERIC_TIMER),
     },
     {
         .name = "ti925t",
         .id = 0x54029252,
+        .features = ARM_FEATURE(V4T) |
+                    ARM_FEATURE(OMAPCP),
         .class_init = ti925t_class_init,
     },
     {
         .name = "sa1100",
         .id = 0x4401A11B,
+        .class_init = sa11xx_class_init,
     },
     {
         .name = "sa1110",
         .id = 0x6901B119,
+        .class_init = sa11xx_class_init,
     },
     {
         .name = "pxa250",
         .id = 0x69052100,
+        .class_init = pxa25x_class_init,
     },
     {
         .name = "pxa255",
         .id = 0x69052d00,
+        .class_init = pxa25x_class_init,
     },
     {
         .name = "pxa260",
         .id = 0x69052903,
+        .class_init = pxa25x_class_init,
     },
     {
         .name = "pxa261",
         .id = 0x69052d05,
+        .class_init = pxa25x_class_init,
     },
     {
         .name = "pxa262",
         .id = 0x69052d06,
+        .class_init = pxa25x_class_init,
     },
     {
         .name = "pxa270-a0",
         .id = 0x69054110,
+        .class_init = pxa270_class_init,
     },
     {
         .name = "pxa270-a1",
         .id = 0x69054111,
+        .class_init = pxa270_class_init,
     },
     {
         .name = "pxa270-b0",
         .id = 0x69054112,
+        .class_init = pxa270_class_init,
     },
     {
         .name = "pxa270-b1",
         .id = 0x69054113,
+        .class_init = pxa270_class_init,
     },
     {
         .name = "pxa270-c0",
         .id = 0x69054114,
+        .class_init = pxa270_class_init,
     },
     {
         .name = "pxa270-c5",
         .id = 0x69054117,
+        .class_init = pxa270_class_init,
     },
     {
         .name = "any",
         .id = 0xffffffff,
+        .features = ARM_FEATURE(V7) |
+                    ARM_FEATURE(VFP4) |
+                    ARM_FEATURE(VFP_FP16) |
+                    ARM_FEATURE(NEON) |
+                    ARM_FEATURE(THUMB2EE) |
+                    ARM_FEATURE(ARM_DIV) |
+                    ARM_FEATURE(V7MP),
     },
 };
 
@@ -233,6 +387,8 @@  static void arm_cpu_initfn(Object *obj)
     ARMCPU *cpu = ARM_CPU(obj);
     ARMCPUClass *cpu_class = ARM_CPU_GET_CLASS(obj);
 
+    cpu->features = cpu_class->features;
+
     memset(&cpu->env, 0, sizeof(CPUARMState));
     cpu_exec_init(&cpu->env);
 
@@ -249,10 +405,13 @@  static void arm_cpu_class_init(ObjectClass *klass, void *data)
     cpu_class->reset = arm_cpu_reset;
 
     k->cp15.c0_cpuid = info->id;
+    k->features = info->features;
 
     if (info->class_init != NULL) {
         (*info->class_init)(k, info);
     }
+
+    arm_infer_features(&k->features);
 }
 
 static void cpu_register(const ARMCPUInfo *info)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 5905ef2..bf8c911 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -170,9 +170,6 @@  typedef struct CPUARMState {
     uint32_t teecr;
     uint32_t teehbr;
 
-    /* Internal CPU feature flags.  */
-    uint32_t features;
-
     /* VFP coprocessor state.  */
     struct {
         float64 regs[32];
@@ -385,10 +382,7 @@  enum arm_features {
     ARM_FEATURE_GENERIC_TIMER,
 };
 
-static inline int arm_feature(CPUARMState *env, int feature)
-{
-    return (env->features & (1u << feature)) != 0;
-}
+static inline int arm_feature(CPUARMState *env, int feature);
 
 void arm_cpu_list(FILE *f, fprintf_function cpu_fprintf);
 
@@ -475,6 +469,7 @@  static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #endif
 
 #include "cpu-all.h"
+#include "cpu-core.h"
 
 /* Bit usage in the TB flags field: */
 #define ARM_TBFLAG_THUMB_SHIFT      0
diff --git a/target-arm/helper.c b/target-arm/helper.c
index e877c3f..4fd8ba8 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -49,46 +49,31 @@  static uint32_t arm1176_cp15_c0_c1[8] =
 static uint32_t arm1176_cp15_c0_c2[8] =
 { 0x0140011, 0x12002111, 0x11231121, 0x01102131, 0x01141, 0, 0, 0 };
 
-static inline void set_feature(CPUARMState *env, int feature)
-{
-    env->features |= 1u << feature;
-}
-
 static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
 {
     switch (id) {
     case ARM_CPUID_ARM926:
-        set_feature(env, ARM_FEATURE_V5);
-        set_feature(env, ARM_FEATURE_VFP);
         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_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_AUXCR);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
         env->cp15.c0_cachetype = 0x1dd20d2;
         env->cp15.c1_sys = 0x00090078;
         break;
     case ARM_CPUID_ARM1136:
         /* This is the 1136 r1, which is a v6K core */
-        set_feature(env, ARM_FEATURE_V6K);
         /* Fall through */
     case ARM_CPUID_ARM1136_R2:
         /* What qemu calls "arm1136_r2" is actually the 1136 r0p2, ie an
          * older core than plain "arm1136". In particular this does not
          * have the v6K features.
          */
-        set_feature(env, ARM_FEATURE_V6);
-        set_feature(env, ARM_FEATURE_VFP);
         /* These ID register values are correct for 1136 but may be wrong
          * for 1136_r2 (in particular r0p2 does not actually implement most
          * of the ID registers).
@@ -102,9 +87,6 @@  static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM1176:
-        set_feature(env, ARM_FEATURE_V6K);
-        set_feature(env, ARM_FEATURE_VFP);
-        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b5;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -114,9 +96,6 @@  static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00050078;
         break;
     case ARM_CPUID_ARM11MPCORE:
-        set_feature(env, ARM_FEATURE_V6K);
-        set_feature(env, ARM_FEATURE_VFP);
-        set_feature(env, ARM_FEATURE_VAPA);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410120b4;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11111111;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00000000;
@@ -125,10 +104,6 @@  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_V7);
-        set_feature(env, ARM_FEATURE_VFP3);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410330c0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x00011100;
@@ -142,16 +117,6 @@  static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA9:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP3);
-        set_feature(env, ARM_FEATURE_VFP_FP16);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
-        /* Note that A9 supports the MP extensions even for
-         * A9UP and single-core A9MP (which are both different
-         * and valid configurations; we don't model A9UP).
-         */
-        set_feature(env, ARM_FEATURE_V7MP);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x41034000; /* Guess */
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x11110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x01111111;
@@ -164,14 +129,6 @@  static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXA15:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP4);
-        set_feature(env, ARM_FEATURE_VFP_FP16);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_ARM_DIV);
-        set_feature(env, ARM_FEATURE_V7MP);
-        set_feature(env, ARM_FEATURE_GENERIC_TIMER);
         env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
         env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
         env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
@@ -185,22 +142,11 @@  static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
         env->cp15.c1_sys = 0x00c50078;
         break;
     case ARM_CPUID_CORTEXM3:
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_M);
         break;
     case ARM_CPUID_ANY: /* For userspace emulation.  */
-        set_feature(env, ARM_FEATURE_V7);
-        set_feature(env, ARM_FEATURE_VFP4);
-        set_feature(env, ARM_FEATURE_VFP_FP16);
-        set_feature(env, ARM_FEATURE_NEON);
-        set_feature(env, ARM_FEATURE_THUMB2EE);
-        set_feature(env, ARM_FEATURE_ARM_DIV);
-        set_feature(env, ARM_FEATURE_V7MP);
         break;
     case ARM_CPUID_TI915T:
     case ARM_CPUID_TI925T:
-        set_feature(env, ARM_FEATURE_V4T);
-        set_feature(env, ARM_FEATURE_OMAPCP);
         env->cp15.c0_cachetype = 0x5109149;
         env->cp15.c1_sys = 0x00000070;
         env->cp15.c15_i_max = 0x000;
@@ -211,8 +157,6 @@  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_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
@@ -223,58 +167,19 @@  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_XSCALE);
         /* JTAG_ID is ((id << 28) | 0x09265013) */
-        set_feature(env, ARM_FEATURE_IWMMXT);
         env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
         env->cp15.c0_cachetype = 0xd172172;
         env->cp15.c1_sys = 0x00000078;
         break;
     case ARM_CPUID_SA1100:
     case ARM_CPUID_SA1110:
-        set_feature(env, ARM_FEATURE_STRONGARM);
         env->cp15.c1_sys = 0x00000070;
         break;
     default:
         cpu_abort(env, "Bad CPU ID: %x\n", id);
         break;
     }
-
-    /* Some features automatically imply others: */
-    if (arm_feature(env, ARM_FEATURE_V7)) {
-        set_feature(env, ARM_FEATURE_VAPA);
-        set_feature(env, ARM_FEATURE_THUMB2);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            set_feature(env, ARM_FEATURE_V6K);
-        } else {
-            set_feature(env, ARM_FEATURE_V6);
-        }
-    }
-    if (arm_feature(env, ARM_FEATURE_V6K)) {
-        set_feature(env, ARM_FEATURE_V6);
-    }
-    if (arm_feature(env, ARM_FEATURE_V6)) {
-        set_feature(env, ARM_FEATURE_V5);
-        if (!arm_feature(env, ARM_FEATURE_M)) {
-            set_feature(env, ARM_FEATURE_AUXCR);
-        }
-    }
-    if (arm_feature(env, ARM_FEATURE_V5)) {
-        set_feature(env, ARM_FEATURE_V4T);
-    }
-    if (arm_feature(env, ARM_FEATURE_M)) {
-        set_feature(env, ARM_FEATURE_THUMB_DIV);
-    }
-    if (arm_feature(env, ARM_FEATURE_ARM_DIV)) {
-        set_feature(env, ARM_FEATURE_THUMB_DIV);
-    }
-    if (arm_feature(env, ARM_FEATURE_VFP4)) {
-        set_feature(env, ARM_FEATURE_VFP3);
-    }
-    if (arm_feature(env, ARM_FEATURE_VFP3)) {
-        set_feature(env, ARM_FEATURE_VFP);
-    }
 }
 
 void cpu_reset(CPUARMState *env)
diff --git a/target-arm/machine.c b/target-arm/machine.c
index f66b8df..c93fded 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -5,6 +5,7 @@  void cpu_save(QEMUFile *f, void *opaque)
 {
     int i;
     CPUARMState *env = (CPUARMState *)opaque;
+    ARMCPU *cpu = ARM_CPU(ENV_GET_OBJECT(env));
 
     for (i = 0; i < 16; i++) {
         qemu_put_be32(f, env->regs[i]);
@@ -61,7 +62,7 @@  void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, env->cp15.c15_diagnostic);
     qemu_put_be32(f, env->cp15.c15_power_diagnostic);
 
-    qemu_put_be32(f, env->features);
+    qemu_put_be32(f, cpu->features);
 
     if (arm_feature(env, ARM_FEATURE_VFP)) {
         for (i = 0;  i < 16; i++) {
@@ -115,6 +116,7 @@  void cpu_save(QEMUFile *f, void *opaque)
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
     CPUARMState *env = (CPUARMState *)opaque;
+    ARMCPU *cpu = ARM_CPU(ENV_GET_OBJECT(env));
     int i;
     uint32_t val;
 
@@ -179,7 +181,7 @@  int cpu_load(QEMUFile *f, void *opaque, int version_id)
     env->cp15.c15_diagnostic = qemu_get_be32(f);
     env->cp15.c15_power_diagnostic = qemu_get_be32(f);
 
-    env->features = qemu_get_be32(f);
+    cpu->features = qemu_get_be32(f);
 
     if (arm_feature(env, ARM_FEATURE_VFP)) {
         for (i = 0;  i < 16; i++) {