@@ -105,6 +105,7 @@ endif
libobj-$(TARGET_SPARC) += int32_helper.o
libobj-$(TARGET_SPARC64) += int64_helper.o
libobj-$(TARGET_UNICORE32) += cpu.o
+libobj-$(TARGET_XTENSA) += cpu.o
libobj-y += disas.o
libobj-$(CONFIG_TCI_DIS) += tci-dis.o
@@ -1570,14 +1570,17 @@ 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))->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;
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ const XtensaGdbReg *reg = klass->gdb_regmap.reg + n;
- if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+ if (n < 0 || n >= klass->gdb_regmap.num_regs) {
return 0;
}
@@ -1588,7 +1591,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) % klass->nareg]);
break;
case 2: /*SR*/
@@ -1613,9 +1616,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)
{
uint32_t tmp;
- const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ const XtensaGdbReg *reg = klass->gdb_regmap.reg + n;
- if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
+ if (n < 0 || n >= klass->gdb_regmap.num_regs) {
return 0;
}
@@ -1627,7 +1632,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) % klass->nareg] = tmp;
xtensa_sync_window_from_phys(env);
break;
@@ -31,13 +31,15 @@
void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = 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(klass, XTENSA_OPTION_TIMER_INTERRUPT)) {
int i;
- for (i = 0; i < env->config->nccompare; ++i) {
+ for (i = 0; i < klass->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)
{
- int minlevel = xtensa_get_cintlevel(env);
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ int minlevel = xtensa_get_cintlevel(cpu);
uint32_t int_set_enabled = env->sregs[INTSET] & env->sregs[INTENABLE];
int level;
@@ -59,11 +63,11 @@ void check_interrupts(CPUXtensaState *env)
xtensa_advance_ccount(env,
muldiv64(now - env->halt_clock,
- env->config->clock_freq_khz, 1000000));
+ klass->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 = klass->nlevel; level > minlevel; --level) {
+ if (klass->level_mask[level] & int_set_enabled) {
env->pending_irq_level = level;
cpu_interrupt(env, CPU_INTERRUPT_HARD);
qemu_log_mask(CPU_LOG_INT,
@@ -71,7 +75,7 @@ void check_interrupts(CPUXtensaState *env)
"pc = %08x, a0 = %08x, ps = %08x, "
"intset = %08x, intenable = %08x, "
"ccount = %08x\n",
- __func__, level, xtensa_get_cintlevel(env),
+ __func__, level, xtensa_get_cintlevel(cpu),
env->pc, env->regs[0], env->sregs[PS],
env->sregs[INTSET], env->sregs[INTENABLE],
env->sregs[CCOUNT]);
@@ -85,15 +89,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
- if (irq >= env->config->ninterrupt) {
+ if (irq >= klass->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 (klass->interrupt[irq].inttype == INTTYPE_LEVEL) {
env->sregs[INTSET] &= ~irq_bit;
}
@@ -103,15 +109,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ qemu_set_irq(env->irq_inputs[klass->timerint[id]], active);
}
void xtensa_rearm_ccompare_timer(CPUXtensaState *env)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = 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 < klass->nccompare; ++i) {
if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] <
wake_ccount - env->sregs[CCOUNT]) {
wake_ccount = env->sregs[CCOMPARE + i];
@@ -120,7 +131,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, klass->clock_freq_khz));
}
static void xtensa_ccompare_cb(void *opaque)
@@ -139,10 +150,13 @@ static void xtensa_ccompare_cb(void *opaque)
void xtensa_irq_init(CPUXtensaState *env)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = 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, klass->ninterrupt);
+ if (xtensa_option_enabled(klass, XTENSA_OPTION_TIMER_INTERRUPT) &&
+ klass->nccompare > 0) {
env->ccompare_timer =
qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env);
}
@@ -150,8 +164,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ if (extint < klass->nextint) {
+ unsigned irq = klass->extint[extint];
return env->irq_inputs[irq];
} else {
qemu_log("%s: trying to acquire invalid external interrupt %d\n",
@@ -6,8 +6,7 @@
#include "core-dc232b/core-isa.h"
#include "overlay_tool.h"
-static const XtensaConfig dc232b = {
- .name = "dc232b",
+static const XtensaCPUClass dc232b = {
.options = XTENSA_OPTIONS,
.gdb_regmap = {
.num_regs = 120,
@@ -25,4 +24,4 @@ static const XtensaConfig dc232b = {
.clock_freq_khz = 10000,
};
-REGISTER_CORE(dc232b)
+REGISTER_CORE("dc232b", dc232b)
@@ -6,8 +6,7 @@
#include "core-fsf/core-isa.h"
#include "overlay_tool.h"
-static const XtensaConfig fsf = {
- .name = "fsf",
+static const XtensaCPUClass fsf = {
.options = XTENSA_OPTIONS,
/* GDB for this core is not supported currently */
.nareg = XCHAL_NUM_AREGS,
@@ -19,4 +18,4 @@ static const XtensaConfig fsf = {
.clock_freq_khz = 10000,
};
-REGISTER_CORE(fsf)
+REGISTER_CORE("fsf", fsf)
new file mode 100644
@@ -0,0 +1,186 @@
+/*
+ * QEMU Xtensa CPU
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef QEMU_XTENSA_CPU_QOM_H
+#define QEMU_XTENSA_CPU_QOM_H
+
+#include "qemu/cpu.h"
+#include "cpu.h"
+
+#define TYPE_XTENSA_CPU "xtensa-cpu"
+
+#define XTENSA_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(XtensaCPUClass, (klass), TYPE_XTENSA_CPU)
+#define XTENSA_CPU(obj) \
+ OBJECT_CHECK(XtensaCPU, (obj), TYPE_XTENSA_CPU)
+#define XTENSA_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(XtensaCPUClass, (obj), TYPE_XTENSA_CPU)
+
+typedef struct xtensa_tlb {
+ unsigned nways;
+ const unsigned way_size[10];
+ bool varway56;
+ unsigned nrefillentries;
+} xtensa_tlb;
+
+typedef struct XtensaGdbReg {
+ int targno;
+ int type;
+ int group;
+} XtensaGdbReg;
+
+typedef struct XtensaGdbRegmap {
+ int num_regs;
+ int num_core_regs;
+ /* PC + a + ar + sr + ur */
+ XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
+} XtensaGdbRegmap;
+
+/**
+ * XtensaCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * An Xtensa CPU model.
+ */
+typedef struct XtensaCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+
+ uint64_t options;
+ XtensaGdbRegmap gdb_regmap;
+ unsigned nareg;
+ int excm_level;
+ int ndepc;
+ uint32_t vecbase;
+ uint32_t exception_vector[EXC_MAX];
+ unsigned ninterrupt;
+ unsigned nlevel;
+ uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1];
+ uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1];
+ uint32_t inttype_mask[INTTYPE_MAX];
+ struct {
+ uint32_t level;
+ interrupt_type inttype;
+ } interrupt[MAX_NINTERRUPT];
+ unsigned nccompare;
+ uint32_t timerint[MAX_NCCOMPARE];
+ unsigned nextint;
+ unsigned extint[MAX_NINTERRUPT];
+
+ unsigned debug_level;
+ unsigned nibreak;
+ unsigned ndbreak;
+
+ uint32_t clock_freq_khz;
+
+ xtensa_tlb itlb;
+ xtensa_tlb dtlb;
+} XtensaCPUClass;
+
+/**
+ * XtensaCPU:
+ * @env: Legacy CPU state.
+ *
+ * An Xtensa CPU.
+ */
+typedef struct XtensaCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUXtensaState env;
+} XtensaCPU;
+
+static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env)
+{
+ return XTENSA_CPU(container_of(env, XtensaCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(xtensa_env_get_cpu(e))
+
+
+#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
+
+static inline bool xtensa_option_bits_enabled(XtensaCPUClass *klass,
+ uint64_t opt)
+{
+ return (klass->options & opt) != 0;
+}
+
+static inline bool xtensa_option_enabled(XtensaCPUClass *klass, int opt)
+{
+ return xtensa_option_bits_enabled(klass, XTENSA_OPTION_BIT(opt));
+}
+
+static inline bool xtensa_cpu_option_enabled(XtensaCPU *cpu, int opt)
+{
+ return xtensa_option_enabled(XTENSA_CPU_GET_CLASS(cpu), opt);
+}
+
+static inline int xtensa_get_cintlevel(XtensaCPU *cpu)
+{
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ CPUXtensaState *env = &cpu->env;
+ int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
+ if ((env->sregs[PS] & PS_EXCM) && klass->excm_level > level) {
+ level = klass->excm_level;
+ }
+ return level;
+}
+
+static inline int xtensa_get_debug_level(XtensaCPU *cpu)
+{
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ return klass->debug_level;
+}
+
+static inline int xtensa_get_ring(XtensaCPU *cpu)
+{
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
+ return (cpu->env.sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+ } else {
+ return 0;
+ }
+}
+
+static inline int xtensa_get_cring(XtensaCPU *cpu)
+{
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU) &&
+ (cpu->env.sregs[PS] & PS_EXCM) == 0) {
+ return (cpu->env.sregs[PS] & PS_RING) >> PS_RING_SHIFT;
+ } else {
+ return 0;
+ }
+}
+
+
+#endif
new file mode 100644
@@ -0,0 +1,87 @@
+/*
+ * QEMU Xtensa CPU
+ *
+ * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab.
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Open Source and Linux Lab nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "cpu-qom.h"
+#include "qemu-common.h"
+
+static void xtensa_cpu_reset(CPUState *c)
+{
+ XtensaCPU *cpu = XTENSA_CPU(c);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ CPUXtensaState *env = &cpu->env;
+
+ klass->parent_reset(c);
+
+ env->exception_taken = 0;
+ env->pc = klass->exception_vector[EXC_RESET];
+ env->sregs[LITBASE] &= ~1;
+ env->sregs[PS] = xtensa_option_enabled(klass,
+ XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
+ env->sregs[VECBASE] = klass->vecbase;
+ env->sregs[IBREAKENABLE] = 0;
+
+ env->pending_irq_level = 0;
+ reset_mmu(cpu);
+}
+
+static void xtensa_cpu_initfn(Object *obj)
+{
+ XtensaCPU *cpu = XTENSA_CPU(obj);
+ CPUXtensaState *env = &cpu->env;
+
+ cpu_exec_init(env);
+ xtensa_irq_init(env);
+}
+
+static void xtensa_cpu_class_init(ObjectClass *klass, void *data)
+{
+ CPUClass *cpu_class = CPU_CLASS(klass);
+ XtensaCPUClass *k = XTENSA_CPU_CLASS(klass);
+
+ k->parent_reset = cpu_class->reset;
+ cpu_class->reset = xtensa_cpu_reset;
+}
+
+static const TypeInfo xtensa_cpu_info = {
+ .name = TYPE_XTENSA_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(XtensaCPU),
+ .instance_init = xtensa_cpu_initfn,
+ .abstract = true,
+ .class_size = sizeof(XtensaCPUClass),
+ .class_init = xtensa_cpu_class_init,
+};
+
+static void xtensa_cpu_register_types(void)
+{
+ type_register_static(&xtensa_cpu_info);
+}
+
+type_init(xtensa_cpu_register_types)
@@ -260,66 +260,7 @@ typedef struct xtensa_tlb_entry {
bool variable;
} xtensa_tlb_entry;
-typedef struct xtensa_tlb {
- unsigned nways;
- const unsigned way_size[10];
- bool varway56;
- unsigned nrefillentries;
-} xtensa_tlb;
-
-typedef struct XtensaGdbReg {
- int targno;
- int type;
- int group;
-} XtensaGdbReg;
-
-typedef struct XtensaGdbRegmap {
- int num_regs;
- int num_core_regs;
- /* PC + a + ar + sr + ur */
- XtensaGdbReg reg[1 + 16 + 64 + 256 + 256];
-} XtensaGdbRegmap;
-
-typedef struct XtensaConfig {
- const char *name;
- uint64_t options;
- XtensaGdbRegmap gdb_regmap;
- unsigned nareg;
- int excm_level;
- int ndepc;
- uint32_t vecbase;
- uint32_t exception_vector[EXC_MAX];
- unsigned ninterrupt;
- unsigned nlevel;
- uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1];
- uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1];
- uint32_t inttype_mask[INTTYPE_MAX];
- struct {
- uint32_t level;
- interrupt_type inttype;
- } interrupt[MAX_NINTERRUPT];
- unsigned nccompare;
- uint32_t timerint[MAX_NCCOMPARE];
- unsigned nextint;
- unsigned extint[MAX_NINTERRUPT];
-
- unsigned debug_level;
- unsigned nibreak;
- unsigned ndbreak;
-
- uint32_t clock_freq_khz;
-
- xtensa_tlb itlb;
- xtensa_tlb dtlb;
-} XtensaConfig;
-
-typedef struct XtensaConfigList {
- const XtensaConfig *config;
- struct XtensaConfigList *next;
-} XtensaConfigList;
-
typedef struct CPUXtensaState {
- const XtensaConfig *config;
uint32_t regs[16];
uint32_t pc;
uint32_t sregs[256];
@@ -350,10 +291,17 @@ typedef struct CPUXtensaState {
#define cpu_signal_handler cpu_xtensa_signal_handler
#define cpu_list xtensa_cpu_list
+typedef struct XtensaCPU XtensaCPU;
+static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env);
+static inline bool xtensa_cpu_option_enabled(XtensaCPU *klass, int opt);
+static inline int xtensa_get_cintlevel(XtensaCPU *cpu);
+static inline int xtensa_get_debug_level(XtensaCPU *cpu);
+static inline int xtensa_get_ring(XtensaCPU *cpu);
+static inline int xtensa_get_cring(XtensaCPU *cpu);
+
CPUXtensaState *cpu_xtensa_init(const char *cpu_model);
void xtensa_translate_init(void);
int cpu_xtensa_exec(CPUXtensaState *s);
-void xtensa_register_core(XtensaConfigList *node);
void do_interrupt(CPUXtensaState *s);
void check_interrupts(CPUXtensaState *s);
void xtensa_irq_init(CPUXtensaState *env);
@@ -377,49 +325,9 @@ int xtensa_get_physical_addr(CPUXtensaState *env,
uint32_t *paddr, uint32_t *page_size, unsigned *access);
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env);
void debug_exception_env(CPUXtensaState *new_env, uint32_t cause);
+void reset_mmu(XtensaCPU *cpu);
-#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt))
-
-static inline bool xtensa_option_bits_enabled(const XtensaConfig *config,
- uint64_t opt)
-{
- return (config->options & opt) != 0;
-}
-
-static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
-{
- return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt));
-}
-
-static inline int xtensa_get_cintlevel(const CPUXtensaState *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;
- }
- return level;
-}
-
-static inline int xtensa_get_ring(const CPUXtensaState *env)
-{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
- return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
- } else {
- return 0;
- }
-}
-
-static inline int xtensa_get_cring(const CPUXtensaState *env)
-{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) &&
- (env->sregs[PS] & PS_EXCM) == 0) {
- return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT;
- } else {
- return 0;
- }
-}
-
static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
bool dtlb, unsigned wi, unsigned ei)
{
@@ -436,7 +344,7 @@ static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env,
static inline int cpu_mmu_index(CPUXtensaState *env)
{
- return xtensa_get_cring(env);
+ return xtensa_get_cring(xtensa_env_get_cpu(env));
}
#define XTENSA_TBFLAG_RING_MASK 0x3
@@ -448,28 +356,31 @@ 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)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
*pc = env->pc;
*cs_base = 0;
*flags = 0;
- *flags |= xtensa_get_ring(env);
+ *flags |= xtensa_get_ring(cpu);
if (env->sregs[PS] & PS_EXCM) {
*flags |= XTENSA_TBFLAG_EXCM;
}
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) &&
+ if (xtensa_cpu_option_enabled(cpu, 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_cpu_option_enabled(cpu, XTENSA_OPTION_DEBUG)) {
+ if (xtensa_get_cintlevel(cpu) < xtensa_get_debug_level(cpu)) {
*flags |= XTENSA_TBFLAG_DEBUG;
}
- if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) {
+ if (xtensa_get_cintlevel(cpu) < env->sregs[ICOUNTLEVEL]) {
*flags |= XTENSA_TBFLAG_ICOUNT;
}
}
}
#include "cpu-all.h"
+#include "cpu-qom.h"
#include "exec-all.h"
static inline int cpu_has_work(CPUXtensaState *env)
@@ -33,35 +33,18 @@
#include "hw/loader.h"
#endif
-static void reset_mmu(CPUXtensaState *env);
-
void cpu_state_reset(CPUXtensaState *env)
{
- env->exception_taken = 0;
- env->pc = env->config->exception_vector[EXC_RESET];
- env->sregs[LITBASE] &= ~1;
- env->sregs[PS] = xtensa_option_enabled(env->config,
- XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10;
- env->sregs[VECBASE] = env->config->vecbase;
- env->sregs[IBREAKENABLE] = 0;
-
- env->pending_irq_level = 0;
- reset_mmu(env);
+ cpu_reset(ENV_GET_CPU(env));
}
-static struct XtensaConfigList *xtensa_cores;
-
-void xtensa_register_core(XtensaConfigList *node)
-{
- node->next = xtensa_cores;
- xtensa_cores = node;
-}
-
-static uint32_t check_hw_breakpoints(CPUXtensaState *env)
+static uint32_t check_hw_breakpoints(XtensaCPU *cpu)
{
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ CPUXtensaState *env = &cpu->env;
unsigned i;
- for (i = 0; i < env->config->ndbreak; ++i) {
+ for (i = 0; i < klass->ndbreak; ++i) {
if (env->cpu_watchpoint[i] &&
env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) {
return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT);
@@ -76,10 +59,11 @@ static void breakpoint_handler(CPUXtensaState *env)
{
if (env->watchpoint_hit) {
if (env->watchpoint_hit->flags & BP_CPU) {
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
uint32_t cause;
env->watchpoint_hit = NULL;
- cause = check_hw_breakpoints(env);
+ cause = check_hw_breakpoints(cpu);
if (cause) {
debug_exception_env(env, cause);
}
@@ -95,23 +79,14 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
{
static int tcg_inited;
static int debug_handler_inited;
+ 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) {
+ if (object_class_by_name(cpu_model) == NULL) {
return NULL;
}
-
- env = g_malloc0(sizeof(*env));
- env->config = config;
- cpu_exec_init(env);
+ cpu = XTENSA_CPU(object_new(cpu_model));
+ env = &cpu->env;
if (!tcg_inited) {
tcg_inited = 1;
@@ -124,19 +99,48 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_model)
cpu_set_debug_excp_handler(breakpoint_handler);
}
- xtensa_irq_init(env);
qemu_init_vcpu(env);
return env;
}
+typedef struct XtensaCPUListState {
+ fprintf_function cpu_fprintf;
+ FILE *file;
+} XtensaCPUListState;
+
+/* Sort alphabetically. */
+static gint xtensa_cpu_list_compare(gconstpointer a, gconstpointer b)
+{
+ ObjectClass *class_a = (ObjectClass *)a;
+ ObjectClass *class_b = (ObjectClass *)b;
+
+ return strcasecmp(object_class_get_name(class_a),
+ object_class_get_name(class_b));
+}
+
+static void xtensa_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ ObjectClass *klass = data;
+ XtensaCPUListState *s = user_data;
+
+ (*s->cpu_fprintf)(s->file, " %s\n",
+ object_class_get_name(klass));
+}
+
void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
- XtensaConfigList *core = xtensa_cores;
+ XtensaCPUListState s = {
+ .file = f,
+ .cpu_fprintf = cpu_fprintf,
+ };
+ GSList *list;
+
+ list = object_class_get_list(TYPE_XTENSA_CPU, false);
+ list = g_slist_sort(list, xtensa_cpu_list_compare);
cpu_fprintf(f, "Available CPUs:\n");
- for (; core; core = core->next) {
- cpu_fprintf(f, " %s\n", core->config->name);
- }
+ g_slist_foreach(list, xtensa_cpu_list_entry, &s);
+ g_slist_free(list);
}
target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong addr)
@@ -158,9 +162,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_ulong add
static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector)
{
- if (xtensa_option_enabled(env->config,
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ if (xtensa_option_enabled(klass,
XTENSA_OPTION_RELOCATABLE_VECTOR)) {
- return vector - env->config->vecbase + env->sregs[VECBASE];
+ return vector - klass->vecbase + env->sregs[VECBASE];
} else {
return vector;
}
@@ -174,11 +181,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 *klass = 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] &
+ if (level > xtensa_get_cintlevel(cpu) &&
+ level <= klass->nlevel &&
+ (klass->level_mask[level] &
env->sregs[INTSET] &
env->sregs[INTENABLE])) {
if (level > 1) {
@@ -187,12 +196,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]);
+ klass->interrupt_vector[level]);
} else {
env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE;
if (env->sregs[PS] & PS_EXCM) {
- if (env->config->ndepc) {
+ if (klass->ndepc) {
env->sregs[DEPC] = env->pc;
} else {
env->sregs[EPC1] = env->pc;
@@ -211,13 +220,16 @@ static void handle_interrupt(CPUXtensaState *env)
void do_interrupt(CPUXtensaState *env)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+
if (env->exception_index == EXC_IRQ) {
qemu_log_mask(CPU_LOG_INT,
"%s(EXC_IRQ) level = %d, cintlevel = %d, "
"pc = %08x, a0 = %08x, ps = %08x, "
"intset = %08x, intenable = %08x, "
"ccount = %08x\n",
- __func__, env->pending_irq_level, xtensa_get_cintlevel(env),
+ __func__, env->pending_irq_level, xtensa_get_cintlevel(cpu),
env->pc, env->regs[0], env->sregs[PS],
env->sregs[INTSET], env->sregs[INTENABLE],
env->sregs[CCOUNT]);
@@ -239,9 +251,9 @@ void do_interrupt(CPUXtensaState *env)
"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 (klass->exception_vector[env->exception_index]) {
env->pc = relocated_vector(env,
- env->config->exception_vector[env->exception_index]);
+ klass->exception_vector[env->exception_index]);
env->exception_taken = 1;
} else {
qemu_log("%s(pc = %08x) bad exception_index: %d\n",
@@ -334,17 +346,20 @@ static void reset_tlb_region_way0(CPUXtensaState *env,
}
}
-static void reset_mmu(CPUXtensaState *env)
+void reset_mmu(XtensaCPU *cpu)
{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
+ CPUXtensaState *env = &cpu->env;
+
+ if (xtensa_option_enabled(klass, 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, &klass->itlb, env->itlb);
+ reset_tlb_mmu_all_ways(env, &klass->dtlb, env->dtlb);
+ reset_tlb_mmu_ways56(env, &klass->itlb, env->itlb);
+ reset_tlb_mmu_ways56(env, &klass->dtlb, env->dtlb);
} else {
reset_tlb_region_way0(env, env->itlb);
reset_tlb_region_way0(env, env->dtlb);
@@ -374,8 +389,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
const xtensa_tlb *tlb = dtlb ?
- &env->config->dtlb : &env->config->itlb;
+ &klass->dtlb : &klass->itlb;
const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ?
env->dtlb : env->itlb;
@@ -567,10 +584,13 @@ int xtensa_get_physical_addr(CPUXtensaState *env,
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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ if (xtensa_option_enabled(klass, XTENSA_OPTION_MMU)) {
return get_physical_addr_mmu(env, vaddr, is_write, mmu_idx,
paddr, page_size, access);
- } else if (xtensa_option_bits_enabled(env->config,
+ } else if (xtensa_option_bits_enabled(klass,
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,
@@ -586,11 +606,13 @@ int xtensa_get_physical_addr(CPUXtensaState *env,
static void dump_tlb(FILE *f, fprintf_function cpu_fprintf,
CPUXtensaState *env, bool dtlb)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
unsigned wi, ei;
const xtensa_tlb *conf =
- dtlb ? &env->config->dtlb : &env->config->itlb;
+ dtlb ? &klass->dtlb : &klass->itlb;
unsigned (*attr_to_access)(uint32_t) =
- xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ?
+ xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU) ?
mmu_attr_to_access : region_attr_to_access;
for (wi = 0; wi < conf->nways; ++wi) {
@@ -636,7 +658,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ if (xtensa_option_bits_enabled(klass,
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) |
XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) |
XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) {
@@ -62,8 +62,10 @@ static void do_restore_state(void *pc_ptr)
static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
void *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);
+
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_UNALIGNED_EXCEPTION) &&
+ !xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_HW_ALIGNMENT)) {
do_restore_state(retaddr);
HELPER(exception_cause_vaddr)(
env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr);
@@ -107,11 +109,13 @@ void HELPER(exception)(uint32_t excp)
void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
uint32_t vector;
env->pc = pc;
if (env->sregs[PS] & PS_EXCM) {
- if (env->config->ndepc) {
+ if (klass->ndepc) {
env->sregs[DEPC] = pc;
} else {
env->sregs[EPC1] = pc;
@@ -136,7 +140,9 @@ void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
void debug_exception_env(CPUXtensaState *new_env, uint32_t cause)
{
- if (xtensa_get_cintlevel(new_env) < new_env->config->debug_level) {
+ XtensaCPU *new_cpu = xtensa_env_get_cpu(new_env);
+
+ if (xtensa_get_cintlevel(new_cpu) < xtensa_get_debug_level(new_cpu)) {
env = new_env;
HELPER(debug_exception)(env->pc, cause);
}
@@ -144,7 +150,8 @@ void debug_exception_env(CPUXtensaState *new_env, uint32_t cause)
void HELPER(debug_exception)(uint32_t pc, uint32_t cause)
{
- unsigned level = env->config->debug_level;
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ unsigned level = xtensa_get_debug_level(cpu);
env->pc = pc;
env->sregs[DEBUGCAUSE] = cause;
@@ -171,12 +178,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ assert(phys < klass->nareg);
+ if (phys + n <= klass->nareg) {
memcpy(env->regs + window, env->phys_regs + phys,
n * sizeof(uint32_t));
} else {
- uint32_t n1 = env->config->nareg - phys;
+ uint32_t n1 = klass->nareg - phys;
memcpy(env->regs + window, env->phys_regs + phys,
n1 * sizeof(uint32_t));
memcpy(env->regs + window + n1, env->phys_regs,
@@ -187,12 +197,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ assert(phys < klass->nareg);
+ if (phys + n <= klass->nareg) {
memcpy(env->phys_regs + phys, env->regs + window,
n * sizeof(uint32_t));
} else {
- uint32_t n1 = env->config->nareg - phys;
+ uint32_t n1 = klass->nareg - phys;
memcpy(env->phys_regs + phys, env->regs + window,
n1 * sizeof(uint32_t));
memcpy(env->phys_regs, env->regs + window + n1,
@@ -203,7 +216,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ return a & (klass->nareg / 4 - 1);
}
static inline unsigned windowstart_bit(unsigned a, const CPUXtensaState *env)
@@ -382,6 +398,8 @@ void HELPER(dump_state)(void)
void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
env->pc = pc;
env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) |
(intlevel << PS_INTLEVEL_SHIFT);
@@ -393,7 +411,7 @@ void HELPER(waiti)(uint32_t pc, uint32_t intlevel)
env->halt_clock = qemu_get_clock_ns(vm_clock);
env->halted = 1;
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) {
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_TIMER_INTERRUPT)) {
xtensa_rearm_ccompare_timer(env);
}
HELPER(exception)(EXCP_HLT);
@@ -447,10 +465,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
bool varway56 = dtlb ?
- env->config->dtlb.varway56 :
- env->config->itlb.varway56;
+ klass->dtlb.varway56 :
+ klass->itlb.varway56;
switch (way) {
case 4:
@@ -484,18 +505,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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
if (way < 4) {
bool is32 = (dtlb ?
- env->config->dtlb.nrefillentries :
- env->config->itlb.nrefillentries) == 32;
+ klass->dtlb.nrefillentries :
+ klass->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;
+ klass->dtlb.varway56 :
+ klass->itlb.varway56;
if (varway56) {
return mask << (way == 5 ? 2 : 3);
@@ -514,9 +538,12 @@ 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 *klass = XTENSA_CPU_GET_CLASS(cpu);
+
bool varway56 = dtlb ?
- env->config->dtlb.varway56 :
- env->config->itlb.varway56;
+ klass->dtlb.varway56 :
+ klass->itlb.varway56;
if (!dtlb) {
wi &= 7;
@@ -524,8 +551,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;
+ klass->dtlb.nrefillentries :
+ klass->itlb.nrefillentries) == 32;
*ei = (v >> 12) & (is32 ? 0x7 : 0x3);
} else {
switch (wi) {
@@ -569,7 +596,9 @@ void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb,
static void split_tlb_entry_spec(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);
+
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
*wi = v & (dtlb ? 0xf : 0x7);
split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei);
} else {
@@ -594,7 +623,9 @@ static xtensa_tlb_entry *get_tlb_entry(uint32_t v, bool dtlb, uint32_t *pwi)
uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb)
{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
uint32_t wi;
const xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid;
@@ -611,7 +642,9 @@ uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb)
void HELPER(itlb)(uint32_t v, uint32_t dtlb)
{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
uint32_t wi;
xtensa_tlb_entry *entry = get_tlb_entry(v, dtlb, &wi);
if (entry->variable && entry->asid) {
@@ -623,7 +656,9 @@ void HELPER(itlb)(uint32_t v, uint32_t dtlb)
uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
{
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
uint32_t wi;
uint32_t ei;
uint8_t ring;
@@ -631,7 +666,7 @@ uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
switch (res) {
case 0:
- if (ring >= xtensa_get_ring(env)) {
+ if (ring >= xtensa_get_ring(cpu)) {
return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8);
}
break;
@@ -650,9 +685,10 @@ uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb)
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);
xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei);
- if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
+ if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) {
if (entry->variable) {
if (entry->asid) {
tlb_flush_page(env, entry->vaddr);
@@ -667,7 +703,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_cpu_option_enabled(cpu,
XTENSA_OPTION_REGION_TRANSLATION)) {
entry->paddr = pte & REGION_PAGE_MASK;
}
@@ -687,16 +723,18 @@ void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t dtlb)
void HELPER(wsr_ibreakenable)(uint32_t v)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = 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 < klass->nibreak; ++i) {
if (change & (1 << i)) {
tb_invalidate_phys_page_range(
env->sregs[IBREAKA + i], env->sregs[IBREAKA + i] + 1, 0);
}
}
- env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1);
+ env->sregs[IBREAKENABLE] = v & ((1 << klass->nibreak) - 1);
}
void HELPER(wsr_ibreaka)(uint32_t i, uint32_t v)
@@ -291,16 +291,28 @@
#endif
#if (defined(TARGET_WORDS_BIGENDIAN) != 0) == (XCHAL_HAVE_BE != 0)
-#define REGISTER_CORE(core) \
- static void __attribute__((constructor)) register_core(void) \
+#define REGISTER_CORE(typename, class) \
+ static void core_class_init(ObjectClass *klass, void *data) \
{ \
- static XtensaConfigList node = { \
- .config = &core, \
- }; \
- xtensa_register_core(&node); \
- }
+ /* XXX This is a really ugly but easy way to init the class... */ \
+ memcpy((void *)klass + offsetof(XtensaCPUClass, options), \
+ (void *)&(class) + offsetof(XtensaCPUClass, options), \
+ sizeof(XtensaCPUClass) - offsetof(XtensaCPUClass, options)); \
+ } \
+ static const TypeInfo core_info = { \
+ .name = (typename), \
+ .parent = TYPE_XTENSA_CPU, \
+ .instance_size = sizeof(XtensaCPU), \
+ .class_size = sizeof(XtensaCPUClass), \
+ .class_init = core_class_init, \
+ }; \
+ static void register_core_type(void) \
+ { \
+ type_register_static(&core_info); \
+ } \
+ type_init(register_core_type)
#else
-#define REGISTER_CORE(core)
+#define REGISTER_CORE(name, core)
#endif
#define DEBUG_SECTION \
@@ -42,7 +42,7 @@
#include "helpers.h"
typedef struct DisasContext {
- const XtensaConfig *config;
+ XtensaCPUClass *config;
TranslationBlock *tb;
uint32_t pc;
uint32_t next_pc;
@@ -2524,6 +2524,7 @@ static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc)
static void gen_intermediate_code_internal(
CPUXtensaState *env, TranslationBlock *tb, int search_pc)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
DisasContext dc;
int insn_count = 0;
int j, lj = -1;
@@ -2537,7 +2538,7 @@ static void gen_intermediate_code_internal(
max_insns = CF_COUNT_MASK;
}
- dc.config = env->config;
+ dc.config = XTENSA_CPU_GET_CLASS(cpu);
dc.singlestep_enabled = env->singlestep_enabled;
dc.tb = tb;
dc.pc = pc_start;
@@ -2657,6 +2658,8 @@ void gen_intermediate_code_pc(CPUXtensaState *env, TranslationBlock *tb)
void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf,
int flags)
{
+ XtensaCPU *cpu = xtensa_env_get_cpu(env);
+ XtensaCPUClass *klass = XTENSA_CPU_GET_CLASS(cpu);
int i, j;
cpu_fprintf(f, "PC=%08x\n\n", env->pc);
@@ -2686,7 +2689,7 @@ void cpu_dump_state(CPUXtensaState *env, FILE *f, fprintf_function cpu_fprintf,
cpu_fprintf(f, "\n");
- for (i = 0; i < env->config->nareg; ++i) {
+ for (i = 0; i < klass->nareg; ++i) {
cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i],
(i % 4) == 3 ? '\n' : ' ');
}
Let xtensa_cpu_list() enumerate CPU classes alphabetically. Signed-off-by: Andreas Färber <afaerber@suse.de> --- Makefile.target | 1 + gdbstub.c | 19 +++-- hw/xtensa_pic.c | 51 ++++++++---- target-xtensa/core-dc232b.c | 5 +- target-xtensa/core-fsf.c | 5 +- target-xtensa/cpu-qom.h | 186 ++++++++++++++++++++++++++++++++++++++++++ target-xtensa/cpu.c | 87 ++++++++++++++++++++ target-xtensa/cpu.h | 125 ++++------------------------ target-xtensa/helper.c | 151 ++++++++++++++++++++-------------- target-xtensa/op_helper.c | 104 ++++++++++++++++-------- target-xtensa/overlay_tool.h | 28 +++++-- target-xtensa/translate.c | 9 ++- 12 files changed, 527 insertions(+), 244 deletions(-) create mode 100644 target-xtensa/cpu-qom.h create mode 100644 target-xtensa/cpu.c