Signed-off-by: Michael Rolnik <mrol...@gmail.com> --- .gitignore | 2 + MAINTAINERS | 5 + arch_init.c | 2 + configure | 5 + default-configs/arc-softmmu.mak | 0 include/sysemu/arch_init.h | 1 + target-arc/Makefile.objs | 26 +++ target-arc/cpu-qom.h | 84 ++++++++ target-arc/cpu.c | 269 +++++++++++++++++++++++++ target-arc/cpu.h | 174 +++++++++++++++++ target-arc/decode.c | 7 + target-arc/gdbstub.c | 138 +++++++++++++ target-arc/helper.c | 74 +++++++ target-arc/helper.h | 21 ++ target-arc/machine.c | 35 ++++ target-arc/machine.h | 21 ++ target-arc/translate.c | 424 ++++++++++++++++++++++++++++++++++++++++ target-arc/translate.h | 223 +++++++++++++++++++++ 18 files changed, 1511 insertions(+) create mode 100644 default-configs/arc-softmmu.mak create mode 100644 target-arc/Makefile.objs create mode 100644 target-arc/cpu-qom.h create mode 100644 target-arc/cpu.c create mode 100644 target-arc/cpu.h create mode 100644 target-arc/decode.c create mode 100644 target-arc/gdbstub.c create mode 100644 target-arc/helper.c create mode 100644 target-arc/helper.h create mode 100644 target-arc/machine.c create mode 100644 target-arc/machine.h create mode 100644 target-arc/translate.c create mode 100644 target-arc/translate.h
diff --git a/.gitignore b/.gitignore index 88ec249..37a71af 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,8 @@ /fsdev/virtfs-proxy-helper *.[1-9] *.a +*.swp +*.swo *.aux *.cp *.dvi diff --git a/MAINTAINERS b/MAINTAINERS index b6fb84e..0500cf5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -99,6 +99,11 @@ F: hw/alpha/ F: tests/tcg/alpha/ F: disas/alpha.c +ARC +M: Michael Rolnik <mrol...@gmail.com> +S: Maintained +F: target-arc/ + ARM M: Peter Maydell <peter.mayd...@linaro.org> L: qemu-...@nongnu.org diff --git a/arch_init.c b/arch_init.c index fa05973..04b51f5 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_ARC) +#define QEMU_ARCH QEMU_ARCH_ARC #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index 5a9bda1..8aee641 100755 --- a/configure +++ b/configure @@ -5672,6 +5672,8 @@ case "$target_name" in ;; alpha) ;; + arc) + ;; arm|armeb) TARGET_ARCH=arm bflt="yes" @@ -5874,6 +5876,9 @@ for i in $ARCH $TARGET_BASE_ARCH ; do disas_config "ARM_A64" fi ;; + arc) + disas_config "ARC" + ;; arm) disas_config "ARM" if test -n "${cxx}"; then diff --git a/default-configs/arc-softmmu.mak b/default-configs/arc-softmmu.mak new file mode 100644 index 0000000..e69de29 diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index 1c9dad1..35148a6 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), + QEMU_ARCH_ARC = (1 << 16), }; extern const uint32_t arch_type; diff --git a/target-arc/Makefile.objs b/target-arc/Makefile.objs new file mode 100644 index 0000000..a3475dd --- /dev/null +++ b/target-arc/Makefile.objs @@ -0,0 +1,26 @@ +# +# QEMU ARC CPU +# +# Copyright (c) 2016 Michael Rolnik +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see +# <http://www.gnu.org/licenses/lgpl-2.1.html> +# + +obj-y += translate.o +obj-y += helper.o +obj-y += cpu.o +obj-y += gdbstub.o +obj-y += decode.o +obj-$(CONFIG_SOFTMMU) += machine.o diff --git a/target-arc/cpu-qom.h b/target-arc/cpu-qom.h new file mode 100644 index 0000000..b9cb1b2 --- /dev/null +++ b/target-arc/cpu-qom.h @@ -0,0 +1,84 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#ifndef QEMU_ARC_CPU_QOM_H +#define QEMU_ARC_CPU_QOM_H + +#include "qom/cpu.h" + +#define TYPE_ARC_CPU "arc" + +#define ARC_CPU_CLASS(klass) \ + OBJECT_CLASS_CHECK(ARCCPUClass, (klass), TYPE_ARC_CPU) +#define ARC_CPU(obj) \ + OBJECT_CHECK(ARCCPU, (obj), TYPE_ARC_CPU) +#define ARC_CPU_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ARCCPUClass, (obj), TYPE_ARC_CPU) + +/** +* ARCCPUClass: +* @parent_realize: The parent class' realize handler. +* @parent_reset: The parent class' reset handler. +* @vr: Version Register value. +* +* A ARC CPU model. +*/ +typedef struct ARCCPUClass { + CPUClass parent_class; + + DeviceRealize parent_realize; + void (*parent_reset)(CPUState *cpu); +} ARCCPUClass; + +/** +* ARCCPU: +* @env: #CPUARCState +* +* A ARC CPU. +*/ +typedef struct ARCCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + CPUARCState env; +} ARCCPU; + +static inline ARCCPU *arc_env_get_cpu(CPUARCState *env) +{ + return container_of(env, ARCCPU, env); +} + +#define ENV_GET_CPU(e) CPU(arc_env_get_cpu(e)) +#define ENV_OFFSET offsetof(ARCCPU, env) + +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vms_arc_cpu; +#endif + +void arc_cpu_do_interrupt(CPUState *cpu); +bool arc_cpu_exec_interrupt(CPUState *cpu, int int_req); +void arc_cpu_dump_state(CPUState *cs, FILE *f, + fprintf_function cpu_fprintf, int flags); +hwaddr arc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int arc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int arc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); + +#endif diff --git a/target-arc/cpu.c b/target-arc/cpu.c new file mode 100644 index 0000000..b162274 --- /dev/null +++ b/target-arc/cpu.c @@ -0,0 +1,269 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "cpu.h" +#include "qemu-common.h" +#include "migration/vmstate.h" +#include "machine.h" + +static void arc_cpu_set_pc(CPUState *cs, vaddr value) +{ + ARCCPU *cpu = ARC_CPU(cs); + + CPU_PCL(&cpu->env) = value & 0xfffffffc; + cpu->env.pc = value; +} + +static bool arc_cpu_has_work(CPUState *cs) +{ + return false; +} +static void arc_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) +{ + ARCCPU *cpu = ARC_CPU(cs); + CPUARCState *env = &cpu->env; + + env->pc = tb->pc; +} + +static void arc_cpu_reset(CPUState *s) +{ + ARCCPU *cpu = ARC_CPU(s); + ARCCPUClass *mcc = ARC_CPU_GET_CLASS(cpu); + CPUARCState *env = &cpu->env; + + mcc->parent_reset(s); + + memset(env->r, 0, sizeof(env->r)); + env->pc = 0x12c; /* TODO: this is just for testing */ + CPU_PCL(env) = 0x12c; /* TODO: this is just for testing */ + + tlb_flush(s, 1); +} + +static void arc_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_arch_arc; + info->print_insn = NULL; +} + +static void arc_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + ARCCPUClass *mcc = ARC_CPU_GET_CLASS(dev); + + qemu_init_vcpu(cs); + cpu_reset(cs); + + mcc->parent_realize(dev, errp); +} + +static void arc_cpu_set_int(void *opaque, int irq, int level) +{ +} + +static void arc_cpu_initfn(Object *obj) +{ + CPUState *cs = CPU(obj); + ARCCPU *cpu = ARC_CPU(obj); + static int inited; + + cs->env_ptr = &cpu->env; + cpu_exec_init(cs, &error_abort); + +#ifndef CONFIG_USER_ONLY + qdev_init_gpio_in(DEVICE(cpu), arc_cpu_set_int, 37); +#endif + + if (tcg_enabled() && !inited) { + inited = 1; + arc_translate_init(); + } +} + +static ObjectClass *arc_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + char *typename; + char **cpuname; + + if (!cpu_model) { + return NULL; + } + + cpuname = g_strsplit(cpu_model, ",", 1); + typename = g_strdup_printf("%s-" TYPE_ARC_CPU, cpuname[0]); + oc = object_class_by_name(typename); + + g_strfreev(cpuname); + g_free(typename); + + if (!oc + || !object_class_dynamic_cast(oc, TYPE_ARC_CPU) + || object_class_is_abstract(oc)) { + return NULL; + } + + return oc; +} + +static void arc_cpu_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + CPUClass *cc = CPU_CLASS(oc); + ARCCPUClass *mcc = ARC_CPU_CLASS(oc); + + mcc->parent_realize = dc->realize; + dc->realize = arc_cpu_realizefn; + + mcc->parent_reset = cc->reset; + cc->reset = arc_cpu_reset; + + cc->class_by_name = arc_cpu_class_by_name; + + cc->has_work = arc_cpu_has_work; + cc->do_interrupt = arc_cpu_do_interrupt; + cc->cpu_exec_interrupt = arc_cpu_exec_interrupt; + cc->dump_state = arc_cpu_dump_state; + cc->set_pc = arc_cpu_set_pc; +#if !defined(CONFIG_USER_ONLY) + cc->memory_rw_debug = arc_cpu_memory_rw_debug; +#endif +#ifdef CONFIG_USER_ONLY + cc->handle_mmu_fault = arc_cpu_handle_mmu_fault; +#else + cc->get_phys_page_debug = arc_cpu_get_phys_page_debug; + cc->vmsd = &vms_arc_cpu; +#endif + cc->disas_set_info = arc_cpu_disas_set_info; + cc->synchronize_from_tb = arc_cpu_synchronize_from_tb; + cc->gdb_read_register = arc_cpu_gdb_read_register; + cc->gdb_write_register = arc_cpu_gdb_write_register; + cc->gdb_num_core_regs = 68; + + /* + * Reason: arc_cpu_initfn() calls cpu_exec_init(), which saves + * the object in cpus -> dangling pointer after final + * object_unref(). + */ + dc->cannot_destroy_with_object_finalize_yet = true; +} + +static void arc_any_initfn(Object *obj) +{ + /* Set cpu feature flags */ +} + +typedef struct ARCCPUInfo { + const char *name; + void (*initfn)(Object *obj); +} ARCCPUInfo; + +static const ARCCPUInfo arc_cpus[] = { + { .name = "any", .initfn = arc_any_initfn }, +}; + +static gint arc_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + ObjectClass *class_a = (ObjectClass *)a; + ObjectClass *class_b = (ObjectClass *)b; + const char *name_a; + const char *name_b; + + name_a = object_class_get_name(class_a); + name_b = object_class_get_name(class_b); + if (strcmp(name_a, "any-" TYPE_ARC_CPU) == 0) { + return 1; + } else if (strcmp(name_b, "any-" TYPE_ARC_CPU) == 0) { + return -1; + } else { + return strcmp(name_a, name_b); + } +} + +static void arc_cpu_list_entry(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CPUListState *s = user_data; + const char *typename; + char *name; + + typename = object_class_get_name(oc); + name = g_strndup(typename, strlen(typename) - strlen("-" TYPE_ARC_CPU)); + (*s->cpu_fprintf)(s->file, " %s\n", name); + g_free(name); +} + +void arc_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ + CPUListState s = { + .file = f, + .cpu_fprintf = cpu_fprintf, + }; + GSList *list; + + list = object_class_get_list(TYPE_ARC_CPU, false); + list = g_slist_sort(list, arc_cpu_list_compare); + (*cpu_fprintf)(f, "Available CPUs:\n"); + g_slist_foreach(list, arc_cpu_list_entry, &s); + g_slist_free(list); +} +ARCCPU *cpu_arc_init(const char *cpu_model) +{ + return ARC_CPU(cpu_generic_init(TYPE_ARC_CPU, cpu_model)); +} + +static void cpu_register(const ARCCPUInfo *info) +{ + TypeInfo type_info = { + .parent = TYPE_ARC_CPU, + .instance_size = sizeof(ARCCPU), + .instance_init = info->initfn, + .class_size = sizeof(ARCCPUClass), + }; + + type_info.name = g_strdup_printf("%s-" TYPE_ARC_CPU, info->name); + type_register(&type_info); + g_free((void *)type_info.name); +} + +static const TypeInfo arc_cpu_type_info = { + .name = TYPE_ARC_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(ARCCPU), + .instance_init = arc_cpu_initfn, + .class_size = sizeof(ARCCPUClass), + .class_init = arc_cpu_class_init, + .abstract = true, +}; + +static void arc_cpu_register_types(void) +{ + int i; + type_register_static(&arc_cpu_type_info); + + for (i = 0; i < ARRAY_SIZE(arc_cpus); i++) { + cpu_register(&arc_cpus[i]); + } +} + +type_init(arc_cpu_register_types) diff --git a/target-arc/cpu.h b/target-arc/cpu.h new file mode 100644 index 0000000..253a1bc --- /dev/null +++ b/target-arc/cpu.h @@ -0,0 +1,174 @@ + /* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#if !defined(CPU_ARC_H) +#define CPU_ARC_H + +#include "qemu-common.h" + +#define TARGET_LONG_BITS 32 + +#define CPUArchState struct CPUARCState + +#include "exec/cpu-defs.h" +#include "fpu/softfloat.h" + +#define TARGET_PAGE_BITS 12 +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define NB_MMU_MODES 1 + +#define MMU_IDX 0 + +#define PHYS_BASE_RAM 0x00000000 +#define VIRT_BASE_RAM 0x00000000 + +enum arc_features { + ARC_FEATURE_ARC5, + ARC_FEATURE_ARC600, + ARC_FEATURE_ARC700, + no_features, +}; + + +typedef struct CPUARCState CPUARCState; +#define CPU_GP(env) ((env)->r[26]) +#define CPU_FP(env) ((env)->r[27]) +#define CPU_SP(env) ((env)->r[28]) +#define CPU_ILINK1(env) ((env)->r[29]) +#define CPU_ILINK2(env) ((env)->r[30]) +#define CPU_BLINK(env) ((env)->r[31]) +#define CPU_MLO(env) ((env)->r[57]) +#define CPU_MMI(env) ((env)->r[58]) +#define CPU_MHI(env) ((env)->r[59]) +#define CPU_LP(env) ((env)->r[60]) +#define CPU_IMM(env) ((env)->r[62]) +#define CPU_PCL(env) ((env)->r[63]) + + +struct CPUARCState { + uint32_t r[64]; + + struct { + uint32_t Lf; + uint32_t Zf; /* zero */ + uint32_t Nf; /* negative */ + uint32_t Cf; /* carry */ + uint32_t Vf; /* overflow */ + uint32_t Uf; + + uint32_t DEf; + uint32_t AEf; + uint32_t A2f; /* interrupt 1 is active */ + uint32_t A1f; /* interrupt 2 is active */ + uint32_t E2f; /* interrupt 1 mask */ + uint32_t E1f; /* interrupt 2 mask */ + uint32_t Hf; /* halt */ + } stat, stat_l1, stat_l2, stat_er; + + struct { + uint32_t S2; + uint32_t S1; + uint32_t CS; + } macmod; + + uint32_t intvec; + + uint32_t eret; + uint32_t erbta; + uint32_t ecr; + uint32_t efa; + uint32_t bta; + uint32_t bta_l1; + uint32_t bta_l2; + + uint32_t pc; /* program counter */ + uint32_t lps; /* loops start */ + uint32_t lpe; /* loops end */ + + struct { + uint32_t LD; /* load pending bit */ + uint32_t SH; /* self halt */ + uint32_t BH; /* breakpoint halt */ + uint32_t UB; /* user mode break enabled */ + uint32_t ZZ; /* sleep mode */ + uint32_t RA; /* reset applied */ + uint32_t IS; /* single instruction step */ + uint32_t FH; /* force halt */ + uint32_t SS; /* single step */ + } debug; + uint32_t features; + bool stopped; + + /* Those resources are used only in QEMU core */ + CPU_COMMON +}; + +static inline int arc_feature(CPUARCState *env, int feature) +{ + return (env->features & (1U << feature)) != 0; +} + +static inline void arc_set_feature(CPUARCState *env, int feature) +{ + env->features |= (1U << feature); +} + +#define cpu_list arc_cpu_list +#define cpu_signal_handler cpu_arc_signal_handler + +#include "exec/cpu-all.h" +#include "cpu-qom.h" + +static inline int cpu_mmu_index(CPUARCState *env, bool ifetch) +{ + return 0; +} + +void arc_translate_init(void); + +ARCCPU *cpu_arc_init(const char *cpu_model); + +#define cpu_init(cpu_model) CPU(cpu_arc_init(cpu_model)) + +void arc_cpu_list(FILE *f, fprintf_function cpu_fprintf); +int cpu_arc_exec(CPUState *cpu); +int cpu_arc_signal_handler(int host_signum, void *pinfo, void *puc); +int arc_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, + int mmu_idx); +int arc_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, + int len, bool is_write); + +static inline void cpu_get_tb_cpu_state(CPUARCState *env, target_ulong *pc, + target_ulong *cs_base, uint32_t *pflags) +{ + *pc = env->pc; + *cs_base = 0; + *pflags = 0; +} + +static inline int cpu_interrupts_enabled(CPUARCState *env1) +{ + return 0; +} + +#include "exec/exec-all.h" + +#endif /* !defined (CPU_ARC_H) */ diff --git a/target-arc/decode.c b/target-arc/decode.c new file mode 100644 index 0000000..1bb859a --- /dev/null +++ b/target-arc/decode.c @@ -0,0 +1,7 @@ +#include "translate.h" + +int arc_decode(DisasCtxt *ctx) +{ + return BS_STOP; +} + diff --git a/target-arc/gdbstub.c b/target-arc/gdbstub.c new file mode 100644 index 0000000..69b8cdc --- /dev/null +++ b/target-arc/gdbstub.c @@ -0,0 +1,138 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +static uint32_t arc_cpu_get_stat32(CPUState *cs) +{ + ARCCPU *cpu = ARC_CPU(cs); + CPUARCState *env = &cpu->env; + uint32_t val = 0; + + val |= env->stat.Hf ? BIT(0) : 0; + val |= env->stat.E1f ? BIT(1) : 0; + val |= env->stat.E2f ? BIT(2) : 0; + val |= env->stat.A1f ? BIT(3) : 0; + val |= env->stat.A2f ? BIT(4) : 0; + val |= env->stat.AEf ? BIT(5) : 0; + val |= env->stat.DEf ? BIT(6) : 0; + val |= env->stat.Uf ? BIT(7) : 0; + val |= env->stat.Vf ? BIT(8) : 0; + val |= env->stat.Cf ? BIT(9) : 0; + val |= env->stat.Nf ? BIT(10) : 0; + val |= env->stat.Zf ? BIT(11) : 0; + val |= env->stat.Lf ? BIT(12) : 0; + + return val; +} + +static void arc_cpu_set_stat32(CPUState *cs, uint32_t val) +{ + ARCCPU *cpu = ARC_CPU(cs); + CPUARCState *env = &cpu->env; + + env->stat.Hf = 0 != (val & BIT(0)); + env->stat.E1f = 0 != (val & BIT(1)); + env->stat.E2f = 0 != (val & BIT(2)); + env->stat.A1f = 0 != (val & BIT(3)); + env->stat.A2f = 0 != (val & BIT(4)); + env->stat.AEf = 0 != (val & BIT(5)); + env->stat.DEf = 0 != (val & BIT(6)); + env->stat.Uf = 0 != (val & BIT(7)); + env->stat.Vf = 0 != (val & BIT(8)); + env->stat.Cf = 0 != (val & BIT(9)); + env->stat.Nf = 0 != (val & BIT(10)); + env->stat.Zf = 0 != (val & BIT(11)); + env->stat.Lf = 0 != (val & BIT(12)); +} + +int arc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + ARCCPU *cpu = ARC_CPU(cs); + CPUARCState *env = &cpu->env; + uint32_t val = 0; + + switch (n) { + case 0x00 ... 0x3f: { + val = env->r[n]; + break; + } + + case 0x40: { + val = env->pc; + break; + } + + case 0x41: { + val = env->lps; + break; + } + + case 0x42: { + val = env->lpe; + break; + } + + case 0x43: { + val = arc_cpu_get_stat32(cs); + break; + } + } + + return gdb_get_reg32(mem_buf, val); +} + +int arc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ + ARCCPU *cpu = ARC_CPU(cs); + CPUARCState *env = &cpu->env; + uint16_t val = ldl_p(mem_buf); + + switch (n) { + case 0x00 ... 0x3f: { + env->r[n] = val; + break; + } + + case 0x40: { + env->pc = val; + break; + } + + case 0x41: { + env->lps = val; + break; + } + + case 0x42: { + env->lpe = val; + break; + } + + case 0x43: { + arc_cpu_set_stat32(cs, val); + break; + } + } + + return 4; +} diff --git a/target-arc/helper.c b/target-arc/helper.c new file mode 100644 index 0000000..ace3b5d --- /dev/null +++ b/target-arc/helper.c @@ -0,0 +1,74 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" + +#include "cpu.h" +#include "hw/irq.h" +#include "include/hw/sysbus.h" +#include "include/sysemu/sysemu.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" + +void tlb_fill(CPUState *cs, target_ulong vaddr, MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ + target_ulong page_size = TARGET_PAGE_SIZE; + int prot = 0; + MemTxAttrs attrs = {}; + uint32_t paddr; + + vaddr &= TARGET_PAGE_MASK; + paddr = PHYS_BASE_RAM + vaddr - VIRT_BASE_RAM; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + + tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size); +} + +void arc_cpu_do_interrupt(CPUState *cs) +{ + cs->exception_index = -1; +} + +bool arc_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + return false; +} + +int arc_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, + int len, bool is_write) +{ + return cpu_memory_rw_debug(cs, addr, buf, len, is_write); +} + +hwaddr arc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ + return addr; /* I assume 1:1 address correspondance */ +} + +void helper_debug(CPUARCState *env) +{ + CPUState *cs = CPU(arc_env_get_cpu(env)); + + cs->exception_index = EXCP_DEBUG; + cpu_loop_exit(cs); +} diff --git a/target-arc/helper.h b/target-arc/helper.h new file mode 100644 index 0000000..69c91fb --- /dev/null +++ b/target-arc/helper.h @@ -0,0 +1,21 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +DEF_HELPER_1(debug, void, env) diff --git a/target-arc/machine.c b/target-arc/machine.c new file mode 100644 index 0000000..b008942 --- /dev/null +++ b/target-arc/machine.c @@ -0,0 +1,35 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "cpu.h" +#include "hw/boards.h" +#include "machine.h" +#include "migration/qemu-file.h" + +const VMStateDescription vms_arc_cpu = { + .name = "cpu", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_END_OF_LIST() + } +}; diff --git a/target-arc/machine.h b/target-arc/machine.h new file mode 100644 index 0000000..6190f3d --- /dev/null +++ b/target-arc/machine.h @@ -0,0 +1,21 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +extern const VMStateDescription vmstate_arc_cpu; diff --git a/target-arc/translate.c b/target-arc/translate.c new file mode 100644 index 0000000..fc09403 --- /dev/null +++ b/target-arc/translate.c @@ -0,0 +1,424 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#include "translate.h" + +TCGv_env cpu_env; + +TCGv cpu_gp; /* Global Pointer */ +TCGv cpu_fp; /* Frame Pointer */ +TCGv cpu_sp; /* Stack Pointer */ +TCGv cpu_ilink1; /* Level 1 interrupt link register */ +TCGv cpu_ilink2; /* Level 2 interrupt link register */ +TCGv cpu_blink; /* Branch link register */ +TCGv cpu_limm; /* Long immediate data indicator */ +TCGv cpu_pcl; /* Program Counter [31:2], read-only, + 32-bit aligned address. */ + +TCGv cpu_mlo; /* Multiply low 32 bits, read only */ +TCGv cpu_mmi; /* Multiply middle 32 bits, read only */ +TCGv cpu_mhi; /* Multiply high 32 bits, read only */ + +TCGv cpu_S1f; +TCGv cpu_S2f; +TCGv cpu_CSf; + +TCGv cpu_Lf; +TCGv cpu_Zf; +TCGv cpu_Nf; +TCGv cpu_Cf; +TCGv cpu_Vf; +TCGv cpu_Uf; + +TCGv cpu_DEf; +TCGv cpu_AEf; +TCGv cpu_A2f; +TCGv cpu_A1f; +TCGv cpu_E2f; +TCGv cpu_E1f; +TCGv cpu_Hf; + +TCGv cpu_l1_Lf; +TCGv cpu_l1_Zf; +TCGv cpu_l1_Nf; +TCGv cpu_l1_Cf; +TCGv cpu_l1_Vf; +TCGv cpu_l1_Uf; + +TCGv cpu_l1_DEf; +TCGv cpu_l1_AEf; +TCGv cpu_l1_A2f; +TCGv cpu_l1_A1f; +TCGv cpu_l1_E2f; +TCGv cpu_l1_E1f; +TCGv cpu_l1_Hf; + +TCGv cpu_l2_Lf; +TCGv cpu_l2_Zf; +TCGv cpu_l2_Nf; +TCGv cpu_l2_Cf; +TCGv cpu_l2_Vf; +TCGv cpu_l2_Uf; + +TCGv cpu_l2_DEf; +TCGv cpu_l2_AEf; +TCGv cpu_l2_A2f; +TCGv cpu_l2_A1f; +TCGv cpu_l2_E2f; +TCGv cpu_l2_E1f; +TCGv cpu_l2_Hf; + +TCGv cpu_er_Lf; +TCGv cpu_er_Zf; +TCGv cpu_er_Nf; +TCGv cpu_er_Cf; +TCGv cpu_er_Vf; +TCGv cpu_er_Uf; + +TCGv cpu_er_DEf; +TCGv cpu_er_AEf; +TCGv cpu_er_A2f; +TCGv cpu_er_A1f; +TCGv cpu_er_E2f; +TCGv cpu_er_E1f; +TCGv cpu_er_Hf; + +TCGv cpu_eret; +TCGv cpu_erbta; +TCGv cpu_ecr; +TCGv cpu_efa; + +TCGv cpu_bta; +TCGv cpu_bta_l1; +TCGv cpu_bta_l2; + +TCGv cpu_pc; +TCGv cpu_lpc; +TCGv cpu_lps; +TCGv cpu_lpe; + +TCGv cpu_r[64]; + +TCGv cpu_intvec; + +TCGv cpu_debug_LD; +TCGv cpu_debug_SH; +TCGv cpu_debug_BH; +TCGv cpu_debug_UB; +TCGv cpu_debug_ZZ; +TCGv cpu_debug_RA; +TCGv cpu_debug_IS; +TCGv cpu_debug_FH; +TCGv cpu_debug_SS; + +#include "exec/gen-icount.h" +#define REG(x) (cpu_r[x]) + +void arc_translate_init(void) +{ + int i; + static int init_not_done = 1; + + if (init_not_done == 0) { + return; + } +#define ARC_REG_OFFS(x) offsetof(CPUARCState, x) +#define NEW_ARC_REG(x) \ + tcg_global_mem_new_i32(cpu_env, offsetof(CPUARCState, x), #x) + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + cpu_S1f = NEW_ARC_REG(macmod.S1); + cpu_S2f = NEW_ARC_REG(macmod.S2); + cpu_CSf = NEW_ARC_REG(macmod.CS); + + cpu_Zf = NEW_ARC_REG(stat.Zf); + cpu_Lf = NEW_ARC_REG(stat.Lf); + cpu_Nf = NEW_ARC_REG(stat.Nf); + cpu_Cf = NEW_ARC_REG(stat.Cf); + cpu_Vf = NEW_ARC_REG(stat.Vf); + cpu_Uf = NEW_ARC_REG(stat.Uf); + cpu_DEf = NEW_ARC_REG(stat.DEf); + cpu_AEf = NEW_ARC_REG(stat.AEf); + cpu_A2f = NEW_ARC_REG(stat.A2f); + cpu_A1f = NEW_ARC_REG(stat.A1f); + cpu_E2f = NEW_ARC_REG(stat.E2f); + cpu_E1f = NEW_ARC_REG(stat.E1f); + cpu_Hf = NEW_ARC_REG(stat.Hf); + + cpu_l1_Zf = NEW_ARC_REG(stat_l1.Zf); + cpu_l1_Lf = NEW_ARC_REG(stat_l1.Lf); + cpu_l1_Nf = NEW_ARC_REG(stat_l1.Nf); + cpu_l1_Cf = NEW_ARC_REG(stat_l1.Cf); + cpu_l1_Vf = NEW_ARC_REG(stat_l1.Vf); + cpu_l1_Uf = NEW_ARC_REG(stat_l1.Uf); + cpu_l1_DEf = NEW_ARC_REG(stat_l1.DEf); + cpu_l1_AEf = NEW_ARC_REG(stat_l1.AEf); + cpu_l1_A2f = NEW_ARC_REG(stat_l1.A2f); + cpu_l1_A1f = NEW_ARC_REG(stat_l1.A1f); + cpu_l1_E2f = NEW_ARC_REG(stat_l1.E2f); + cpu_l1_E1f = NEW_ARC_REG(stat_l1.E1f); + cpu_l1_Hf = NEW_ARC_REG(stat_l1.Hf); + + cpu_l2_Zf = NEW_ARC_REG(stat_l2.Zf); + cpu_l2_Lf = NEW_ARC_REG(stat_l2.Lf); + cpu_l2_Nf = NEW_ARC_REG(stat_l2.Nf); + cpu_l2_Cf = NEW_ARC_REG(stat_l2.Cf); + cpu_l2_Vf = NEW_ARC_REG(stat_l2.Vf); + cpu_l2_Uf = NEW_ARC_REG(stat_l2.Uf); + cpu_l2_DEf = NEW_ARC_REG(stat_l2.DEf); + cpu_l2_AEf = NEW_ARC_REG(stat_l2.AEf); + cpu_l2_A2f = NEW_ARC_REG(stat_l2.A2f); + cpu_l2_A1f = NEW_ARC_REG(stat_l2.A1f); + cpu_l2_E2f = NEW_ARC_REG(stat_l2.E2f); + cpu_l2_E1f = NEW_ARC_REG(stat_l2.E1f); + cpu_l2_Hf = NEW_ARC_REG(stat_l2.Hf); + + cpu_er_Zf = NEW_ARC_REG(stat_er.Zf); + cpu_er_Lf = NEW_ARC_REG(stat_er.Lf); + cpu_er_Nf = NEW_ARC_REG(stat_er.Nf); + cpu_er_Cf = NEW_ARC_REG(stat_er.Cf); + cpu_er_Vf = NEW_ARC_REG(stat_er.Vf); + cpu_er_Uf = NEW_ARC_REG(stat_er.Uf); + cpu_er_DEf = NEW_ARC_REG(stat_er.DEf); + cpu_er_AEf = NEW_ARC_REG(stat_er.AEf); + cpu_er_A2f = NEW_ARC_REG(stat_er.A2f); + cpu_er_A1f = NEW_ARC_REG(stat_er.A1f); + cpu_er_E2f = NEW_ARC_REG(stat_er.E2f); + cpu_er_E1f = NEW_ARC_REG(stat_er.E1f); + cpu_er_Hf = NEW_ARC_REG(stat_er.Hf); + + cpu_eret = NEW_ARC_REG(eret); + cpu_erbta = NEW_ARC_REG(erbta); + cpu_ecr = NEW_ARC_REG(ecr); + cpu_efa = NEW_ARC_REG(efa); + cpu_bta = NEW_ARC_REG(bta); + cpu_lps = NEW_ARC_REG(lps); + cpu_lpe = NEW_ARC_REG(lpe); + cpu_pc = NEW_ARC_REG(pc); + + cpu_bta_l1 = NEW_ARC_REG(bta_l1); + cpu_bta_l2 = NEW_ARC_REG(bta_l2); + + cpu_intvec = NEW_ARC_REG(intvec); + + for (i = 0; i < 64; i++) { + char name[16]; + + sprintf(name, "r[%d]", i); + + cpu_r[i] = tcg_global_mem_new_i32(cpu_env, ARC_REG_OFFS(r[i]), name); + } + + cpu_gp = cpu_r[26]; + cpu_fp = cpu_r[27]; + cpu_sp = cpu_r[28]; + cpu_ilink1 = cpu_r[29]; + cpu_ilink2 = cpu_r[30]; + cpu_blink = cpu_r[31]; + cpu_mlo = cpu_r[57]; + cpu_mmi = cpu_r[58]; + cpu_mhi = cpu_r[59]; + cpu_lpc = cpu_r[60]; + cpu_limm = cpu_r[62]; + cpu_pcl = cpu_r[63]; + + cpu_debug_LD = NEW_ARC_REG(debug.LD); + cpu_debug_SH = NEW_ARC_REG(debug.SH); + cpu_debug_BH = NEW_ARC_REG(debug.BH); + cpu_debug_UB = NEW_ARC_REG(debug.UB); + cpu_debug_ZZ = NEW_ARC_REG(debug.ZZ); + cpu_debug_RA = NEW_ARC_REG(debug.RA); + cpu_debug_IS = NEW_ARC_REG(debug.IS); + cpu_debug_FH = NEW_ARC_REG(debug.FH); + cpu_debug_SS = NEW_ARC_REG(debug.SS); + + init_not_done = 0; +} + +int arc_gen_INVALID(DisasCtxt *ctx) +{ + printf("invalid inst @:%08x\n", ctx->cpc); + return BS_NONE; +} + +void gen_intermediate_code(CPUARCState *env, struct TranslationBlock *tb) +{ + ARCCPU *cpu = arc_env_get_cpu(env); + CPUState *cs = CPU(cpu); + DisasCtxt ctx; + target_ulong pc_start; + int num_insns; + int max_insns; + + pc_start = tb->pc; + ctx.tb = tb; + ctx.memidx = 0; + ctx.bstate = BS_NONE; + ctx.singlestep = cs->singlestep_enabled; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + + if (max_insns == 0) { + max_insns = CF_COUNT_MASK; + } + if (max_insns > TCG_MAX_INSNS) { + max_insns = TCG_MAX_INSNS; + } + + gen_tb_start(tb); + + ctx.zero = tcg_const_local_i32(0); + ctx.one = tcg_const_local_i32(1); + ctx.msb32 = tcg_const_local_i32(0x80000000); + ctx.msb16 = tcg_const_local_i32(0x00008000); + ctx.smax16 = tcg_const_local_i32(0x7fffffff); + ctx.smax32 = tcg_const_local_i32(0x00007fff); + ctx.smax5 = tcg_const_local_i32(0x0000001f); + ctx.smin5 = tcg_const_local_i32(0xffffffe1); + + ctx.npc = pc_start; + ctx.env = env; + ctx.ds = 0; + do { + ctx.cpc = ctx.npc; + ctx.pcl = ctx.cpc & 0xfffffffc; + + tcg_gen_insn_start(ctx.cpc); + num_insns++; + + if (unlikely(cpu_breakpoint_test(cs, ctx.cpc, BP_ANY))) { + tcg_gen_movi_i32(cpu_pc, ctx.cpc); + gen_helper_debug(cpu_env); + ctx.bstate = BS_EXCP; + goto done_generating; + } + + ctx.bstate = arc_decode(&ctx); + + if (ctx.npc == env->lpe) { + TCGLabel *label_next = gen_new_label(); + + tcg_gen_subi_tl(cpu_lpc, cpu_lpc, 1); + + tcg_gen_movi_tl(cpu_pc, ctx.npc); + + tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_lpc, 0, label_next); + + tcg_gen_mov_tl(cpu_pc, cpu_lps); + +gen_set_label(label_next); + + ctx.bstate = BS_BRANCH; + } + + if (num_insns >= max_insns) { + break; /* max translated instructions limit reached */ + } + if (ctx.singlestep) { + break; /* single step */ + } + if ((ctx.cpc & (TARGET_PAGE_SIZE - 1)) == 0) { + break; /* page boundary */ + } + + } while (ctx.bstate == BS_NONE && !tcg_op_buf_full()); + + if (tb->cflags & CF_LAST_IO) { + gen_io_end(); + } + + if (ctx.singlestep) { + if (ctx.bstate == BS_STOP || ctx.bstate == BS_NONE) { + tcg_gen_movi_tl(cpu_pc, ctx.npc); + tcg_gen_movi_tl(cpu_pcl, ctx.npc & 0xfffffffc); + } + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(0); + } else { + switch (ctx.bstate) { + case BS_STOP: + case BS_NONE: + gen_goto_tb(env, &ctx, 0, ctx.npc); + break; + case BS_BRANCH: + case BS_BRANCH_DS: + case BS_EXCP: + tcg_gen_exit_tb(0); + break; + default: + break; + } + } + +done_generating: + tcg_temp_free_i32(ctx.one); + tcg_temp_free_i32(ctx.zero); + tcg_temp_free_i32(ctx.msb32); + tcg_temp_free_i32(ctx.msb16); + tcg_temp_free_i32(ctx.smax16); + tcg_temp_free_i32(ctx.smax32); + tcg_temp_free_i32(ctx.smax5); + tcg_temp_free_i32(ctx.smin5); + + gen_tb_end(tb, num_insns); + + tb->size = (ctx.npc - pc_start); + tb->icount = num_insns; +} + +void restore_state_to_opc(CPUARCState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->pc = data[0]; +} + +void arc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, + int flags) +{ + ARCCPU *cpu = ARC_CPU(cs); + CPUARCState *env = &cpu->env; + int i; + + cpu_fprintf(f, "STATUS: [ %c %c %c %c %c %c %s %s %s %s %s %s %c]\n", + env->stat.Lf ? 'L' : '-', + env->stat.Zf ? 'Z' : '-', + env->stat.Nf ? 'N' : '-', + env->stat.Cf ? 'C' : '-', + env->stat.Vf ? 'V' : '-', + env->stat.Uf ? 'U' : '-', + env->stat.DEf ? "DE" : "--", + env->stat.AEf ? "AE" : "--", + env->stat.A2f ? "A2" : "--", + env->stat.A1f ? "A1" : "--", + env->stat.E2f ? "E2" : "--", + env->stat.E1f ? "E1" : "--", + env->stat.Hf ? 'H' : '-' + ); + + cpu_fprintf(f, "\n"); + for (i = 0; i < ARRAY_SIZE(env->r); i++) { + cpu_fprintf(f, "R[%02d]: %02x ", i, env->r[i]); + + if ((i % 8) == 7) { + cpu_fprintf(f, "\n"); + } + } +} diff --git a/target-arc/translate.h b/target-arc/translate.h new file mode 100644 index 0000000..470df47 --- /dev/null +++ b/target-arc/translate.h @@ -0,0 +1,223 @@ +/* + * QEMU ARC CPU + * + * Copyright (c) 2016 Michael Rolnik + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see + * <http://www.gnu.org/licenses/lgpl-2.1.html> + */ + +#ifndef ARC_TRANSLATE_H_ +#define ARC_TRANSLATE_H_ + + +#include "qemu/osdep.h" + +#include "tcg/tcg.h" +#include "cpu.h" +#include "exec/exec-all.h" +#include "disas/disas.h" +#include "tcg-op.h" +#include "exec/cpu_ldst.h" + +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "exec/log.h" + +extern TCGv_env cpu_env; + +extern TCGv cpu_gp; +extern TCGv cpu_fp; +extern TCGv cpu_sp; +extern TCGv cpu_ilink1; +extern TCGv cpu_ilink2; +extern TCGv cpu_blink; +extern TCGv cpu_pcl; +extern TCGv cpu_limm; + +extern TCGv cpu_mlo; +extern TCGv cpu_mmi; +extern TCGv cpu_mhi; + +extern TCGv cpu_S1f; +extern TCGv cpu_S2f; +extern TCGv cpu_CSf; + +extern TCGv cpu_Lf; +extern TCGv cpu_Zf; +extern TCGv cpu_Nf; +extern TCGv cpu_Cf; +extern TCGv cpu_Vf; +extern TCGv cpu_Uf; + +extern TCGv cpu_DEf; +extern TCGv cpu_AEf; +extern TCGv cpu_A2f; +extern TCGv cpu_A1f; +extern TCGv cpu_E2f; +extern TCGv cpu_E1f; +extern TCGv cpu_Hf; + +extern TCGv cpu_l1_Lf; +extern TCGv cpu_l1_Zf; +extern TCGv cpu_l1_Nf; +extern TCGv cpu_l1_Cf; +extern TCGv cpu_l1_Vf; +extern TCGv cpu_l1_Uf; + +extern TCGv cpu_l1_DEf; +extern TCGv cpu_l1_AEf; +extern TCGv cpu_l1_A2f; +extern TCGv cpu_l1_A1f; +extern TCGv cpu_l1_E2f; +extern TCGv cpu_l1_E1f; +extern TCGv cpu_l1_Hf; + +extern TCGv cpu_l2_Lf; +extern TCGv cpu_l2_Zf; +extern TCGv cpu_l2_Nf; +extern TCGv cpu_l2_Cf; +extern TCGv cpu_l2_Vf; +extern TCGv cpu_l2_Uf; + +extern TCGv cpu_l2_DEf; +extern TCGv cpu_l2_AEf; +extern TCGv cpu_l2_A2f; +extern TCGv cpu_l2_A1f; +extern TCGv cpu_l2_E2f; +extern TCGv cpu_l2_E1f; +extern TCGv cpu_l2_Hf; + +extern TCGv cpu_er_Lf; +extern TCGv cpu_er_Zf; +extern TCGv cpu_er_Nf; +extern TCGv cpu_er_Cf; +extern TCGv cpu_er_Vf; +extern TCGv cpu_er_Uf; + +extern TCGv cpu_er_DEf; +extern TCGv cpu_er_AEf; +extern TCGv cpu_er_A2f; +extern TCGv cpu_er_A1f; +extern TCGv cpu_er_E2f; +extern TCGv cpu_er_E1f; +extern TCGv cpu_er_Hf; + +extern TCGv cpu_eret; +extern TCGv cpu_erbta; +extern TCGv cpu_ecr; +extern TCGv cpu_efa; + +extern TCGv cpu_pc; +extern TCGv cpu_lpc; +extern TCGv cpu_lps; +extern TCGv cpu_lpe; + +extern TCGv cpu_bta; +extern TCGv cpu_bta_l1; +extern TCGv cpu_bta_l2; + +extern TCGv cpu_r[64]; + +extern TCGv cpu_intvec; + +extern TCGv cpu_debug_LD; +extern TCGv cpu_debug_SH; +extern TCGv cpu_debug_BH; +extern TCGv cpu_debug_UB; +extern TCGv cpu_debug_ZZ; +extern TCGv cpu_debug_RA; +extern TCGv cpu_debug_IS; +extern TCGv cpu_debug_FH; +extern TCGv cpu_debug_SS; + +enum { + BS_NONE = 0x00, /* Nothing special (none of the below */ + BS_STOP = 0x01, /* We want to stop translation for any reason */ + BS_BRANCH = 0x02, /* A branch condition is reached */ + BS_BRANCH_DS = 0x03, /* A branch condition is reached */ + BS_EXCP = 0x04, /* An exception condition is reached */ + BS_BREAK = 0x05, +}; + +#define BS_DELAYED_SLOT(n) ((n) ? BS_BRANCH_DS : BS_BRANCH) + +typedef struct DisasCtxt DisasCtxt; + +/*This is the state at translation time. */ +typedef struct options_s { + bool di; /* direct data cache bypass */ + bool f; /* set flags */ + bool d; /* delay slot mode*/ + bool x; /* sign extend */ + bool limm; + uint8_t aa; /* address writeback */ + uint8_t zz; /* data size */ +} options_t; + +struct DisasCtxt { + struct TranslationBlock *tb; + + uint32_t cpc; /* current pc */ + uint32_t npc; /* next pc */ + uint32_t dpc; /* next next pc */ + uint32_t pcl; + uint32_t lpe; + + unsigned ds; /* we are within ds*/ + + TCGv one; /* 0x00000000 */ + TCGv zero; /* 0x00000000 */ + TCGv msb32; /* 0x80000000 */ + TCGv msb16; /* 0x00008000 */ + TCGv smax16; /* 0x7fffffff */ + TCGv smax32; /* 0x00007fff */ + TCGv smax5; /* 0x0000001f */ + TCGv smin5; /* 0xffffffe1 */ + + options_t opt; + + int memidx; + int bstate; + int singlestep; + + CPUARCState *env; +}; + +int arc_decode(DisasCtxt *ctx); +int arc_gen_INVALID(DisasCtxt *ctx); + +static inline void gen_goto_tb(CPUARCState *env, DisasCtxt *ctx, + int n, target_ulong dest) +{ + TranslationBlock *tb; + + tb = ctx->tb; + + if (ctx->singlestep == 0) { + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(cpu_pc, dest & 0xfffffffe); /* TODO ??? */ + tcg_gen_movi_tl(cpu_pcl, dest & 0xfffffffc); + tcg_gen_exit_tb((uintptr_t)tb + n); + } else { + tcg_gen_movi_tl(cpu_pc, dest & 0xfffffffe); /* TODO ??? */ + tcg_gen_movi_tl(cpu_pcl, dest & 0xfffffffc); + gen_helper_debug(cpu_env); + tcg_gen_exit_tb(0); + } +} + + +#endif + -- 2.4.9 (Apple Git-60)