Let xtensa_cpu_list() enumerate CPU classes alphabetically. Signed-off-by: Andreas Färber <afaer...@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
diff --git a/Makefile.target b/Makefile.target index 1c6ed12..3edbdfc 100644 --- a/Makefile.target +++ b/Makefile.target @@ -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 diff --git a/gdbstub.c b/gdbstub.c index f4e97f7..773e86f 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -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; diff --git a/hw/xtensa_pic.c b/hw/xtensa_pic.c index 653ded6..3d398a1 100644 --- a/hw/xtensa_pic.c +++ b/hw/xtensa_pic.c @@ -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", diff --git a/target-xtensa/core-dc232b.c b/target-xtensa/core-dc232b.c index 7c03835..a62ca6a 100644 --- a/target-xtensa/core-dc232b.c +++ b/target-xtensa/core-dc232b.c @@ -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) diff --git a/target-xtensa/core-fsf.c b/target-xtensa/core-fsf.c index c11d970..bcda18b 100644 --- a/target-xtensa/core-fsf.c +++ b/target-xtensa/core-fsf.c @@ -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) diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h new file mode 100644 index 0000000..e286458 --- /dev/null +++ b/target-xtensa/cpu-qom.h @@ -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 diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c new file mode 100644 index 0000000..54f4ffc --- /dev/null +++ b/target-xtensa/cpu.c @@ -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) diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index a7bcf52..1191dcf 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -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) diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index dab135c..3433228 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -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))) { diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index cdef0db..96d293f 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -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) diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h index a3a5650..b46bca9 100644 --- a/target-xtensa/overlay_tool.h +++ b/target-xtensa/overlay_tool.h @@ -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 \ diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index e0ff72b..b05b83e 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -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' : ' '); } -- 1.7.7