From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:56924) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S7sP1-00072a-Eg for qemu-devel@nongnu.org; Wed, 14 Mar 2012 13:54:32 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1S7sOO-0002dz-MN for qemu-devel@nongnu.org; Wed, 14 Mar 2012 13:54:23 -0400 Received: from cantor2.suse.de ([195.135.220.15]:51046 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1S7sOO-0002d1-3F for qemu-devel@nongnu.org; Wed, 14 Mar 2012 13:53:44 -0400 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 14 Mar 2012 18:53:36 +0100 Message-Id: <1331747617-7837-13-git-send-email-afaerber@suse.de> In-Reply-To: <1331747617-7837-1-git-send-email-afaerber@suse.de> References: <1330893156-26569-1-git-send-email-afaerber@suse.de> <1331747617-7837-1-git-send-email-afaerber@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [RFC 12/12] target-xtensa: QOM'ify CPU List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Max Filippov , =?UTF-8?q?Andreas=20F=C3=A4rber?= Let xtensa_cpu_list() enumerate CPU classes alphabetically. Signed-off-by: Andreas F=C3=A4rber --- 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) +=3D int32_helper.o libobj-$(TARGET_SPARC64) +=3D int64_helper.o libobj-$(TARGET_UNICORE32) +=3D cpu.o +libobj-$(TARGET_XTENSA) +=3D cpu.o =20 libobj-y +=3D disas.o libobj-$(CONFIG_TCI_DIS) +=3D 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 *e= nv, 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 =20 static int cpu_gdb_read_register(CPUXtensaState *env, uint8_t *mem_buf, = int n) { - const XtensaGdbReg *reg =3D env->config->gdb_regmap.reg + n; + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + const XtensaGdbReg *reg =3D klass->gdb_regmap.reg + n; =20 - if (n < 0 || n >=3D env->config->gdb_regmap.num_regs) { + if (n < 0 || n >=3D klass->gdb_regmap.num_regs) { return 0; } =20 @@ -1588,7 +1591,7 @@ static int cpu_gdb_read_register(CPUXtensaState *en= v, uint8_t *mem_buf, int n) =20 case 1: /*ar*/ xtensa_sync_phys_from_window(env); - GET_REG32(env->phys_regs[(reg->targno & 0xff) % env->config->nar= eg]); + GET_REG32(env->phys_regs[(reg->targno & 0xff) % klass->nareg]); break; =20 case 2: /*SR*/ @@ -1613,9 +1616,11 @@ static int cpu_gdb_read_register(CPUXtensaState *e= nv, 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 =3D env->config->gdb_regmap.reg + n; + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + const XtensaGdbReg *reg =3D klass->gdb_regmap.reg + n; =20 - if (n < 0 || n >=3D env->config->gdb_regmap.num_regs) { + if (n < 0 || n >=3D klass->gdb_regmap.num_regs) { return 0; } =20 @@ -1627,7 +1632,7 @@ static int cpu_gdb_write_register(CPUXtensaState *e= nv, uint8_t *mem_buf, int n) break; =20 case 1: /*ar*/ - env->phys_regs[(reg->targno & 0xff) % env->config->nareg] =3D tm= p; + env->phys_regs[(reg->targno & 0xff) % klass->nareg] =3D tmp; xtensa_sync_window_from_phys(env); break; =20 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 @@ =20 void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); uint32_t old_ccount =3D env->sregs[CCOUNT]; =20 env->sregs[CCOUNT] +=3D d; =20 - if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT= )) { + if (xtensa_option_enabled(klass, XTENSA_OPTION_TIMER_INTERRUPT)) { int i; - for (i =3D 0; i < env->config->nccompare; ++i) { + for (i =3D 0; i < klass->nccompare; ++i) { if (env->sregs[CCOMPARE + i] - old_ccount <=3D d) { xtensa_timer_irq(env, i, 1); } @@ -47,7 +49,9 @@ void xtensa_advance_ccount(CPUXtensaState *env, uint32_= t d) =20 void check_interrupts(CPUXtensaState *env) { - int minlevel =3D xtensa_get_cintlevel(env); + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + int minlevel =3D xtensa_get_cintlevel(cpu); uint32_t int_set_enabled =3D env->sregs[INTSET] & env->sregs[INTENAB= LE]; int level; =20 @@ -59,11 +63,11 @@ void check_interrupts(CPUXtensaState *env) =20 xtensa_advance_ccount(env, muldiv64(now - env->halt_clock, - env->config->clock_freq_khz, 1000000)); + klass->clock_freq_khz, 1000000)); env->halt_clock =3D now; } - for (level =3D env->config->nlevel; level > minlevel; --level) { - if (env->config->level_mask[level] & int_set_enabled) { + for (level =3D klass->nlevel; level > minlevel; --level) { + if (klass->level_mask[level] & int_set_enabled) { env->pending_irq_level =3D level; cpu_interrupt(env, CPU_INTERRUPT_HARD); qemu_log_mask(CPU_LOG_INT, @@ -71,7 +75,7 @@ void check_interrupts(CPUXtensaState *env) "pc =3D %08x, a0 =3D %08x, ps =3D %08x, " "intset =3D %08x, intenable =3D %08x, " "ccount =3D %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 =3D opaque; + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); =20 - if (irq >=3D env->config->ninterrupt) { + if (irq >=3D klass->ninterrupt) { qemu_log("%s: bad IRQ %d\n", __func__, irq); } else { uint32_t irq_bit =3D 1 << irq; =20 if (active) { env->sregs[INTSET] |=3D irq_bit; - } else if (env->config->interrupt[irq].inttype =3D=3D INTTYPE_LE= VEL) { + } else if (klass->interrupt[irq].inttype =3D=3D INTTYPE_LEVEL) { env->sregs[INTSET] &=3D ~irq_bit; } =20 @@ -103,15 +109,20 @@ static void xtensa_set_irq(void *opaque, int irq, i= nt active) =20 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 =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + + qemu_set_irq(env->irq_inputs[klass->timerint[id]], active); } =20 void xtensa_rearm_ccompare_timer(CPUXtensaState *env) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); int i; uint32_t wake_ccount =3D env->sregs[CCOUNT] - 1; =20 - for (i =3D 0; i < env->config->nccompare; ++i) { + for (i =3D 0; i < klass->nccompare; ++i) { if (env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] < wake_ccount - env->sregs[CCOUNT]) { wake_ccount =3D env->sregs[CCOMPARE + i]; @@ -120,7 +131,7 @@ void xtensa_rearm_ccompare_timer(CPUXtensaState *env) env->wake_ccount =3D 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)); } =20 static void xtensa_ccompare_cb(void *opaque) @@ -139,10 +150,13 @@ static void xtensa_ccompare_cb(void *opaque) =20 void xtensa_irq_init(CPUXtensaState *env) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + env->irq_inputs =3D (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 =3D qemu_new_timer_ns(vm_clock, &xtensa_ccompare_cb, env); } @@ -150,8 +164,11 @@ void xtensa_irq_init(CPUXtensaState *env) =20 void *xtensa_get_extint(CPUXtensaState *env, unsigned extint) { - if (extint < env->config->nextint) { - unsigned irq =3D env->config->extint[extint]; + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + + if (extint < klass->nextint) { + unsigned irq =3D 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" =20 -static const XtensaConfig dc232b =3D { - .name =3D "dc232b", +static const XtensaCPUClass dc232b =3D { .options =3D XTENSA_OPTIONS, .gdb_regmap =3D { .num_regs =3D 120, @@ -25,4 +24,4 @@ static const XtensaConfig dc232b =3D { .clock_freq_khz =3D 10000, }; =20 -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" =20 -static const XtensaConfig fsf =3D { - .name =3D "fsf", +static const XtensaCPUClass fsf =3D { .options =3D XTENSA_OPTIONS, /* GDB for this core is not supported currently */ .nareg =3D XCHAL_NUM_AREGS, @@ -19,4 +18,4 @@ static const XtensaConfig fsf =3D { .clock_freq_khz =3D 10000, }; =20 -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 ar= e 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 copyrig= ht + * notice, this list of conditions and the following disclaimer in= the + * documentation and/or other materials provided with the distribu= tion. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote pro= ducts + * derived from this software without specific prior written permi= ssion. + * + * 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 PU= RPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DA= MAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SE= RVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUS= ED 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) !=3D 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 =3D XTENSA_CPU_GET_CLASS(cpu); + CPUXtensaState *env =3D &cpu->env; + int level =3D (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT; + if ((env->sregs[PS] & PS_EXCM) && klass->excm_level > level) { + level =3D klass->excm_level; + } + return level; +} + +static inline int xtensa_get_debug_level(XtensaCPU *cpu) +{ + XtensaCPUClass *klass =3D 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) =3D=3D 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 ar= e 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 copyrig= ht + * notice, this list of conditions and the following disclaimer in= the + * documentation and/or other materials provided with the distribu= tion. + * * Neither the name of the Open Source and Linux Lab nor the + * names of its contributors may be used to endorse or promote pro= ducts + * derived from this software without specific prior written permi= ssion. + * + * 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 PU= RPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DA= MAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SE= RVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUS= ED 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 =3D XTENSA_CPU(c); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + CPUXtensaState *env =3D &cpu->env; + + klass->parent_reset(c); + + env->exception_taken =3D 0; + env->pc =3D klass->exception_vector[EXC_RESET]; + env->sregs[LITBASE] &=3D ~1; + env->sregs[PS] =3D xtensa_option_enabled(klass, + XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; + env->sregs[VECBASE] =3D klass->vecbase; + env->sregs[IBREAKENABLE] =3D 0; + + env->pending_irq_level =3D 0; + reset_mmu(cpu); +} + +static void xtensa_cpu_initfn(Object *obj) +{ + XtensaCPU *cpu =3D XTENSA_CPU(obj); + CPUXtensaState *env =3D &cpu->env; + + cpu_exec_init(env); + xtensa_irq_init(env); +} + +static void xtensa_cpu_class_init(ObjectClass *klass, void *data) +{ + CPUClass *cpu_class =3D CPU_CLASS(klass); + XtensaCPUClass *k =3D XTENSA_CPU_CLASS(klass); + + k->parent_reset =3D cpu_class->reset; + cpu_class->reset =3D xtensa_cpu_reset; +} + +static const TypeInfo xtensa_cpu_info =3D { + .name =3D TYPE_XTENSA_CPU, + .parent =3D TYPE_CPU, + .instance_size =3D sizeof(XtensaCPU), + .instance_init =3D xtensa_cpu_initfn, + .abstract =3D true, + .class_size =3D sizeof(XtensaCPUClass), + .class_init =3D 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; =20 -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 =20 +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); =20 =20 -#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) !=3D 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 =3D (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT; - if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) { - level =3D 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) =3D=3D 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, =20 static inline int cpu_mmu_index(CPUXtensaState *env) { - return xtensa_get_cring(env); + return xtensa_get_cring(xtensa_env_get_cpu(env)); } =20 #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_ulon= g *pc, target_ulong *cs_base, int *flags) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + *pc =3D env->pc; *cs_base =3D 0; *flags =3D 0; - *flags |=3D xtensa_get_ring(env); + *flags |=3D xtensa_get_ring(cpu); if (env->sregs[PS] & PS_EXCM) { *flags |=3D 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 |=3D 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 |=3D XTENSA_TBFLAG_DEBUG; } - if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) { + if (xtensa_get_cintlevel(cpu) < env->sregs[ICOUNTLEVEL]) { *flags |=3D XTENSA_TBFLAG_ICOUNT; } } } =20 #include "cpu-all.h" +#include "cpu-qom.h" #include "exec-all.h" =20 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 =20 -static void reset_mmu(CPUXtensaState *env); - void cpu_state_reset(CPUXtensaState *env) { - env->exception_taken =3D 0; - env->pc =3D env->config->exception_vector[EXC_RESET]; - env->sregs[LITBASE] &=3D ~1; - env->sregs[PS] =3D xtensa_option_enabled(env->config, - XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; - env->sregs[VECBASE] =3D env->config->vecbase; - env->sregs[IBREAKENABLE] =3D 0; - - env->pending_irq_level =3D 0; - reset_mmu(env); + cpu_reset(ENV_GET_CPU(env)); } =20 -static struct XtensaConfigList *xtensa_cores; - -void xtensa_register_core(XtensaConfigList *node) -{ - node->next =3D xtensa_cores; - xtensa_cores =3D node; -} - -static uint32_t check_hw_breakpoints(CPUXtensaState *env) +static uint32_t check_hw_breakpoints(XtensaCPU *cpu) { + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + CPUXtensaState *env =3D &cpu->env; unsigned i; =20 - for (i =3D 0; i < env->config->ndbreak; ++i) { + for (i =3D 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 =3D xtensa_env_get_cpu(env); uint32_t cause; =20 env->watchpoint_hit =3D NULL; - cause =3D check_hw_breakpoints(env); + cause =3D 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 =3D NULL; - XtensaConfigList *core =3D xtensa_cores; =20 - for (; core; core =3D core->next) - if (strcmp(core->config->name, cpu_model) =3D=3D 0) { - config =3D core->config; - break; - } - - if (config =3D=3D NULL) { + if (object_class_by_name(cpu_model) =3D=3D NULL) { return NULL; } - - env =3D g_malloc0(sizeof(*env)); - env->config =3D config; - cpu_exec_init(env); + cpu =3D XTENSA_CPU(object_new(cpu_model)); + env =3D &cpu->env; =20 if (!tcg_inited) { tcg_inited =3D 1; @@ -124,19 +99,48 @@ CPUXtensaState *cpu_xtensa_init(const char *cpu_mode= l) cpu_set_debug_excp_handler(breakpoint_handler); } =20 - xtensa_irq_init(env); qemu_init_vcpu(env); return env; } =20 =20 +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 =3D (ObjectClass *)a; + ObjectClass *class_b =3D (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 =3D data; + XtensaCPUListState *s =3D 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 =3D xtensa_cores; + XtensaCPUListState s =3D { + .file =3D f, + .cpu_fprintf =3D cpu_fprintf, + }; + GSList *list; + + list =3D object_class_get_list(TYPE_XTENSA_CPU, false); + list =3D g_slist_sort(list, xtensa_cpu_list_compare); cpu_fprintf(f, "Available CPUs:\n"); - for (; core; core =3D core->next) { - cpu_fprintf(f, " %s\n", core->config->name); - } + g_slist_foreach(list, xtensa_cpu_list_entry, &s); + g_slist_free(list); } =20 target_phys_addr_t cpu_get_phys_page_debug(CPUXtensaState *env, target_u= long addr) @@ -158,9 +162,12 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUXtensa= State *env, target_ulong add =20 static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector) { - if (xtensa_option_enabled(env->config, + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D 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 *en= v, uint32_t vector) */ static void handle_interrupt(CPUXtensaState *env) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); int level =3D env->pending_irq_level; =20 - if (level > xtensa_get_cintlevel(env) && - level <=3D env->config->nlevel && - (env->config->level_mask[level] & + if (level > xtensa_get_cintlevel(cpu) && + level <=3D 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] =3D (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM; env->pc =3D relocated_vector(env, - env->config->interrupt_vector[level]); + klass->interrupt_vector[level]); } else { env->sregs[EXCCAUSE] =3D LEVEL1_INTERRUPT_CAUSE; =20 if (env->sregs[PS] & PS_EXCM) { - if (env->config->ndepc) { + if (klass->ndepc) { env->sregs[DEPC] =3D env->pc; } else { env->sregs[EPC1] =3D env->pc; @@ -211,13 +220,16 @@ static void handle_interrupt(CPUXtensaState *env) =20 void do_interrupt(CPUXtensaState *env) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + if (env->exception_index =3D=3D EXC_IRQ) { qemu_log_mask(CPU_LOG_INT, "%s(EXC_IRQ) level =3D %d, cintlevel =3D %d, " "pc =3D %08x, a0 =3D %08x, ps =3D %08x, " "intset =3D %08x, intenable =3D %08x, " "ccount =3D %08x\n", - __func__, env->pending_irq_level, xtensa_get_cintlevel(e= nv), + __func__, env->pending_irq_level, xtensa_get_cintlevel(c= pu), 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 =3D %08x, a0 =3D %08x, ps =3D %08x, ccount =3D %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 =3D relocated_vector(env, - env->config->exception_vector[env->exception_index])= ; + klass->exception_vector[env->exception_index]); env->exception_taken =3D 1; } else { qemu_log("%s(pc =3D %08x) bad exception_index: %d\n", @@ -334,17 +346,20 @@ static void reset_tlb_region_way0(CPUXtensaState *e= nv, } } =20 -static void reset_mmu(CPUXtensaState *env) +void reset_mmu(XtensaCPU *cpu) { - if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + CPUXtensaState *env =3D &cpu->env; + + if (xtensa_option_enabled(klass, XTENSA_OPTION_MMU)) { env->sregs[RASID] =3D 0x04030201; env->sregs[ITLBCFG] =3D 0; env->sregs[DTLBCFG] =3D 0; env->autorefill_idx =3D 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 dtl= b, uint32_t *pwi, uint32_t *pei, uint8_t *pring) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); const xtensa_tlb *tlb =3D dtlb ? - &env->config->dtlb : &env->config->itlb; + &klass->dtlb : &klass->itlb; const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] =3D dtlb ? env->dtlb : env->itlb; =20 @@ -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 =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D 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 =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); unsigned wi, ei; const xtensa_tlb *conf =3D - dtlb ? &env->config->dtlb : &env->config->itlb; + dtlb ? &klass->dtlb : &klass->itlb; unsigned (*attr_to_access)(uint32_t) =3D - xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ? + xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU) ? mmu_attr_to_access : region_attr_to_access; =20 for (wi =3D 0; wi < conf->nways; ++wi) { @@ -636,7 +658,10 @@ static void dump_tlb(FILE *f, fprintf_function cpu_f= printf, =20 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env= ) { - if (xtensa_option_bits_enabled(env->config, + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D 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_EXCEP= TION) && - !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNME= NT)) { + XtensaCPU *cpu =3D 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) =20 void HELPER(exception_cause)(uint32_t pc, uint32_t cause) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); uint32_t vector; =20 env->pc =3D pc; if (env->sregs[PS] & PS_EXCM) { - if (env->config->ndepc) { + if (klass->ndepc) { env->sregs[DEPC] =3D pc; } else { env->sregs[EPC1] =3D pc; @@ -136,7 +140,9 @@ void HELPER(exception_cause_vaddr)(uint32_t pc, uint3= 2_t cause, uint32_t vaddr) =20 void debug_exception_env(CPUXtensaState *new_env, uint32_t cause) { - if (xtensa_get_cintlevel(new_env) < new_env->config->debug_level) { + XtensaCPU *new_cpu =3D xtensa_env_get_cpu(new_env); + + if (xtensa_get_cintlevel(new_cpu) < xtensa_get_debug_level(new_cpu))= { env =3D new_env; HELPER(debug_exception)(env->pc, cause); } @@ -144,7 +150,8 @@ void debug_exception_env(CPUXtensaState *new_env, uin= t32_t cause) =20 void HELPER(debug_exception)(uint32_t pc, uint32_t cause) { - unsigned level =3D env->config->debug_level; + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + unsigned level =3D xtensa_get_debug_level(cpu); =20 env->pc =3D pc; env->sregs[DEBUGCAUSE] =3D 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 <=3D env->config->nareg) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + + assert(phys < klass->nareg); + if (phys + n <=3D klass->nareg) { memcpy(env->regs + window, env->phys_regs + phys, n * sizeof(uint32_t)); } else { - uint32_t n1 =3D env->config->nareg - phys; + uint32_t n1 =3D 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 *e= nv, 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 <=3D env->config->nareg) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + + assert(phys < klass->nareg); + if (phys + n <=3D klass->nareg) { memcpy(env->phys_regs + phys, env->regs + window, n * sizeof(uint32_t)); } else { - uint32_t n1 =3D env->config->nareg - phys; + uint32_t n1 =3D 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 *en= v, =20 static inline unsigned windowbase_bound(unsigned a, const CPUXtensaState= *env) { - return a & (env->config->nareg / 4 - 1); + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + + return a & (klass->nareg / 4 - 1); } =20 static inline unsigned windowstart_bit(unsigned a, const CPUXtensaState = *env) @@ -382,6 +398,8 @@ void HELPER(dump_state)(void) =20 void HELPER(waiti)(uint32_t pc, uint32_t intlevel) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + env->pc =3D pc; env->sregs[PS] =3D (env->sregs[PS] & ~PS_INTLEVEL) | (intlevel << PS_INTLEVEL_SHIFT); @@ -393,7 +411,7 @@ void HELPER(waiti)(uint32_t pc, uint32_t intlevel) =20 env->halt_clock =3D qemu_get_clock_ns(vm_clock); env->halted =3D 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 =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + + if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) { bool varway56 =3D dtlb ? - env->config->dtlb.varway56 : - env->config->itlb.varway56; + klass->dtlb.varway56 : + klass->itlb.varway56; =20 switch (way) { case 4: @@ -484,18 +505,21 @@ uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaSt= ate *env, bool dtlb, uint32_t */ static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint3= 2_t way) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + if (way < 4) { bool is32 =3D (dtlb ? - env->config->dtlb.nrefillentries : - env->config->itlb.nrefillentries) =3D=3D 32; + klass->dtlb.nrefillentries : + klass->itlb.nrefillentries) =3D=3D 32; return is32 ? 0xffff8000 : 0xffffc000; } else if (way =3D=3D 4) { return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2; } else if (way <=3D 6) { uint32_t mask =3D xtensa_tlb_get_addr_mask(env, dtlb, way); bool varway56 =3D dtlb ? - env->config->dtlb.varway56 : - env->config->itlb.varway56; + klass->dtlb.varway56 : + klass->itlb.varway56; =20 if (varway56) { return mask << (way =3D=3D 5 ? 2 : 3); @@ -514,9 +538,12 @@ static uint32_t get_vpn_mask(const CPUXtensaState *e= nv, bool dtlb, uint32_t way) void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, boo= l dtlb, uint32_t *vpn, uint32_t wi, uint32_t *ei) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); + bool varway56 =3D dtlb ? - env->config->dtlb.varway56 : - env->config->itlb.varway56; + klass->dtlb.varway56 : + klass->itlb.varway56; =20 if (!dtlb) { wi &=3D 7; @@ -524,8 +551,8 @@ void split_tlb_entry_spec_way(const CPUXtensaState *e= nv, uint32_t v, bool dtlb, =20 if (wi < 4) { bool is32 =3D (dtlb ? - env->config->dtlb.nrefillentries : - env->config->itlb.nrefillentries) =3D=3D 32; + klass->dtlb.nrefillentries : + klass->itlb.nrefillentries) =3D=3D 32; *ei =3D (v >> 12) & (is32 ? 0x7 : 0x3); } else { switch (wi) { @@ -569,7 +596,9 @@ void split_tlb_entry_spec_way(const CPUXtensaState *e= nv, 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 =3D xtensa_env_get_cpu(env); + + if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) { *wi =3D 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, bo= ol dtlb, uint32_t *pwi) =20 uint32_t HELPER(rtlb0)(uint32_t v, uint32_t dtlb) { - if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + + if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) { uint32_t wi; const xtensa_tlb_entry *entry =3D get_tlb_entry(v, dtlb, &wi); return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asi= d; @@ -611,7 +642,9 @@ uint32_t HELPER(rtlb1)(uint32_t v, uint32_t dtlb) =20 void HELPER(itlb)(uint32_t v, uint32_t dtlb) { - if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + + if (xtensa_cpu_option_enabled(cpu, XTENSA_OPTION_MMU)) { uint32_t wi; xtensa_tlb_entry *entry =3D get_tlb_entry(v, dtlb, &wi); if (entry->variable && entry->asid) { @@ -623,7 +656,9 @@ void HELPER(itlb)(uint32_t v, uint32_t dtlb) =20 uint32_t HELPER(ptlb)(uint32_t v, uint32_t dtlb) { - if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { + XtensaCPU *cpu =3D 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) =20 switch (res) { case 0: - if (ring >=3D xtensa_get_ring(env)) { + if (ring >=3D 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 =3D xtensa_env_get_cpu(env); xtensa_tlb_entry *entry =3D xtensa_tlb_get_entry(env, dtlb, wi, ei); =20 - 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 d= tlb, } } 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 =3D pte & REGION_PAGE_MASK; } @@ -687,16 +723,18 @@ void HELPER(wtlb)(uint32_t p, uint32_t v, uint32_t = dtlb) =20 void HELPER(wsr_ibreakenable)(uint32_t v) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); uint32_t change =3D v ^ env->sregs[IBREAKENABLE]; unsigned i; =20 - for (i =3D 0; i < env->config->nibreak; ++i) { + for (i =3D 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] =3D v & ((1 << env->config->nibreak) - 1); + env->sregs[IBREAKENABLE] =3D v & ((1 << klass->nibreak) - 1); } =20 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 =20 #if (defined(TARGET_WORDS_BIGENDIAN) !=3D 0) =3D=3D (XCHAL_HAVE_BE !=3D = 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 =3D { \ - .config =3D &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 =3D { \ + .name =3D (typename), \ + .parent =3D TYPE_XTENSA_CPU, \ + .instance_size =3D sizeof(XtensaCPU), \ + .class_size =3D sizeof(XtensaCPUClass), \ + .class_init =3D 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 =20 #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" =20 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, D= isasContext *dc) static void gen_intermediate_code_internal( CPUXtensaState *env, TranslationBlock *tb, int search_pc) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); DisasContext dc; int insn_count =3D 0; int j, lj =3D -1; @@ -2537,7 +2538,7 @@ static void gen_intermediate_code_internal( max_insns =3D CF_COUNT_MASK; } =20 - dc.config =3D env->config; + dc.config =3D XTENSA_CPU_GET_CLASS(cpu); dc.singlestep_enabled =3D env->singlestep_enabled; dc.tb =3D tb; dc.pc =3D 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_f= printf, int flags) { + XtensaCPU *cpu =3D xtensa_env_get_cpu(env); + XtensaCPUClass *klass =3D XTENSA_CPU_GET_CLASS(cpu); int i, j; =20 cpu_fprintf(f, "PC=3D%08x\n\n", env->pc); @@ -2686,7 +2689,7 @@ void cpu_dump_state(CPUXtensaState *env, FILE *f, f= printf_function cpu_fprintf, =20 cpu_fprintf(f, "\n"); =20 - for (i =3D 0; i < env->config->nareg; ++i) { + for (i =3D 0; i < klass->nareg; ++i) { cpu_fprintf(f, "AR%02d=3D%08x%c", i, env->phys_regs[i], (i % 4) =3D=3D 3 ? '\n' : ' '); } --=20 1.7.7