Patchwork [RFC,qom-cpu,39/41] target-xtensa: Introduce XtensaCPU subclasses

login
register
mail settings
Submitter Andreas Färber
Date June 29, 2013, 8:01 p.m.
Message ID <1372536117-28167-40-git-send-email-afaerber@suse.de>
Download mbox | patch
Permalink /patch/255771/
State New
Headers show

Comments

Andreas Färber - June 29, 2013, 8:01 p.m.
Register a CPU type per core registered. Save the XtensaConfig in
XtensaCPUClass instead of CPUXtensaState.

Prepares for storing per-class GDB register count.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 gdbstub.c                 |  17 ++++---
 hw/xtensa/pic_cpu.c       |  47 ++++++++++++------
 target-xtensa/cpu-qom.h   |   3 ++
 target-xtensa/cpu.c       |  30 ++++++++++--
 target-xtensa/cpu.h       |  22 +++++----
 target-xtensa/helper.c    |  93 +++++++++++++++++++++++------------
 target-xtensa/op_helper.c | 121 ++++++++++++++++++++++++++++++++--------------
 target-xtensa/translate.c |  12 +++--
 8 files changed, 236 insertions(+), 109 deletions(-)
Andreas Färber - July 6, 2013, 12:55 p.m.
Max,

Am 29.06.2013 22:01, schrieb Andreas Färber:
> Register a CPU type per core registered. Save the XtensaConfig in
> XtensaCPUClass instead of CPUXtensaState.
> 
> Prepares for storing per-class GDB register count.
> 
> Signed-off-by: Andreas Färber <afaerber@suse.de>

Ping! Can you ack? (It did not seem to break your test image.)

Thanks,
Andreas

> ---
>  gdbstub.c                 |  17 ++++---
>  hw/xtensa/pic_cpu.c       |  47 ++++++++++++------
>  target-xtensa/cpu-qom.h   |   3 ++
>  target-xtensa/cpu.c       |  30 ++++++++++--
>  target-xtensa/cpu.h       |  22 +++++----
>  target-xtensa/helper.c    |  93 +++++++++++++++++++++++------------
>  target-xtensa/op_helper.c | 121 ++++++++++++++++++++++++++++++++--------------
>  target-xtensa/translate.c |  12 +++--
>  8 files changed, 236 insertions(+), 109 deletions(-)
> 
> diff --git a/gdbstub.c b/gdbstub.c
> index 4ebe9e0..d08cfd3 100644
> --- a/gdbstub.c
> +++ b/gdbstub.c
> @@ -1692,14 +1692,16 @@ static int cpu_gdb_write_register(CPULM32State *env, uint8_t *mem_buf, int n)
>   * reset bit 0 in the 'flags' field of the registers definitions in the
>   * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
>   */
> -#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
> +#define NUM_CORE_REGS \
> +  (XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env))->config->gdb_regmap.num_regs)
>  #define num_g_regs NUM_CORE_REGS
>  
>  static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
>  {
> -    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
> +    const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
>  
> -    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
> +    if (n < 0 || n >= xcc->config->gdb_regmap.num_regs) {
>          return 0;
>      }
>  
> @@ -1710,7 +1712,7 @@ static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
>  
>      case 1: /*ar*/
>          xtensa_sync_phys_from_window(env);
> -        GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
> +        GET_REG32(env->phys_regs[(reg->targno & 0xff) % xcc->config->nareg]);
>          break;
>  
>      case 2: /*SR*/
> @@ -1738,10 +1740,11 @@ static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
>  
>  static int cpu_gdb_write_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
>  {
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
>      uint32_t tmp;
> -    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
> +    const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
>  
> -    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
> +    if (n < 0 || n >= xcc->config->gdb_regmap.num_regs) {
>          return 0;
>      }
>  
> @@ -1753,7 +1756,7 @@ static int cpu_gdb_write_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
>          break;
>  
>      case 1: /*ar*/
> -        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
> +        env->phys_regs[(reg->targno & 0xff) % xcc->config->nareg] = tmp;
>          xtensa_sync_window_from_phys(env);
>          break;
>  
> diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
> index 7f015ff..048038d 100644
> --- a/hw/xtensa/pic_cpu.c
> +++ b/hw/xtensa/pic_cpu.c
> @@ -31,13 +31,15 @@
>  
>  void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      uint32_t old_ccount = env->sregs[CCOUNT];
>  
>      env->sregs[CCOUNT] += d;
>  
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
>          int i;
> -        for (i = 0; i < env->config->nccompare; ++i) {
> +        for (i = 0; i < xcc->config->nccompare; ++i) {
>              if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
>                  xtensa_timer_irq(env, i, 1);
>              }
> @@ -47,7 +49,9 @@ void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
>  
>  void check_interrupts(CPUXtensaState *env)
>  {
> -    CPUState *cs = CPU(xtensa_env_get_cpu(env));
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    CPUState *cs = CPU(cpu);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      int minlevel = xtensa_get_cintlevel(env);
>      uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
>      int level;
> @@ -60,11 +64,11 @@ void check_interrupts(CPUXtensaState *env)
>  
>          xtensa_advance_ccount(env,
>                  muldiv64(now - env->halt_clock,
> -                    env->config->clock_freq_khz, 1000000));
> +                    xcc->config->clock_freq_khz, 1000000));
>          env->halt_clock = now;
>      }
> -    for (level = env->config->nlevel; level > minlevel; --level) {
> -        if (env->config->level_mask[level] & int_set_enabled) {
> +    for (level = xcc->config->nlevel; level > minlevel; --level) {
> +        if (xcc->config->level_mask[level] & int_set_enabled) {
>              env->pending_irq_level = level;
>              cpu_interrupt(cs, CPU_INTERRUPT_HARD);
>              qemu_log_mask(CPU_LOG_INT,
> @@ -86,15 +90,17 @@ void check_interrupts(CPUXtensaState *env)
>  static void xtensa_set_irq(void *opaque, int irq, int active)
>  {
>      CPUXtensaState *env = opaque;
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>  
> -    if (irq >= env->config->ninterrupt) {
> +    if (irq >= xcc->config->ninterrupt) {
>          qemu_log("%s: bad IRQ %d\n", __func__, irq);
>      } else {
>          uint32_t irq_bit = 1 << irq;
>  
>          if (active) {
>              env->sregs[INTSET] |= irq_bit;
> -        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
> +        } else if (xcc->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
>              env->sregs[INTSET] &= ~irq_bit;
>          }
>  
> @@ -104,15 +110,20 @@ static void xtensa_set_irq(void *opaque, int irq, int active)
>  
>  void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
>  {
> -    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    qemu_set_irq(env->irq_inputs[xcc->config->timerint[id]], active);
>  }
>  
>  void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      int i;
>      uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
>  
> -    for (i = 0; i < env->config->nccompare; ++i) {
> +    for (i = 0; i < xcc->config->nccompare; ++i) {
>          if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
>                  wake_ccount - env->sregs[CCOUNT]) {
>              wake_ccount = env->sregs[CCOMPARE + i];
> @@ -121,7 +132,7 @@ void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
>      env->wake_ccount = wake_ccount;
>      qemu_mod_timer(env->ccompare_timer, env->halt_clock +
>              muldiv64(wake_ccount - env->sregs[CCOUNT],
> -                1000000, env->config->clock_freq_khz));
> +                1000000, xcc->config->clock_freq_khz));
>  }
>  
>  static void xtensa_ccompare_cb(void *opaque)
> @@ -143,11 +154,12 @@ static void xtensa_ccompare_cb(void *opaque)
>  void xtensa_irq_init(CPUXtensaState *env)
>  {
>      XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>  
>      env->irq_inputs = (void **)qemu_allocate_irqs(
> -            xtensa_set_irq, env, env->config->ninterrupt);
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
> -            env->config->nccompare > 0) {
> +            xtensa_set_irq, env, xcc->config->ninterrupt);
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
> +            xcc->config->nccompare > 0) {
>          env->ccompare_timer =
>              qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu);
>      }
> @@ -155,8 +167,11 @@ void xtensa_irq_init(CPUXtensaState *env)
>  
>  void *xtensa_get_extint(CPUXtensaState *env, unsigned extint)
>  {
> -    if (extint < env->config->nextint) {
> -        unsigned irq = env->config->extint[extint];
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (extint < xcc->config->nextint) {
> +        unsigned irq = xcc->config->extint[extint];
>          return env->irq_inputs[irq];
>      } else {
>          qemu_log("%s: trying to acquire invalid external interrupt %d\n",
> diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
> index 944d3cc..878eb15 100644
> --- a/target-xtensa/cpu-qom.h
> +++ b/target-xtensa/cpu-qom.h
> @@ -45,6 +45,7 @@
>   * XtensaCPUClass:
>   * @parent_realize: The parent class' realize handler.
>   * @parent_reset: The parent class' reset handler.
> + * @config: The CPU core configuration.
>   *
>   * An Xtensa CPU model.
>   */
> @@ -55,6 +56,8 @@ typedef struct XtensaCPUClass {
>  
>      DeviceRealize parent_realize;
>      void (*parent_reset)(CPUState *cpu);
> +
> +    const XtensaConfig *config;
>  } XtensaCPUClass;
>  
>  /**
> diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
> index 6556caa..75762ad 100644
> --- a/target-xtensa/cpu.c
> +++ b/target-xtensa/cpu.c
> @@ -50,20 +50,39 @@ static void xtensa_cpu_reset(CPUState *s)
>      xcc->parent_reset(s);
>  
>      env->exception_taken = 0;
> -    env->pc = env->config->exception_vector[EXC_RESET];
> +    env->pc = xcc->config->exception_vector[EXC_RESET];
>      env->sregs[LITBASE] &= ~1;
> -    env->sregs[PS] = xtensa_option_enabled(env->config,
> +    env->sregs[PS] = xtensa_option_enabled(xcc->config,
>              XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
> -    env->sregs[VECBASE] = env->config->vecbase;
> +    env->sregs[VECBASE] = xcc->config->vecbase;
>      env->sregs[IBREAKENABLE] = 0;
>      env->sregs[CACHEATTR] = 0x22222222;
> -    env->sregs[ATOMCTL] = xtensa_option_enabled(env->config,
> +    env->sregs[ATOMCTL] = xtensa_option_enabled(xcc->config,
>              XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15;
>  
>      env->pending_irq_level = 0;
>      reset_mmu(env);
>  }
>  
> +static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
> +{
> +    ObjectClass *oc;
> +    char *typename;
> +
> +    if (cpu_model == NULL) {
> +        return NULL;
> +    }
> +
> +    typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model);
> +    oc = object_class_by_name(typename);
> +    g_free(typename);
> +    if (!oc || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) ||
> +        object_class_is_abstract(oc)) {
> +        return NULL;
> +    }
> +    return oc;
> +}
> +
>  static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
>  {
>      XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
> @@ -105,6 +124,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
>      xcc->parent_reset = cc->reset;
>      cc->reset = xtensa_cpu_reset;
>  
> +    cc->class_by_name = xtensa_cpu_class_by_name;
>      cc->do_interrupt = xtensa_cpu_do_interrupt;
>      cc->dump_state = xtensa_cpu_dump_state;
>      cc->set_pc = xtensa_cpu_set_pc;
> @@ -119,7 +139,7 @@ static const TypeInfo xtensa_cpu_type_info = {
>      .parent = TYPE_CPU,
>      .instance_size = sizeof(XtensaCPU),
>      .instance_init = xtensa_cpu_initfn,
> -    .abstract = false,
> +    .abstract = true,
>      .class_size = sizeof(XtensaCPUClass),
>      .class_init = xtensa_cpu_class_init,
>  };
> diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
> index a8f02f6..9ad0ac6 100644
> --- a/target-xtensa/cpu.h
> +++ b/target-xtensa/cpu.h
> @@ -333,7 +333,6 @@ typedef struct XtensaConfigList {
>  } XtensaConfigList;
>  
>  typedef struct CPUXtensaState {
> -    const XtensaConfig *config;
>      uint32_t regs[16];
>      uint32_t pc;
>      uint32_t sregs[256];
> @@ -432,16 +431,18 @@ static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
>  
>  static inline int xtensa_get_cintlevel(const CPUXtensaState *env)
>  {
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
>      int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
> -    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
> -        level = env->config->excm_level;
> +    if ((env->sregs[PS] & PS_EXCM) && xcc->config->excm_level > level) {
> +        level = xcc->config->excm_level;
>      }
>      return level;
>  }
>  
>  static inline int xtensa_get_ring(const CPUXtensaState *env)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
>      } else {
>          return 0;
> @@ -450,7 +451,8 @@ static inline int xtensa_get_ring(const CPUXtensaState *env)
>  
>  static inline int xtensa_get_cring(const CPUXtensaState *env)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU) &&
>              (env->sregs[PS] & PS_EXCM) == 0) {
>          return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
>      } else {
> @@ -488,6 +490,8 @@ static inline int cpu_mmu_index(CPUXtensaState *env)
>  static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
>          target_ulong *cs_base, int *flags)
>  {
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
> +
>      *pc = env->pc;
>      *cs_base = 0;
>      *flags = 0;
> @@ -495,19 +499,19 @@ static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
>      if (env->sregs[PS] & PS_EXCM) {
>          *flags |= XTENSA_TBFLAG_EXCM;
>      }
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_EXTENDED_L32R) &&
>              (env->sregs[LITBASE] & 1)) {
>          *flags |= XTENSA_TBFLAG_LITBASE;
>      }
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) {
> -        if (xtensa_get_cintlevel(env) < env->config->debug_level) {
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_DEBUG)) {
> +        if (xtensa_get_cintlevel(env) < xcc->config->debug_level) {
>              *flags |= XTENSA_TBFLAG_DEBUG;
>          }
>          if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
>              *flags |= XTENSA_TBFLAG_ICOUNT;
>          }
>      }
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) {
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_COPROCESSOR)) {
>          *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT;
>      }
>  }
> diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
> index a67c849..a1e524d 100644
> --- a/target-xtensa/helper.c
> +++ b/target-xtensa/helper.c
> @@ -35,17 +35,36 @@
>  
>  static struct XtensaConfigList *xtensa_cores;
>  
> +static void xtensa_core_class_init(ObjectClass *oc, void *data)
> +{
> +    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
> +    const XtensaConfig *config = data;
> +
> +    xcc->config = config;
> +}
> +
>  void xtensa_register_core(XtensaConfigList *node)
>  {
> +    TypeInfo type = {
> +        .parent = TYPE_XTENSA_CPU,
> +        .class_init = xtensa_core_class_init,
> +        .class_data = (void *)node->config,
> +    };
> +
>      node->next = xtensa_cores;
>      xtensa_cores = node;
> +    type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name);
> +    type_register(&type);
> +    g_free((gpointer)type.name);
>  }
>  
>  static uint32_t check_hw_breakpoints(CPUXtensaState *env)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      unsigned i;
>  
> -    for (i = 0; i < env->config->ndbreak; ++i) {
> +    for (i = 0; i < xcc->config->ndbreak; ++i) {
>          if (env->cpu_watchpoint[i] &&
>                  env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
>              return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
> @@ -72,24 +91,17 @@ void xtensa_breakpoint_handler(CPUXtensaState *env)
>  
>  XtensaCPU *cpu_xtensa_init(const char *cpu_model)
>  {
> +    ObjectClass *oc;
>      XtensaCPU *cpu;
>      CPUXtensaState *env;
> -    const XtensaConfig *config = NULL;
> -    XtensaConfigList *core = xtensa_cores;
>  
> -    for (; core; core = core->next)
> -        if (strcmp(core->config->name, cpu_model) == 0) {
> -            config = core->config;
> -            break;
> -        }
> -
> -    if (config == NULL) {
> +    oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model);
> +    if (oc == NULL) {
>          return NULL;
>      }
>  
> -    cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
> +    cpu = XTENSA_CPU(object_new(object_class_get_name(oc)));
>      env = &cpu->env;
> -    env->config = config;
>  
>      xtensa_irq_init(env);
>  
> @@ -128,9 +140,12 @@ hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, uint64_t addr)
>  
>  static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
>  {
> -    if (xtensa_option_enabled(env->config,
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config,
>                  XTENSA_OPTION_RELOCATABLE_VECTOR)) {
> -        return vector - env->config->vecbase + env->sregs[VECBASE];
> +        return vector - xcc->config->vecbase + env->sregs[VECBASE];
>      } else {
>          return vector;
>      }
> @@ -144,11 +159,13 @@ static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
>   */
>  static void handle_interrupt(CPUXtensaState *env)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      int level = env->pending_irq_level;
>  
>      if (level > xtensa_get_cintlevel(env) &&
> -            level <= env->config->nlevel &&
> -            (env->config->level_mask[level] &
> +            level <= xcc->config->nlevel &&
> +            (xcc->config->level_mask[level] &
>               env->sregs[INTSET] &
>               env->sregs[INTENABLE])) {
>          if (level > 1) {
> @@ -157,12 +174,12 @@ static void handle_interrupt(CPUXtensaState *env)
>              env->sregs[PS] =
>                  (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
>              env->pc = relocated_vector(env,
> -                    env->config->interrupt_vector[level]);
> +                    xcc->config->interrupt_vector[level]);
>          } else {
>              env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
>  
>              if (env->sregs[PS] & PS_EXCM) {
> -                if (env->config->ndepc) {
> +                if (xcc->config->ndepc) {
>                      env->sregs[DEPC] = env->pc;
>                  } else {
>                      env->sregs[EPC1] = env->pc;
> @@ -182,6 +199,7 @@ static void handle_interrupt(CPUXtensaState *env)
>  void xtensa_cpu_do_interrupt(CPUState *cs)
>  {
>      XtensaCPU *cpu = XTENSA_CPU(cs);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      CPUXtensaState *env = &cpu->env;
>  
>      if (env->exception_index == EXC_IRQ) {
> @@ -212,9 +230,9 @@ void xtensa_cpu_do_interrupt(CPUState *cs)
>                  "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
>                  __func__, env->exception_index,
>                  env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
> -        if (env->config->exception_vector[env->exception_index]) {
> +        if (xcc->config->exception_vector[env->exception_index]) {
>              env->pc = relocated_vector(env,
> -                    env->config->exception_vector[env->exception_index]);
> +                    xcc->config->exception_vector[env->exception_index]);
>              env->exception_taken = 1;
>          } else {
>              qemu_log("%s(pc = %08x) bad exception_index: %d\n",
> @@ -309,15 +327,18 @@ static void reset_tlb_region_way0(CPUXtensaState *env,
>  
>  void reset_mmu(CPUXtensaState *env)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          env->sregs[RASID] = 0x04030201;
>          env->sregs[ITLBCFG] = 0;
>          env->sregs[DTLBCFG] = 0;
>          env->autorefill_idx = 0;
> -        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
> -        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
> -        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
> -        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
> +        reset_tlb_mmu_all_ways(env, &xcc->config->itlb, env->itlb);
> +        reset_tlb_mmu_all_ways(env, &xcc->config->dtlb, env->dtlb);
> +        reset_tlb_mmu_ways56(env, &xcc->config->itlb, env->itlb);
> +        reset_tlb_mmu_ways56(env, &xcc->config->dtlb, env->dtlb);
>      } else {
>          reset_tlb_region_way0(env, env->itlb);
>          reset_tlb_region_way0(env, env->dtlb);
> @@ -347,8 +368,10 @@ static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
>  int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
>          uint32_t *pwi, uint32_t *pei, uint8_t *pring)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      const xtensa_tlb *tlb = dtlb ?
> -        &env->config->dtlb : &env->config->itlb;
> +        &xcc->config->dtlb : &xcc->config->itlb;
>      const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
>          env->dtlb : env->itlb;
>  
> @@ -586,10 +609,13 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
>          uint32_t vaddr, int is_write, int mmu_idx,
>          uint32_t *paddr, uint32_t *page_size, unsigned *access)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          return get_physical_addr_mmu(env, update_tlb,
>                  vaddr, is_write, mmu_idx, paddr, page_size, access, true);
> -    } else if (xtensa_option_bits_enabled(env->config,
> +    } else if (xtensa_option_bits_enabled(xcc->config,
>                  XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
>                  XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
>          return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
> @@ -606,11 +632,13 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
>  static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
>          CPUXtensaState *env, bool dtlb)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      unsigned wi, ei;
>      const xtensa_tlb *conf =
> -        dtlb ? &env->config->dtlb : &env->config->itlb;
> +        dtlb ? &xcc->config->dtlb : &xcc->config->itlb;
>      unsigned (*attr_to_access)(uint32_t) =
> -        xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
> +        xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU) ?
>          mmu_attr_to_access : region_attr_to_access;
>  
>      for (wi = 0; wi < conf->nways; ++wi) {
> @@ -666,7 +694,10 @@ static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
>  
>  void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env)
>  {
> -    if (xtensa_option_bits_enabled(env->config,
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_bits_enabled(xcc->config,
>                  XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
>                  XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
>                  XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
> diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
> index 4c41de0..2f08766 100644
> --- a/target-xtensa/op_helper.c
> +++ b/target-xtensa/op_helper.c
> @@ -50,8 +50,11 @@ static void do_unaligned_access(CPUXtensaState *env,
>  static void do_unaligned_access(CPUXtensaState *env,
>          target_ulong addr, int is_write, int is_user, uintptr_t retaddr)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
> -            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
> +            !xtensa_option_enabled(xcc->config, XTENSA_OPTION_HW_ALIGNMENT)) {
>          cpu_restore_state(env, retaddr);
>          HELPER(exception_cause_vaddr)(env,
>                  env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
> @@ -101,11 +104,13 @@ void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
>  
>  void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      uint32_t vector;
>  
>      env->pc = pc;
>      if (env->sregs[PS] & PS_EXCM) {
> -        if (env->config->ndepc) {
> +        if (xcc->config->ndepc) {
>              env->sregs[DEPC] = pc;
>          } else {
>              env->sregs[EPC1] = pc;
> @@ -131,14 +136,19 @@ void HELPER(exception_cause_vaddr)(CPUXtensaState *env,
>  
>  void debug_exception_env(CPUXtensaState *env, uint32_t cause)
>  {
> -    if (xtensa_get_cintlevel(env) < env->config->debug_level) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_get_cintlevel(env) < xcc->config->debug_level) {
>          HELPER(debug_exception)(env, env->pc, cause);
>      }
>  }
>  
>  void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
>  {
> -    unsigned level = env->config->debug_level;
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +    unsigned level = xcc->config->debug_level;
>  
>      env->pc = pc;
>      env->sregs[DEBUGCAUSE] = cause;
> @@ -165,12 +175,15 @@ uint32_t HELPER(nsau)(uint32_t v)
>  static void copy_window_from_phys(CPUXtensaState *env,
>          uint32_t window, uint32_t phys, uint32_t n)
>  {
> -    assert(phys < env->config->nareg);
> -    if (phys + n <= env->config->nareg) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    assert(phys < xcc->config->nareg);
> +    if (phys + n <= xcc->config->nareg) {
>          memcpy(env->regs + window, env->phys_regs + phys,
>                  n * sizeof(uint32_t));
>      } else {
> -        uint32_t n1 = env->config->nareg - phys;
> +        uint32_t n1 = xcc->config->nareg - phys;
>          memcpy(env->regs + window, env->phys_regs + phys,
>                  n1 * sizeof(uint32_t));
>          memcpy(env->regs + window + n1, env->phys_regs,
> @@ -181,12 +194,15 @@ static void copy_window_from_phys(CPUXtensaState *env,
>  static void copy_phys_from_window(CPUXtensaState *env,
>          uint32_t phys, uint32_t window, uint32_t n)
>  {
> -    assert(phys < env->config->nareg);
> -    if (phys + n <= env->config->nareg) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    assert(phys < xcc->config->nareg);
> +    if (phys + n <= xcc->config->nareg) {
>          memcpy(env->phys_regs + phys, env->regs + window,
>                  n * sizeof(uint32_t));
>      } else {
> -        uint32_t n1 = env->config->nareg - phys;
> +        uint32_t n1 = xcc->config->nareg - phys;
>          memcpy(env->phys_regs + phys, env->regs + window,
>                  n1 * sizeof(uint32_t));
>          memcpy(env->phys_regs, env->regs + window + n1,
> @@ -197,7 +213,10 @@ static void copy_phys_from_window(CPUXtensaState *env,
>  
>  static inline unsigned windowbase_bound(unsigned a, const CPUXtensaState *env)
>  {
> -    return a & (env->config->nareg / 4 - 1);
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    return a & (xcc->config->nareg / 4 - 1);
>  }
>  
>  static inline unsigned windowstart_bit(unsigned a, const CPUXtensaState *env)
> @@ -375,7 +394,9 @@ void HELPER(dump_state)(CPUXtensaState *env)
>  
>  void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
>  {
> -    CPUState *cpu;
> +    CPUState *cs;
> +    XtensaCPU *cpu;
> +    XtensaCPUClass *xcc;
>  
>      env->pc = pc;
>      env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
> @@ -386,10 +407,12 @@ void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
>          return;
>      }
>  
> -    cpu = CPU(xtensa_env_get_cpu(env));
> +    cpu = xtensa_env_get_cpu(env);
> +    cs = CPU(cpu);
> +    xcc = XTENSA_CPU_GET_CLASS(cpu);
>      env->halt_clock = qemu_get_clock_ns(vm_clock);
> -    cpu->halted = 1;
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
> +    cs->halted = 1;
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
>          xtensa_rearm_ccompare_timer(env);
>      }
>      HELPER(exception)(env, EXCP_HLT);
> @@ -418,6 +441,8 @@ void HELPER(check_interrupts)(CPUXtensaState *env)
>   */
>  void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      uint32_t paddr, page_size, access;
>      uint32_t atomctl = env->sregs[ATOMCTL];
>      int rc = xtensa_get_physical_addr(env, true, vaddr, 1,
> @@ -441,7 +466,7 @@ void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
>       * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL)
>       * under the Conditional Store Option.
>       */
> -    if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
> +    if (!xtensa_option_enabled(xcc->config, XTENSA_OPTION_DCACHE)) {
>          access = PAGE_CACHE_BYPASS;
>      }
>  
> @@ -500,10 +525,13 @@ static uint32_t get_page_size(const CPUXtensaState *env, bool dtlb, uint32_t way
>   */
>  uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          bool varway56 = dtlb ?
> -            env->config->dtlb.varway56 :
> -            env->config->itlb.varway56;
> +            xcc->config->dtlb.varway56 :
> +            xcc->config->itlb.varway56;
>  
>          switch (way) {
>          case 4:
> @@ -537,18 +565,21 @@ uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t
>   */
>  static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
>      if (way < 4) {
>          bool is32 = (dtlb ?
> -                env->config->dtlb.nrefillentries :
> -                env->config->itlb.nrefillentries) == 32;
> +                xcc->config->dtlb.nrefillentries :
> +                xcc->config->itlb.nrefillentries) == 32;
>          return is32 ? 0xffff8000 : 0xffffc000;
>      } else if (way == 4) {
>          return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
>      } else if (way <= 6) {
>          uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
>          bool varway56 = dtlb ?
> -            env->config->dtlb.varway56 :
> -            env->config->itlb.varway56;
> +            xcc->config->dtlb.varway56 :
> +            xcc->config->itlb.varway56;
>  
>          if (varway56) {
>              return mask << (way == 5 ? 2 : 3);
> @@ -567,9 +598,11 @@ static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
>  void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
>          uint32_t *vpn, uint32_t wi, uint32_t *ei)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      bool varway56 = dtlb ?
> -        env->config->dtlb.varway56 :
> -        env->config->itlb.varway56;
> +        xcc->config->dtlb.varway56 :
> +        xcc->config->itlb.varway56;
>  
>      if (!dtlb) {
>          wi &= 7;
> @@ -577,8 +610,8 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
>  
>      if (wi < 4) {
>          bool is32 = (dtlb ?
> -                env->config->dtlb.nrefillentries :
> -                env->config->itlb.nrefillentries) == 32;
> +                xcc->config->dtlb.nrefillentries :
> +                xcc->config->itlb.nrefillentries) == 32;
>          *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
>      } else {
>          switch (wi) {
> @@ -622,7 +655,10 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
>  static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
>          uint32_t *vpn, uint32_t *wi, uint32_t *ei)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          *wi = v & (dtlb ? 0xf : 0x7);
>          split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
>      } else {
> @@ -648,7 +684,10 @@ static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
>  
>  uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          uint32_t wi;
>          const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
>          return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
> @@ -665,7 +704,10 @@ uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
>  
>  void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          uint32_t wi;
>          xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
>          if (entry->variable && entry->asid) {
> @@ -677,7 +719,10 @@ void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
>  
>  uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
>  {
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
> +
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          uint32_t wi;
>          uint32_t ei;
>          uint8_t ring;
> @@ -714,9 +759,11 @@ void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
>  void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
>          unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
>  
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
>          if (entry->variable) {
>              if (entry->asid) {
>                  tlb_flush_page(env, entry->vaddr);
> @@ -729,7 +776,7 @@ void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
>          }
>      } else {
>          tlb_flush_page(env, entry->vaddr);
> -        if (xtensa_option_enabled(env->config,
> +        if (xtensa_option_enabled(xcc->config,
>                      XTENSA_OPTION_REGION_TRANSLATION)) {
>              entry->paddr = pte & REGION_PAGE_MASK;
>          }
> @@ -749,15 +796,17 @@ void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
>  
>  void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v)
>  {
> +    XtensaCPU *cpu = xtensa_env_get_cpu(env);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      uint32_t change = v ^ env->sregs[IBREAKENABLE];
>      unsigned i;
>  
> -    for (i = 0; i < env->config->nibreak; ++i) {
> +    for (i = 0; i < xcc->config->nibreak; ++i) {
>          if (change & (1 << i)) {
>              tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
>          }
>      }
> -    env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
> +    env->sregs[IBREAKENABLE] = v & ((1 << xcc->config->nibreak) - 1);
>  }
>  
>  void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v)
> diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
> index cc36fa4..c64b54e 100644
> --- a/target-xtensa/translate.c
> +++ b/target-xtensa/translate.c
> @@ -2881,6 +2881,7 @@ static void gen_intermediate_code_internal(XtensaCPU *cpu,
>  {
>      CPUState *cs = CPU(cpu);
>      CPUXtensaState *env = &cpu->env;
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
>      DisasContext dc;
>      int insn_count = 0;
>      int j, lj = -1;
> @@ -2894,7 +2895,7 @@ static void gen_intermediate_code_internal(XtensaCPU *cpu,
>          max_insns = CF_COUNT_MASK;
>      }
>  
> -    dc.config = env->config;
> +    dc.config = xcc->config;
>      dc.singlestep_enabled = cs->singlestep_enabled;
>      dc.tb = tb;
>      dc.pc = pc_start;
> @@ -3021,13 +3022,14 @@ void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
>                             fprintf_function cpu_fprintf, int flags)
>  {
>      XtensaCPU *cpu = XTENSA_CPU(cs);
> +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cs);
>      CPUXtensaState *env = &cpu->env;
>      int i, j;
>  
>      cpu_fprintf(f, "PC=%08x\n\n", env->pc);
>  
>      for (i = j = 0; i < 256; ++i) {
> -        if (xtensa_option_bits_enabled(env->config, sregnames[i].opt_bits)) {
> +        if (xtensa_option_bits_enabled(xcc->config, sregnames[i].opt_bits)) {
>              cpu_fprintf(f, "%12s=%08x%c", sregnames[i].name, env->sregs[i],
>                      (j++ % 4) == 3 ? '\n' : ' ');
>          }
> @@ -3036,7 +3038,7 @@ void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
>      cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
>  
>      for (i = j = 0; i < 256; ++i) {
> -        if (xtensa_option_bits_enabled(env->config, uregnames[i].opt_bits)) {
> +        if (xtensa_option_bits_enabled(xcc->config, uregnames[i].opt_bits)) {
>              cpu_fprintf(f, "%s=%08x%c", uregnames[i].name, env->uregs[i],
>                      (j++ % 4) == 3 ? '\n' : ' ');
>          }
> @@ -3051,12 +3053,12 @@ void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
>  
>      cpu_fprintf(f, "\n");
>  
> -    for (i = 0; i < env->config->nareg; ++i) {
> +    for (i = 0; i < xcc->config->nareg; ++i) {
>          cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
>                  (i % 4) == 3 ? '\n' : ' ');
>      }
>  
> -    if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) {
> +    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_FP_COPROCESSOR)) {
>          cpu_fprintf(f, "\n");
>  
>          for (i = 0; i < 16; ++i) {
>
Max Filippov - July 6, 2013, 6:01 p.m.
On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
> Max,
>
> Am 29.06.2013 22:01, schrieb Andreas Färber:
>> Register a CPU type per core registered. Save the XtensaConfig in
>> XtensaCPUClass instead of CPUXtensaState.
>>
>> Prepares for storing per-class GDB register count.
>>
>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>
> Ping! Can you ack? (It did not seem to break your test image.)

Hi Andreas,

I tried make check -C tests/tcg/xtensa with the branch you recommended
and it segfaults on elf loading:

#0  object_class_dynamic_cast_assert (class=0x0,
typename=typename@entry=0x55555573a85e "cpu",
file=file@entry=0x5555557349c8
"/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/include/qom/cpu.h",
line=line@entry=290, func=func@entry=
    0x555555735770 <__func__.17127> "cpu_get_phys_page_debug") at
/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/qom/object.c:535
#1  0x00005555556b884b in cpu_get_phys_page_debug (addr=3489660928,
cpu=0x555556275a30) at
/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/include/qom/cpu.h:290
#2  translate_phys_addr (env=0x555556275a30, addr=3489660928) at
/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/hw/xtensa/xtensa_sim.c:37
#3  0x0000555555602b9b in load_elf32 (clear_lsb=0, elf_machine=94,
highaddr=0x0, lowaddr=0x7fffffffd3b0, pentry=0x7fffffffd3a8,
must_swab=<optimized out>, translate_opaque=0x555556275a30,
translate_fn=
    0x5555556b8800 <translate_phys_addr>, fd=10, name=0x555556267df0
"./test_b.tst") at
/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/include/hw/elf_ops.h:269
#4  load_elf (filename=filename@entry=0x555556267df0 "./test_b.tst",
translate_fn=translate_fn@entry=0x5555556b8800 <translate_phys_addr>,
translate_opaque=translate_opaque@entry=0x555556275a30,
pentry=pentry@entry=
    0x7fffffffd3a8, lowaddr=lowaddr@entry=0x7fffffffd3b0,
highaddr=highaddr@entry=0x0, big_endian=big_endian@entry=0,
elf_machine=elf_machine@entry=94, clear_lsb=clear_lsb@entry=0)
    at /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/hw/core/loader.c:326
#5  0x00005555556b8a23 in xtensa_sim_init (args=<optimized out>) at
/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/hw/xtensa/xtensa_sim.c:94
#6  0x000055555559cf6f in main (argc=<optimized out>, argv=<optimized
out>, envp=<optimized out>) at
/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/vl.c:4286

The mainline is ok.
Max Filippov - July 6, 2013, 6:39 p.m.
On Sat, Jul 6, 2013 at 10:01 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
> On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
>> Max,
>>
>> Am 29.06.2013 22:01, schrieb Andreas Färber:
>>> Register a CPU type per core registered. Save the XtensaConfig in
>>> XtensaCPUClass instead of CPUXtensaState.
>>>
>>> Prepares for storing per-class GDB register count.
>>>
>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>
>> Ping! Can you ack? (It did not seem to break your test image.)
>
> Hi Andreas,
>
> I tried make check -C tests/tcg/xtensa with the branch you recommended
> and it segfaults on elf loading

...and maybe a stupid question, but why moving configuration pointer away
from env and then changing every place that used to access it?
Andreas Färber - July 6, 2013, 6:45 p.m.
Hi Max,

Am 06.07.2013 20:01, schrieb Max Filippov:
> On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
>> Am 29.06.2013 22:01, schrieb Andreas Färber:
>>> Register a CPU type per core registered. Save the XtensaConfig in
>>> XtensaCPUClass instead of CPUXtensaState.
>>>
>>> Prepares for storing per-class GDB register count.
>>>
>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>
>> Ping! Can you ack? (It did not seem to break your test image.)
> 
> I tried make check -C tests/tcg/xtensa with the branch you recommended
> and it segfaults on elf loading:

That's weird, I'm seeing a similar breakage with the test image on
today's qom-cpu-11 branch. It is not caused by this commit though, so
must be something I reordered last minute... sorry.

The make command above was not working, I've sent a patch for
out-of-tree builds and to update it to the current tree layout with tcg/
subdirectory.

Andreas

> #0  object_class_dynamic_cast_assert (class=0x0,
> typename=typename@entry=0x55555573a85e "cpu",
> file=file@entry=0x5555557349c8
> "/home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/include/qom/cpu.h",
> line=line@entry=290, func=func@entry=
>     0x555555735770 <__func__.17127> "cpu_get_phys_page_debug") at
> /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/qom/object.c:535
> #1  0x00005555556b884b in cpu_get_phys_page_debug (addr=3489660928,
> cpu=0x555556275a30) at
> /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/include/qom/cpu.h:290
> #2  translate_phys_addr (env=0x555556275a30, addr=3489660928) at
> /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/hw/xtensa/xtensa_sim.c:37
> #3  0x0000555555602b9b in load_elf32 (clear_lsb=0, elf_machine=94,
> highaddr=0x0, lowaddr=0x7fffffffd3b0, pentry=0x7fffffffd3a8,
> must_swab=<optimized out>, translate_opaque=0x555556275a30,
> translate_fn=
>     0x5555556b8800 <translate_phys_addr>, fd=10, name=0x555556267df0
> "./test_b.tst") at
> /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/include/hw/elf_ops.h:269
> #4  load_elf (filename=filename@entry=0x555556267df0 "./test_b.tst",
> translate_fn=translate_fn@entry=0x5555556b8800 <translate_phys_addr>,
> translate_opaque=translate_opaque@entry=0x555556275a30,
> pentry=pentry@entry=
>     0x7fffffffd3a8, lowaddr=lowaddr@entry=0x7fffffffd3b0,
> highaddr=highaddr@entry=0x0, big_endian=big_endian@entry=0,
> elf_machine=elf_machine@entry=94, clear_lsb=clear_lsb@entry=0)
>     at /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/hw/core/loader.c:326
> #5  0x00005555556b8a23 in xtensa_sim_init (args=<optimized out>) at
> /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/hw/xtensa/xtensa_sim.c:94
> #6  0x000055555559cf6f in main (argc=<optimized out>, argv=<optimized
> out>, envp=<optimized out>) at
> /home/jcmvbkbc/ws/m/awt/emu/xtensa/qemu/vl.c:4286
> 
> The mainline is ok.
>
Andreas Färber - July 6, 2013, 7:12 p.m.
Am 06.07.2013 20:39, schrieb Max Filippov:
> On Sat, Jul 6, 2013 at 10:01 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>> On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
>>> Am 29.06.2013 22:01, schrieb Andreas Färber:
>>>> Register a CPU type per core registered. Save the XtensaConfig in
>>>> XtensaCPUClass instead of CPUXtensaState.
>>>>
>>>> Prepares for storing per-class GDB register count.
>>>>
>>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>>
>>> Ping! Can you ack? (It did not seem to break your test image.)
>>
>> Hi Andreas,
>>
>> I tried make check -C tests/tcg/xtensa with the branch you recommended
>> and it segfaults on elf loading
> 
> ...and maybe a stupid question, but why moving configuration pointer away
> from env and then changing every place that used to access it?

Xtensa is the only target trying to implicitly access an "env" variable
through a macro to obtain the number of registers for gdbstub. That's
what I'm trying to fix with 40/41 in order to get rid of the #ifdeffery.

The number of registers is not accessed by TCG, so it could go into
XtensaCPU instead of CPUXtensaState.
Further it does not change during vCPU runtime, so it no longer belongs
in CPUXtensaState nor XtensaCPU but in XtensaCPUClass, which is shared
among CPU cores and can be accessed statically.
However we only had one XtensaCPUClass but multiple XtensaConfigs.
Therefore this patch registers one XtensaCPUClass per XtensaConfig.

You might remember that I once tried to place the XtensaConfig fields
directly into XtensaCPUClass but that didn't work out nicely back then.
This is by comparison a slim/minimal conversion to subclasses, leaving
XtensaConfig and your custom registration mechanisms in place. Cleaning
that up to use type_init() and type_register_static() in the respective
source files and changing -cpu ? to iterate QOM types would be a nice
follow-up, but not needed for this gdbstub refactoring series.

Another background is that I'm trying to get rid of cpu_init() and
anything that blocks using -device or device_add with QOM CPUs.

Regards,
Andreas
Max Filippov - July 6, 2013, 7:41 p.m.
On Sat, Jul 6, 2013 at 10:45 PM, Andreas Färber <afaerber@suse.de> wrote:
> Hi Max,
>
> Am 06.07.2013 20:01, schrieb Max Filippov:
>> On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
>>> Am 29.06.2013 22:01, schrieb Andreas Färber:
>>>> Register a CPU type per core registered. Save the XtensaConfig in
>>>> XtensaCPUClass instead of CPUXtensaState.
>>>>
>>>> Prepares for storing per-class GDB register count.
>>>>
>>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>>
>>> Ping! Can you ack? (It did not seem to break your test image.)
>>
>> I tried make check -C tests/tcg/xtensa with the branch you recommended
>> and it segfaults on elf loading:
>
> That's weird, I'm seeing a similar breakage with the test image on
> today's qom-cpu-11 branch. It is not caused by this commit though, so
> must be something I reordered last minute... sorry.
>
> The make command above was not working, I've sent a patch for
> out-of-tree builds and to update it to the current tree layout with tcg/
> subdirectory.

I have actually always been using it in-tree, adjusting PATH to pick up
qemu-system-xtensa from the correct build tree... I've made a couple
more fixes to your patch so that it actually builds and runs tests
out-of-tree.
Andreas Färber - July 6, 2013, 7:45 p.m.
Am 06.07.2013 20:01, schrieb Max Filippov:
> On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
>> Max,
>>
>> Am 29.06.2013 22:01, schrieb Andreas Färber:
>>> Register a CPU type per core registered. Save the XtensaConfig in
>>> XtensaCPUClass instead of CPUXtensaState.
>>>
>>> Prepares for storing per-class GDB register count.
>>>
>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>
>> Ping! Can you ack? (It did not seem to break your test image.)
> 
> Hi Andreas,
> 
> I tried make check -C tests/tcg/xtensa with the branch you recommended
> and it segfaults on elf loading:

First bad commit seems to be "cpu: Turn cpu_get_phys_page_debug() into a
CPUClass hook", investigating.

Andreas
Max Filippov - July 6, 2013, 7:54 p.m.
On Sat, Jul 6, 2013 at 11:12 PM, Andreas Färber <afaerber@suse.de> wrote:
> Am 06.07.2013 20:39, schrieb Max Filippov:
>> On Sat, Jul 6, 2013 at 10:01 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
>>> On Sat, Jul 6, 2013 at 4:55 PM, Andreas Färber <afaerber@suse.de> wrote:
>>>> Am 29.06.2013 22:01, schrieb Andreas Färber:
>>>>> Register a CPU type per core registered. Save the XtensaConfig in
>>>>> XtensaCPUClass instead of CPUXtensaState.
>>>>>
>>>>> Prepares for storing per-class GDB register count.
>>>>>
>>>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>>>
>>>> Ping! Can you ack? (It did not seem to break your test image.)
>>>
>>> Hi Andreas,
>>>
>>> I tried make check -C tests/tcg/xtensa with the branch you recommended
>>> and it segfaults on elf loading
>>
>> ...and maybe a stupid question, but why moving configuration pointer away
>> from env and then changing every place that used to access it?
>
> Xtensa is the only target trying to implicitly access an "env" variable
> through a macro to obtain the number of registers for gdbstub. That's
> what I'm trying to fix with 40/41 in order to get rid of the #ifdeffery.
>
> The number of registers is not accessed by TCG, so it could go into
> XtensaCPU instead of CPUXtensaState.
> Further it does not change during vCPU runtime, so it no longer belongs
> in CPUXtensaState nor XtensaCPU but in XtensaCPUClass, which is shared
> among CPU cores and can be accessed statically.

I'm concerned about two things here: adding boilerplate code to access
CPU class and doing more work at runtime than just following a pointer.
I mean that env->config is almost always used together with env itself,
could we consider env->config to be a cache for xcc->config?

> However we only had one XtensaCPUClass but multiple XtensaConfigs.
> Therefore this patch registers one XtensaCPUClass per XtensaConfig.
>
> You might remember that I once tried to place the XtensaConfig fields
> directly into XtensaCPUClass but that didn't work out nicely back then.
> This is by comparison a slim/minimal conversion to subclasses, leaving
> XtensaConfig and your custom registration mechanisms in place. Cleaning
> that up to use type_init() and type_register_static() in the respective
> source files and changing -cpu ? to iterate QOM types would be a nice
> follow-up, but not needed for this gdbstub refactoring series.
>
> Another background is that I'm trying to get rid of cpu_init() and
> anything that blocks using -device or device_add with QOM CPUs.
Andreas Färber - July 7, 2013, 6:51 p.m.
Am 06.07.2013 21:54, schrieb Max Filippov:
> On Sat, Jul 6, 2013 at 11:12 PM, Andreas Färber <afaerber@suse.de> wrote:
>> Am 06.07.2013 20:39, schrieb Max Filippov:
>>> ...and maybe a stupid question, but why moving configuration pointer away
>>> from env and then changing every place that used to access it?
>>
>> Xtensa is the only target trying to implicitly access an "env" variable
>> through a macro to obtain the number of registers for gdbstub. That's
>> what I'm trying to fix with 40/41 in order to get rid of the #ifdeffery.
>>
>> The number of registers is not accessed by TCG, so it could go into
>> XtensaCPU instead of CPUXtensaState.
>> Further it does not change during vCPU runtime, so it no longer belongs
>> in CPUXtensaState nor XtensaCPU but in XtensaCPUClass, which is shared
>> among CPU cores and can be accessed statically.
> 
> I'm concerned about two things here: adding boilerplate code to access
> CPU class and doing more work at runtime than just following a pointer.
> I mean that env->config is almost always used together with env itself,
> could we consider env->config to be a cache for xcc->config?

xtensa_env_get_cpu() after the recent patch in my queue no longer does a
cast, thus it's dirt cheap to switch between CPUXtensaState and
XtensaCPU (and back via ->env).

The ObjectClass is a pointer in Object, just like your XtensaConfig in
CPUXtensaState. Anthony has added a cast cache for v1.5 and Paolo a
configure option to turn cast checks off.

That leaves declaring an extra variable.

But since this is orthogonal to my gdbstub cleanups, v2 just initializes
env->config in XtensaCPU's instance_init, to keep the patch small while
keeping cpu_init() free of non-QOM initializations.
Anything else can be done later in an xtensa-only series.

Regards,
Andreas

Patch

diff --git a/gdbstub.c b/gdbstub.c
index 4ebe9e0..d08cfd3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1692,14 +1692,16 @@  static int cpu_gdb_write_register(CPULM32State *env, uint8_t *mem_buf, int n)
  * reset bit 0 in the 'flags' field of the registers definitions in the
  * gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
  */
-#define NUM_CORE_REGS (env->config->gdb_regmap.num_regs)
+#define NUM_CORE_REGS \
+  (XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env))->config->gdb_regmap.num_regs)
 #define num_g_regs NUM_CORE_REGS
 
 static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
 {
-    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
+    const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
 
-    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+    if (n < 0 || n >= xcc->config->gdb_regmap.num_regs) {
         return 0;
     }
 
@@ -1710,7 +1712,7 @@  static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
 
     case 1: /*ar*/
         xtensa_sync_phys_from_window(env);
-        GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nareg]);
+        GET_REG32(env->phys_regs[(reg->targno & 0xff) % xcc->config->nareg]);
         break;
 
     case 2: /*SR*/
@@ -1738,10 +1740,11 @@  static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
 
 static int cpu_gdb_write_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
 {
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
     uint32_t tmp;
-    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+    const XtensaGdbReg *reg = xcc->config->gdb_regmap.reg + n;
 
-    if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+    if (n < 0 || n >= xcc->config->gdb_regmap.num_regs) {
         return 0;
     }
 
@@ -1753,7 +1756,7 @@  static int cpu_gdb_write_register(CPUXtensaState *env, uint8_t *mem_buf, int n)
         break;
 
     case 1: /*ar*/
-        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
+        env->phys_regs[(reg->targno & 0xff) % xcc->config->nareg] = tmp;
         xtensa_sync_window_from_phys(env);
         break;
 
diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c
index 7f015ff..048038d 100644
--- a/hw/xtensa/pic_cpu.c
+++ b/hw/xtensa/pic_cpu.c
@@ -31,13 +31,15 @@ 
 
 void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     uint32_t old_ccount = env->sregs[CCOUNT];
 
     env->sregs[CCOUNT] += d;
 
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
         int i;
-        for (i = 0; i < env->config->nccompare; ++i) {
+        for (i = 0; i < xcc->config->nccompare; ++i) {
             if (env->sregs[CCOMPARE + i] - old_ccount <= d) {
                 xtensa_timer_irq(env, i, 1);
             }
@@ -47,7 +49,9 @@  void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
 
 void check_interrupts(CPUXtensaState *env)
 {
-    CPUState *cs = CPU(xtensa_env_get_cpu(env));
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    CPUState *cs = CPU(cpu);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     int minlevel = xtensa_get_cintlevel(env);
     uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
     int level;
@@ -60,11 +64,11 @@  void check_interrupts(CPUXtensaState *env)
 
         xtensa_advance_ccount(env,
                 muldiv64(now - env->halt_clock,
-                    env->config->clock_freq_khz, 1000000));
+                    xcc->config->clock_freq_khz, 1000000));
         env->halt_clock = now;
     }
-    for (level = env->config->nlevel; level > minlevel; --level) {
-        if (env->config->level_mask[level] & int_set_enabled) {
+    for (level = xcc->config->nlevel; level > minlevel; --level) {
+        if (xcc->config->level_mask[level] & int_set_enabled) {
             env->pending_irq_level = level;
             cpu_interrupt(cs, CPU_INTERRUPT_HARD);
             qemu_log_mask(CPU_LOG_INT,
@@ -86,15 +90,17 @@  void check_interrupts(CPUXtensaState *env)
 static void xtensa_set_irq(void *opaque, int irq, int active)
 {
     CPUXtensaState *env = opaque;
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
 
-    if (irq >= env->config->ninterrupt) {
+    if (irq >= xcc->config->ninterrupt) {
         qemu_log("%s: bad IRQ %d\n", __func__, irq);
     } else {
         uint32_t irq_bit = 1 << irq;
 
         if (active) {
             env->sregs[INTSET] |= irq_bit;
-        } else if (env->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
+        } else if (xcc->config->interrupt[irq].inttype == INTTYPE_LEVEL) {
             env->sregs[INTSET] &= ~irq_bit;
         }
 
@@ -104,15 +110,20 @@  static void xtensa_set_irq(void *opaque, int irq, int active)
 
 void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active)
 {
-    qemu_set_irq(env->irq_inputs[env->config->timerint[id]], active);
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    qemu_set_irq(env->irq_inputs[xcc->config->timerint[id]], active);
 }
 
 void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     int i;
     uint32_t wake_ccount = env->sregs[CCOUNT] - 1;
 
-    for (i = 0; i < env->config->nccompare; ++i) {
+    for (i = 0; i < xcc->config->nccompare; ++i) {
         if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
                 wake_ccount - env->sregs[CCOUNT]) {
             wake_ccount = env->sregs[CCOMPARE + i];
@@ -121,7 +132,7 @@  void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
     env->wake_ccount = wake_ccount;
     qemu_mod_timer(env->ccompare_timer, env->halt_clock +
             muldiv64(wake_ccount - env->sregs[CCOUNT],
-                1000000, env->config->clock_freq_khz));
+                1000000, xcc->config->clock_freq_khz));
 }
 
 static void xtensa_ccompare_cb(void *opaque)
@@ -143,11 +154,12 @@  static void xtensa_ccompare_cb(void *opaque)
 void xtensa_irq_init(CPUXtensaState *env)
 {
     XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
 
     env->irq_inputs = (void **)qemu_allocate_irqs(
-            xtensa_set_irq, env, env->config->ninterrupt);
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
-            env->config->nccompare > 0) {
+            xtensa_set_irq, env, xcc->config->ninterrupt);
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_TIMER_INTERRUPT) &&
+            xcc->config->nccompare > 0) {
         env->ccompare_timer =
             qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, cpu);
     }
@@ -155,8 +167,11 @@  void xtensa_irq_init(CPUXtensaState *env)
 
 void *xtensa_get_extint(CPUXtensaState *env, unsigned extint)
 {
-    if (extint < env->config->nextint) {
-        unsigned irq = env->config->extint[extint];
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (extint < xcc->config->nextint) {
+        unsigned irq = xcc->config->extint[extint];
         return env->irq_inputs[irq];
     } else {
         qemu_log("%s: trying to acquire invalid external interrupt %d\n",
diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h
index 944d3cc..878eb15 100644
--- a/target-xtensa/cpu-qom.h
+++ b/target-xtensa/cpu-qom.h
@@ -45,6 +45,7 @@ 
  * XtensaCPUClass:
  * @parent_realize: The parent class' realize handler.
  * @parent_reset: The parent class' reset handler.
+ * @config: The CPU core configuration.
  *
  * An Xtensa CPU model.
  */
@@ -55,6 +56,8 @@  typedef struct XtensaCPUClass {
 
     DeviceRealize parent_realize;
     void (*parent_reset)(CPUState *cpu);
+
+    const XtensaConfig *config;
 } XtensaCPUClass;
 
 /**
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 6556caa..75762ad 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -50,20 +50,39 @@  static void xtensa_cpu_reset(CPUState *s)
     xcc->parent_reset(s);
 
     env->exception_taken = 0;
-    env->pc = env->config->exception_vector[EXC_RESET];
+    env->pc = xcc->config->exception_vector[EXC_RESET];
     env->sregs[LITBASE] &= ~1;
-    env->sregs[PS] = xtensa_option_enabled(env->config,
+    env->sregs[PS] = xtensa_option_enabled(xcc->config,
             XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
-    env->sregs[VECBASE] = env->config->vecbase;
+    env->sregs[VECBASE] = xcc->config->vecbase;
     env->sregs[IBREAKENABLE] = 0;
     env->sregs[CACHEATTR] = 0x22222222;
-    env->sregs[ATOMCTL] = xtensa_option_enabled(env->config,
+    env->sregs[ATOMCTL] = xtensa_option_enabled(xcc->config,
             XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15;
 
     env->pending_irq_level = 0;
     reset_mmu(env);
 }
 
+static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
+{
+    ObjectClass *oc;
+    char *typename;
+
+    if (cpu_model == NULL) {
+        return NULL;
+    }
+
+    typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model);
+    oc = object_class_by_name(typename);
+    g_free(typename);
+    if (!oc || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) ||
+        object_class_is_abstract(oc)) {
+        return NULL;
+    }
+    return oc;
+}
+
 static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
@@ -105,6 +124,7 @@  static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
     xcc->parent_reset = cc->reset;
     cc->reset = xtensa_cpu_reset;
 
+    cc->class_by_name = xtensa_cpu_class_by_name;
     cc->do_interrupt = xtensa_cpu_do_interrupt;
     cc->dump_state = xtensa_cpu_dump_state;
     cc->set_pc = xtensa_cpu_set_pc;
@@ -119,7 +139,7 @@  static const TypeInfo xtensa_cpu_type_info = {
     .parent = TYPE_CPU,
     .instance_size = sizeof(XtensaCPU),
     .instance_init = xtensa_cpu_initfn,
-    .abstract = false,
+    .abstract = true,
     .class_size = sizeof(XtensaCPUClass),
     .class_init = xtensa_cpu_class_init,
 };
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index a8f02f6..9ad0ac6 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -333,7 +333,6 @@  typedef struct XtensaConfigList {
 } XtensaConfigList;
 
 typedef struct CPUXtensaState {
-    const XtensaConfig *config;
     uint32_t regs[16];
     uint32_t pc;
     uint32_t sregs[256];
@@ -432,16 +431,18 @@  static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
 
 static inline int xtensa_get_cintlevel(const CPUXtensaState *env)
 {
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
     int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
-    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
-        level = env->config->excm_level;
+    if ((env->sregs[PS] & PS_EXCM) && xcc->config->excm_level > level) {
+        level = xcc->config->excm_level;
     }
     return level;
 }
 
 static inline int xtensa_get_ring(const CPUXtensaState *env)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
     } else {
         return 0;
@@ -450,7 +451,8 @@  static inline int xtensa_get_ring(const CPUXtensaState *env)
 
 static inline int xtensa_get_cring(const CPUXtensaState *env)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU) &&
             (env->sregs[PS] & PS_EXCM) == 0) {
         return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
     } else {
@@ -488,6 +490,8 @@  static inline int cpu_mmu_index(CPUXtensaState *env)
 static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
         target_ulong *cs_base, int *flags)
 {
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(xtensa_env_get_cpu(env));
+
     *pc = env->pc;
     *cs_base = 0;
     *flags = 0;
@@ -495,19 +499,19 @@  static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc,
     if (env->sregs[PS] & PS_EXCM) {
         *flags |= XTENSA_TBFLAG_EXCM;
     }
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_EXTENDED_L32R) &&
             (env->sregs[LITBASE] & 1)) {
         *flags |= XTENSA_TBFLAG_LITBASE;
     }
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) {
-        if (xtensa_get_cintlevel(env) < env->config->debug_level) {
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_DEBUG)) {
+        if (xtensa_get_cintlevel(env) < xcc->config->debug_level) {
             *flags |= XTENSA_TBFLAG_DEBUG;
         }
         if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
             *flags |= XTENSA_TBFLAG_ICOUNT;
         }
     }
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) {
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_COPROCESSOR)) {
         *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT;
     }
 }
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index a67c849..a1e524d 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -35,17 +35,36 @@ 
 
 static struct XtensaConfigList *xtensa_cores;
 
+static void xtensa_core_class_init(ObjectClass *oc, void *data)
+{
+    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
+    const XtensaConfig *config = data;
+
+    xcc->config = config;
+}
+
 void xtensa_register_core(XtensaConfigList *node)
 {
+    TypeInfo type = {
+        .parent = TYPE_XTENSA_CPU,
+        .class_init = xtensa_core_class_init,
+        .class_data = (void *)node->config,
+    };
+
     node->next = xtensa_cores;
     xtensa_cores = node;
+    type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name);
+    type_register(&type);
+    g_free((gpointer)type.name);
 }
 
 static uint32_t check_hw_breakpoints(CPUXtensaState *env)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     unsigned i;
 
-    for (i = 0; i < env->config->ndbreak; ++i) {
+    for (i = 0; i < xcc->config->ndbreak; ++i) {
         if (env->cpu_watchpoint[i] &&
                 env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
             return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
@@ -72,24 +91,17 @@  void xtensa_breakpoint_handler(CPUXtensaState *env)
 
 XtensaCPU *cpu_xtensa_init(const char *cpu_model)
 {
+    ObjectClass *oc;
     XtensaCPU *cpu;
     CPUXtensaState *env;
-    const XtensaConfig *config = NULL;
-    XtensaConfigList *core = xtensa_cores;
 
-    for (; core; core = core->next)
-        if (strcmp(core->config->name, cpu_model) == 0) {
-            config = core->config;
-            break;
-        }
-
-    if (config == NULL) {
+    oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model);
+    if (oc == NULL) {
         return NULL;
     }
 
-    cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
+    cpu = XTENSA_CPU(object_new(object_class_get_name(oc)));
     env = &cpu->env;
-    env->config = config;
 
     xtensa_irq_init(env);
 
@@ -128,9 +140,12 @@  hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, uint64_t addr)
 
 static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
 {
-    if (xtensa_option_enabled(env->config,
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config,
                 XTENSA_OPTION_RELOCATABLE_VECTOR)) {
-        return vector - env->config->vecbase + env->sregs[VECBASE];
+        return vector - xcc->config->vecbase + env->sregs[VECBASE];
     } else {
         return vector;
     }
@@ -144,11 +159,13 @@  static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
  */
 static void handle_interrupt(CPUXtensaState *env)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     int level = env->pending_irq_level;
 
     if (level > xtensa_get_cintlevel(env) &&
-            level <= env->config->nlevel &&
-            (env->config->level_mask[level] &
+            level <= xcc->config->nlevel &&
+            (xcc->config->level_mask[level] &
              env->sregs[INTSET] &
              env->sregs[INTENABLE])) {
         if (level > 1) {
@@ -157,12 +174,12 @@  static void handle_interrupt(CPUXtensaState *env)
             env->sregs[PS] =
                 (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM;
             env->pc = relocated_vector(env,
-                    env->config->interrupt_vector[level]);
+                    xcc->config->interrupt_vector[level]);
         } else {
             env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
 
             if (env->sregs[PS] & PS_EXCM) {
-                if (env->config->ndepc) {
+                if (xcc->config->ndepc) {
                     env->sregs[DEPC] = env->pc;
                 } else {
                     env->sregs[EPC1] = env->pc;
@@ -182,6 +199,7 @@  static void handle_interrupt(CPUXtensaState *env)
 void xtensa_cpu_do_interrupt(CPUState *cs)
 {
     XtensaCPU *cpu = XTENSA_CPU(cs);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     CPUXtensaState *env = &cpu->env;
 
     if (env->exception_index == EXC_IRQ) {
@@ -212,9 +230,9 @@  void xtensa_cpu_do_interrupt(CPUState *cs)
                 "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n",
                 __func__, env->exception_index,
                 env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]);
-        if (env->config->exception_vector[env->exception_index]) {
+        if (xcc->config->exception_vector[env->exception_index]) {
             env->pc = relocated_vector(env,
-                    env->config->exception_vector[env->exception_index]);
+                    xcc->config->exception_vector[env->exception_index]);
             env->exception_taken = 1;
         } else {
             qemu_log("%s(pc = %08x) bad exception_index: %d\n",
@@ -309,15 +327,18 @@  static void reset_tlb_region_way0(CPUXtensaState *env,
 
 void reset_mmu(CPUXtensaState *env)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         env->sregs[RASID] = 0x04030201;
         env->sregs[ITLBCFG] = 0;
         env->sregs[DTLBCFG] = 0;
         env->autorefill_idx = 0;
-        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb);
-        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb);
-        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb);
-        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb);
+        reset_tlb_mmu_all_ways(env, &xcc->config->itlb, env->itlb);
+        reset_tlb_mmu_all_ways(env, &xcc->config->dtlb, env->dtlb);
+        reset_tlb_mmu_ways56(env, &xcc->config->itlb, env->itlb);
+        reset_tlb_mmu_ways56(env, &xcc->config->dtlb, env->dtlb);
     } else {
         reset_tlb_region_way0(env, env->itlb);
         reset_tlb_region_way0(env, env->dtlb);
@@ -347,8 +368,10 @@  static unsigned get_ring(const CPUXtensaState *env, uint8_t asid)
 int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb,
         uint32_t *pwi, uint32_t *pei, uint8_t *pring)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     const xtensa_tlb *tlb = dtlb ?
-        &env->config->dtlb : &env->config->itlb;
+        &xcc->config->dtlb : &xcc->config->itlb;
     const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
         env->dtlb : env->itlb;
 
@@ -586,10 +609,13 @@  int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
         uint32_t vaddr, int is_write, int mmu_idx,
         uint32_t *paddr, uint32_t *page_size, unsigned *access)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         return get_physical_addr_mmu(env, update_tlb,
                 vaddr, is_write, mmu_idx, paddr, page_size, access, true);
-    } else if (xtensa_option_bits_enabled(env->config,
+    } else if (xtensa_option_bits_enabled(xcc->config,
                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) {
         return get_physical_addr_region(env, vaddr, is_write, mmu_idx,
@@ -606,11 +632,13 @@  int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb,
 static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
         CPUXtensaState *env, bool dtlb)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     unsigned wi, ei;
     const xtensa_tlb *conf =
-        dtlb ? &env->config->dtlb : &env->config->itlb;
+        dtlb ? &xcc->config->dtlb : &xcc->config->itlb;
     unsigned (*attr_to_access)(uint32_t) =
-        xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
+        xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU) ?
         mmu_attr_to_access : region_attr_to_access;
 
     for (wi = 0; wi < conf->nways; ++wi) {
@@ -666,7 +694,10 @@  static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
 
 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env)
 {
-    if (xtensa_option_bits_enabled(env->config,
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_bits_enabled(xcc->config,
                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
                 XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
                 XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index 4c41de0..2f08766 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -50,8 +50,11 @@  static void do_unaligned_access(CPUXtensaState *env,
 static void do_unaligned_access(CPUXtensaState *env,
         target_ulong addr, int is_write, int is_user, uintptr_t retaddr)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
-            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
+            !xtensa_option_enabled(xcc->config, XTENSA_OPTION_HW_ALIGNMENT)) {
         cpu_restore_state(env, retaddr);
         HELPER(exception_cause_vaddr)(env,
                 env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
@@ -101,11 +104,13 @@  void HELPER(exception)(CPUXtensaState *env, uint32_t excp)
 
 void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     uint32_t vector;
 
     env->pc = pc;
     if (env->sregs[PS] & PS_EXCM) {
-        if (env->config->ndepc) {
+        if (xcc->config->ndepc) {
             env->sregs[DEPC] = pc;
         } else {
             env->sregs[EPC1] = pc;
@@ -131,14 +136,19 @@  void HELPER(exception_cause_vaddr)(CPUXtensaState *env,
 
 void debug_exception_env(CPUXtensaState *env, uint32_t cause)
 {
-    if (xtensa_get_cintlevel(env) < env->config->debug_level) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_get_cintlevel(env) < xcc->config->debug_level) {
         HELPER(debug_exception)(env, env->pc, cause);
     }
 }
 
 void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause)
 {
-    unsigned level = env->config->debug_level;
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+    unsigned level = xcc->config->debug_level;
 
     env->pc = pc;
     env->sregs[DEBUGCAUSE] = cause;
@@ -165,12 +175,15 @@  uint32_t HELPER(nsau)(uint32_t v)
 static void copy_window_from_phys(CPUXtensaState *env,
         uint32_t window, uint32_t phys, uint32_t n)
 {
-    assert(phys < env->config->nareg);
-    if (phys + n <= env->config->nareg) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    assert(phys < xcc->config->nareg);
+    if (phys + n <= xcc->config->nareg) {
         memcpy(env->regs + window, env->phys_regs + phys,
                 n * sizeof(uint32_t));
     } else {
-        uint32_t n1 = env->config->nareg - phys;
+        uint32_t n1 = xcc->config->nareg - phys;
         memcpy(env->regs + window, env->phys_regs + phys,
                 n1 * sizeof(uint32_t));
         memcpy(env->regs + window + n1, env->phys_regs,
@@ -181,12 +194,15 @@  static void copy_window_from_phys(CPUXtensaState *env,
 static void copy_phys_from_window(CPUXtensaState *env,
         uint32_t phys, uint32_t window, uint32_t n)
 {
-    assert(phys < env->config->nareg);
-    if (phys + n <= env->config->nareg) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    assert(phys < xcc->config->nareg);
+    if (phys + n <= xcc->config->nareg) {
         memcpy(env->phys_regs + phys, env->regs + window,
                 n * sizeof(uint32_t));
     } else {
-        uint32_t n1 = env->config->nareg - phys;
+        uint32_t n1 = xcc->config->nareg - phys;
         memcpy(env->phys_regs + phys, env->regs + window,
                 n1 * sizeof(uint32_t));
         memcpy(env->phys_regs, env->regs + window + n1,
@@ -197,7 +213,10 @@  static void copy_phys_from_window(CPUXtensaState *env,
 
 static inline unsigned windowbase_bound(unsigned a, const CPUXtensaState *env)
 {
-    return a & (env->config->nareg / 4 - 1);
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    return a & (xcc->config->nareg / 4 - 1);
 }
 
 static inline unsigned windowstart_bit(unsigned a, const CPUXtensaState *env)
@@ -375,7 +394,9 @@  void HELPER(dump_state)(CPUXtensaState *env)
 
 void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
 {
-    CPUState *cpu;
+    CPUState *cs;
+    XtensaCPU *cpu;
+    XtensaCPUClass *xcc;
 
     env->pc = pc;
     env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
@@ -386,10 +407,12 @@  void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel)
         return;
     }
 
-    cpu = CPU(xtensa_env_get_cpu(env));
+    cpu = xtensa_env_get_cpu(env);
+    cs = CPU(cpu);
+    xcc = XTENSA_CPU_GET_CLASS(cpu);
     env->halt_clock = qemu_get_clock_ns(vm_clock);
-    cpu->halted = 1;
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+    cs->halted = 1;
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
         xtensa_rearm_ccompare_timer(env);
     }
     HELPER(exception)(env, EXCP_HLT);
@@ -418,6 +441,8 @@  void HELPER(check_interrupts)(CPUXtensaState *env)
  */
 void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     uint32_t paddr, page_size, access;
     uint32_t atomctl = env->sregs[ATOMCTL];
     int rc = xtensa_get_physical_addr(env, true, vaddr, 1,
@@ -441,7 +466,7 @@  void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr)
      * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL)
      * under the Conditional Store Option.
      */
-    if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) {
+    if (!xtensa_option_enabled(xcc->config, XTENSA_OPTION_DCACHE)) {
         access = PAGE_CACHE_BYPASS;
     }
 
@@ -500,10 +525,13 @@  static uint32_t get_page_size(const CPUXtensaState *env, bool dtlb, uint32_t way
  */
 uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         bool varway56 = dtlb ?
-            env->config->dtlb.varway56 :
-            env->config->itlb.varway56;
+            xcc->config->dtlb.varway56 :
+            xcc->config->itlb.varway56;
 
         switch (way) {
         case 4:
@@ -537,18 +565,21 @@  uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t
  */
 static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
     if (way < 4) {
         bool is32 = (dtlb ?
-                env->config->dtlb.nrefillentries :
-                env->config->itlb.nrefillentries) == 32;
+                xcc->config->dtlb.nrefillentries :
+                xcc->config->itlb.nrefillentries) == 32;
         return is32 ? 0xffff8000 : 0xffffc000;
     } else if (way == 4) {
         return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2;
     } else if (way <= 6) {
         uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way);
         bool varway56 = dtlb ?
-            env->config->dtlb.varway56 :
-            env->config->itlb.varway56;
+            xcc->config->dtlb.varway56 :
+            xcc->config->itlb.varway56;
 
         if (varway56) {
             return mask << (way == 5 ? 2 : 3);
@@ -567,9 +598,11 @@  static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way)
 void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
         uint32_t *vpn, uint32_t wi, uint32_t *ei)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     bool varway56 = dtlb ?
-        env->config->dtlb.varway56 :
-        env->config->itlb.varway56;
+        xcc->config->dtlb.varway56 :
+        xcc->config->itlb.varway56;
 
     if (!dtlb) {
         wi &= 7;
@@ -577,8 +610,8 @@  void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
 
     if (wi < 4) {
         bool is32 = (dtlb ?
-                env->config->dtlb.nrefillentries :
-                env->config->itlb.nrefillentries) == 32;
+                xcc->config->dtlb.nrefillentries :
+                xcc->config->itlb.nrefillentries) == 32;
         *ei = (v >> 12) & (is32 ? 0x7 : 0x3);
     } else {
         switch (wi) {
@@ -622,7 +655,10 @@  void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
 static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb,
         uint32_t *vpn, uint32_t *wi, uint32_t *ei)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         *wi = v & (dtlb ? 0xf : 0x7);
         split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
     } else {
@@ -648,7 +684,10 @@  static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env,
 
 uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         uint32_t wi;
         const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
         return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
@@ -665,7 +704,10 @@  uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 
 void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         uint32_t wi;
         xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi);
         if (entry->variable && entry->asid) {
@@ -677,7 +719,10 @@  void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 
 uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb)
 {
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
+
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         uint32_t wi;
         uint32_t ei;
         uint8_t ring;
@@ -714,9 +759,11 @@  void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env,
 void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
         unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
 
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_MMU)) {
         if (entry->variable) {
             if (entry->asid) {
                 tlb_flush_page(env, entry->vaddr);
@@ -729,7 +776,7 @@  void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb,
         }
     } else {
         tlb_flush_page(env, entry->vaddr);
-        if (xtensa_option_enabled(env->config,
+        if (xtensa_option_enabled(xcc->config,
                     XTENSA_OPTION_REGION_TRANSLATION)) {
             entry->paddr = pte & REGION_PAGE_MASK;
         }
@@ -749,15 +796,17 @@  void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb)
 
 void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v)
 {
+    XtensaCPU *cpu = xtensa_env_get_cpu(env);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     uint32_t change = v ^ env->sregs[IBREAKENABLE];
     unsigned i;
 
-    for (i = 0; i < env->config->nibreak; ++i) {
+    for (i = 0; i < xcc->config->nibreak; ++i) {
         if (change & (1 << i)) {
             tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]);
         }
     }
-    env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
+    env->sregs[IBREAKENABLE] = v & ((1 << xcc->config->nibreak) - 1);
 }
 
 void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v)
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index cc36fa4..c64b54e 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -2881,6 +2881,7 @@  static void gen_intermediate_code_internal(XtensaCPU *cpu,
 {
     CPUState *cs = CPU(cpu);
     CPUXtensaState *env = &cpu->env;
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu);
     DisasContext dc;
     int insn_count = 0;
     int j, lj = -1;
@@ -2894,7 +2895,7 @@  static void gen_intermediate_code_internal(XtensaCPU *cpu,
         max_insns = CF_COUNT_MASK;
     }
 
-    dc.config = env->config;
+    dc.config = xcc->config;
     dc.singlestep_enabled = cs->singlestep_enabled;
     dc.tb = tb;
     dc.pc = pc_start;
@@ -3021,13 +3022,14 @@  void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
                            fprintf_function cpu_fprintf, int flags)
 {
     XtensaCPU *cpu = XTENSA_CPU(cs);
+    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cs);
     CPUXtensaState *env = &cpu->env;
     int i, j;
 
     cpu_fprintf(f, "PC=%08x\n\n", env->pc);
 
     for (i = j = 0; i < 256; ++i) {
-        if (xtensa_option_bits_enabled(env->config, sregnames[i].opt_bits)) {
+        if (xtensa_option_bits_enabled(xcc->config, sregnames[i].opt_bits)) {
             cpu_fprintf(f, "%12s=%08x%c", sregnames[i].name, env->sregs[i],
                     (j++ % 4) == 3 ? '\n' : ' ');
         }
@@ -3036,7 +3038,7 @@  void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
     cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n");
 
     for (i = j = 0; i < 256; ++i) {
-        if (xtensa_option_bits_enabled(env->config, uregnames[i].opt_bits)) {
+        if (xtensa_option_bits_enabled(xcc->config, uregnames[i].opt_bits)) {
             cpu_fprintf(f, "%s=%08x%c", uregnames[i].name, env->uregs[i],
                     (j++ % 4) == 3 ? '\n' : ' ');
         }
@@ -3051,12 +3053,12 @@  void xtensa_cpu_dump_state(CPUState *cs, FILE *f,
 
     cpu_fprintf(f, "\n");
 
-    for (i = 0; i < env->config->nareg; ++i) {
+    for (i = 0; i < xcc->config->nareg; ++i) {
         cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
                 (i % 4) == 3 ? '\n' : ' ');
     }
 
-    if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) {
+    if (xtensa_option_enabled(xcc->config, XTENSA_OPTION_FP_COPROCESSOR)) {
         cpu_fprintf(f, "\n");
 
         for (i = 0; i < 16; ++i) {