[PATCH 01/27] arc: Add initial core cpu files
cupertinomiranda at gmail.com
cupertinomiranda at gmail.com
Mon Apr 5 15:31:12 BST 2021
From: Cupertino Miranda <cmiranda at synopsys.com>
Signed-off-by: Cupertino Miranda <cmiranda at synopsys.com>
---
target/arc/arc-common.h | 54 +++++
target/arc/cpu-param.h | 32 +++
target/arc/cpu-qom.h | 52 +++++
target/arc/cpu.c | 472 ++++++++++++++++++++++++++++++++++++++++
target/arc/cpu.h | 445 +++++++++++++++++++++++++++++++++++++
target/arc/meson.build | 21 ++
6 files changed, 1076 insertions(+)
create mode 100644 target/arc/arc-common.h
create mode 100644 target/arc/cpu-param.h
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/meson.build
diff --git a/target/arc/arc-common.h b/target/arc/arc-common.h
new file mode 100644
index 0000000000..ff9f97d457
--- /dev/null
+++ b/target/arc/arc-common.h
@@ -0,0 +1,54 @@
+/*
+ * Common header file to be used by cpu and disassembler.
+ * Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GAS or GDB; see the file COPYING3. If not, write to
+ * the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef ARC_COMMON_H
+#define ARC_COMMON_H
+
+
+/* CPU combi. */
+#define ARC_OPCODE_ARCALL (ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700 \
+ | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS)
+#define ARC_OPCODE_ARCFPX (ARC_OPCODE_ARC700 | ARC_OPCODE_ARCv2EM)
+#define ARC_OPCODE_ARCV1 (ARC_OPCODE_ARC700 | ARC_OPCODE_ARC600)
+#define ARC_OPCODE_ARCV2 (ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS)
+#define ARC_OPCODE_ARCMPY6E (ARC_OPCODE_ARC700 | ARC_OPCODE_ARCV2)
+
+
+enum arc_cpu_family {
+ ARC_OPCODE_NONE = 0,
+ ARC_OPCODE_DEFAULT = 1 << 0,
+ ARC_OPCODE_ARC600 = 1 << 1,
+ ARC_OPCODE_ARC700 = 1 << 2,
+ ARC_OPCODE_ARCv2EM = 1 << 3,
+ ARC_OPCODE_ARCv2HS = 1 << 4
+};
+
+typedef struct {
+ uint32_t value;
+ uint32_t type;
+} operand_t;
+
+typedef struct {
+ uint32_t class;
+ uint32_t limm;
+ uint8_t len;
+ bool limm_p;
+ operand_t operands[3];
+ uint8_t n_ops;
+ uint8_t cc;
+ uint8_t aa;
+ uint8_t zz;
+ bool d;
+ bool f;
+ bool di;
+ bool x;
+} insn_t;
+
+#endif
diff --git a/target/arc/cpu-param.h b/target/arc/cpu-param.h
new file mode 100644
index 0000000000..512f4c8b75
--- /dev/null
+++ b/target/arc/cpu-param.h
@@ -0,0 +1,32 @@
+/*
+ * ARC cpu parameters for qemu.
+ *
+ * Copyright (c) 2020 Synopsys Inc.
+ * Contributed by Shahab Vahedi <shahab at synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ARC_CPU_PARAM_H
+#define ARC_CPU_PARAM_H 1
+
+#define TARGET_LONG_BITS 32
+#define TARGET_PAGE_BITS 13
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+#define NB_MMU_MODES 2
+
+#endif
+
+/*-*-indent-tabs-mode:nil;tab-width:4;indent-line-function:'insert-tab'-*-*/
+/* vim: set ts=4 sw=4 et: */
diff --git a/target/arc/cpu-qom.h b/target/arc/cpu-qom.h
new file mode 100644
index 0000000000..ee60db158d
--- /dev/null
+++ b/target/arc/cpu-qom.h
@@ -0,0 +1,52 @@
+/*
+ * QEMU ARC CPU
+ *
+ * Copyright (c) 2020 Synopsys Inc.
+ * Contributed by Cupertino Miranda <cmiranda at synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_ARC_CPU_QOM_H
+#define QEMU_ARC_CPU_QOM_H
+
+#include "hw/core/cpu.h"
+
+#define TYPE_ARC_CPU "arc-cpu"
+
+#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.
+ *
+ * A ARC CPU model.
+ */
+typedef struct ARCCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ DeviceRealize parent_realize;
+ DeviceReset parent_reset;
+} ARCCPUClass;
+
+typedef struct ARCCPU ARCCPU;
+
+#endif
diff --git a/target/arc/cpu.c b/target/arc/cpu.c
new file mode 100644
index 0000000000..f1a5b2a7c1
--- /dev/null
+++ b/target/arc/cpu.c
@@ -0,0 +1,472 @@
+/*
+ * QEMU ARC CPU
+ *
+ * Copyright (c) 2020 Synopsys Inc.
+ * Contributed by Cupertino Miranda <cmiranda at synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "migration/vmstate.h"
+#include "exec/log.h"
+#include "mmu.h"
+#include "mpu.h"
+#include "hw/qdev-properties.h"
+#include "irq.h"
+#include "hw/arc/cpudevs.h"
+#include "timer.h"
+#include "gdbstub.h"
+
+static const VMStateDescription vms_arc_cpu = {
+ .name = "cpu",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property arc_cpu_properties[] = {
+ DEFINE_PROP_UINT32("address-size", ARCCPU, cfg.addr_size, 32),
+ DEFINE_PROP_BOOL("aps", ARCCPU, cfg.aps_feature, false),
+ DEFINE_PROP_BOOL("byte-order", ARCCPU, cfg.byte_order, false),
+ DEFINE_PROP_BOOL("bitscan", ARCCPU, cfg.bitscan_option, true),
+ DEFINE_PROP_UINT32("br_bc-entries", ARCCPU, cfg.br_bc_entries, -1),
+ DEFINE_PROP_UINT32("br_pt-entries", ARCCPU, cfg.br_pt_entries, -1),
+ DEFINE_PROP_BOOL("full-tag", ARCCPU, cfg.br_bc_full_tag, false),
+ DEFINE_PROP_UINT8("rs-entries", ARCCPU, cfg.br_rs_entries, -1),
+ DEFINE_PROP_UINT32("tag-size", ARCCPU, cfg.br_bc_tag_size, -1),
+ DEFINE_PROP_UINT8("tosq-entries", ARCCPU, cfg.br_tosq_entries, -1),
+ DEFINE_PROP_UINT8("fb-entries", ARCCPU, cfg.br_fb_entries, -1),
+ DEFINE_PROP_BOOL("code-density", ARCCPU, cfg.code_density, true),
+ DEFINE_PROP_BOOL("code-protect", ARCCPU, cfg.code_protect, false),
+ DEFINE_PROP_UINT8("dcc-memcyc", ARCCPU, cfg.dccm_mem_cycles, -1),
+ DEFINE_PROP_BOOL("ddcm-posedge", ARCCPU, cfg.dccm_posedge, false),
+ DEFINE_PROP_UINT8("dcc-mem-banks", ARCCPU, cfg.dccm_mem_bancks, -1),
+ DEFINE_PROP_UINT8("mem-cycles", ARCCPU, cfg.dc_mem_cycles, -1),
+ DEFINE_PROP_BOOL("dc-posedge", ARCCPU, cfg.dc_posedge, false),
+ DEFINE_PROP_BOOL("unaligned", ARCCPU, cfg.dmp_unaligned, true),
+ DEFINE_PROP_BOOL("ecc-excp", ARCCPU, cfg.ecc_exception, false),
+ DEFINE_PROP_UINT32("ext-irq", ARCCPU, cfg.external_interrupts, 128),
+ DEFINE_PROP_UINT8("ecc-option", ARCCPU, cfg.ecc_option, -1),
+ DEFINE_PROP_BOOL("firq", ARCCPU, cfg.firq_option, true),
+ DEFINE_PROP_BOOL("fpu-dp", ARCCPU, cfg.fpu_dp_option, false),
+ DEFINE_PROP_BOOL("fpu-fma", ARCCPU, cfg.fpu_fma_option, false),
+ DEFINE_PROP_BOOL("fpu-div", ARCCPU, cfg.fpu_div_option, false),
+ DEFINE_PROP_BOOL("actionpoints", ARCCPU, cfg.has_actionpoints, false),
+ DEFINE_PROP_BOOL("fpu", ARCCPU, cfg.has_fpu, false),
+ DEFINE_PROP_BOOL("has-irq", ARCCPU, cfg.has_interrupts, true),
+ DEFINE_PROP_BOOL("has-mmu", ARCCPU, cfg.has_mmu, true),
+ DEFINE_PROP_BOOL("has-mpu", ARCCPU, cfg.has_mpu, true),
+ DEFINE_PROP_BOOL("timer0", ARCCPU, cfg.has_timer_0, true),
+ DEFINE_PROP_BOOL("timer1", ARCCPU, cfg.has_timer_1, true),
+ DEFINE_PROP_BOOL("has-pct", ARCCPU, cfg.has_pct, false),
+ DEFINE_PROP_BOOL("has-rtt", ARCCPU, cfg.has_rtt, false),
+ DEFINE_PROP_BOOL("has-smart", ARCCPU, cfg.has_smart, false),
+ DEFINE_PROP_UINT32("intv-base", ARCCPU, cfg.intvbase_preset, 0x0),
+ DEFINE_PROP_UINT32("lpc-size", ARCCPU, cfg.lpc_size, 32),
+ DEFINE_PROP_UINT8("mpu-numreg", ARCCPU, cfg.mpu_num_regions, 0),
+ DEFINE_PROP_UINT8("mpy-option", ARCCPU, cfg.mpy_option, 2),
+ DEFINE_PROP_UINT32("mmu-pagesize0", ARCCPU, cfg.mmu_page_size_sel0, -1),
+ DEFINE_PROP_UINT32("mmu-pagesize1", ARCCPU, cfg.mmu_page_size_sel1, -1),
+ DEFINE_PROP_UINT32("mmu-pae", ARCCPU, cfg.mmu_pae_enabled, -1),
+ DEFINE_PROP_UINT32("ntlb-numentries", ARCCPU, cfg.ntlb_num_entries, -1),
+ DEFINE_PROP_UINT32("num-actionpoints", ARCCPU, cfg.num_actionpoints, -1),
+ DEFINE_PROP_UINT32("num-irq", ARCCPU, cfg.number_of_interrupts, 240),
+ DEFINE_PROP_UINT32("num-irqlevels", ARCCPU, cfg.number_of_levels, 15),
+ DEFINE_PROP_UINT32("pct-counters", ARCCPU, cfg.pct_counters, -1),
+ DEFINE_PROP_UINT32("pct-irq", ARCCPU, cfg.pct_interrupt, -1),
+ DEFINE_PROP_UINT32("pc-size", ARCCPU, cfg.pc_size, 32),
+ DEFINE_PROP_UINT32("num-regs", ARCCPU, cfg.rgf_num_regs, 32),
+ DEFINE_PROP_UINT32("banked-regs", ARCCPU, cfg.rgf_banked_regs, -1),
+ DEFINE_PROP_UINT32("num-banks", ARCCPU, cfg.rgf_num_banks, 0),
+ DEFINE_PROP_BOOL("rtc-opt", ARCCPU, cfg.rtc_option, false),
+ DEFINE_PROP_UINT32("rtt-featurelevel", ARCCPU, cfg.rtt_feature_level, -1),
+ DEFINE_PROP_BOOL("stack-check", ARCCPU, cfg.stack_checking, false),
+ DEFINE_PROP_BOOL("swap-option", ARCCPU, cfg.swap_option, true),
+ DEFINE_PROP_UINT32("smrt-stackentries", ARCCPU, cfg.smar_stack_entries, -1),
+ DEFINE_PROP_UINT32("smrt-impl", ARCCPU, cfg.smart_implementation, -1),
+ DEFINE_PROP_UINT32("stlb", ARCCPU, cfg.stlb_num_entries, -1),
+ DEFINE_PROP_UINT32("slc-size", ARCCPU, cfg.slc_size, -1),
+ DEFINE_PROP_UINT32("slc-linesize", ARCCPU, cfg.slc_line_size, -1),
+ DEFINE_PROP_UINT32("slc-ways", ARCCPU, cfg.slc_ways, -1),
+ DEFINE_PROP_UINT32("slc-tagbanks", ARCCPU, cfg.slc_tag_banks, -1),
+ DEFINE_PROP_UINT32("slc-tram", ARCCPU, cfg.slc_tram_delay, -1),
+ DEFINE_PROP_UINT32("slc-dbank", ARCCPU, cfg.slc_dbank_width, -1),
+ DEFINE_PROP_UINT32("slc-data", ARCCPU, cfg.slc_data_banks, -1),
+ DEFINE_PROP_UINT32("slc-delay", ARCCPU, cfg.slc_dram_delay, -1),
+ DEFINE_PROP_BOOL("slc-memwidth", ARCCPU, cfg.slc_mem_bus_width, false),
+ DEFINE_PROP_UINT32("slc-ecc", ARCCPU, cfg.slc_ecc_option, -1),
+ DEFINE_PROP_BOOL("slc-datahalf", ARCCPU, cfg.slc_data_halfcycle_steal, false),
+ DEFINE_PROP_BOOL("slc-dataadd", ARCCPU, cfg.slc_data_add_pre_pipeline, false),
+ DEFINE_PROP_BOOL("uaux", ARCCPU, cfg.uaux_option, false),
+ DEFINE_PROP_UINT32("freq_hz", ARCCPU, cfg.freq_hz, 4600000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arc_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ ARCCPU *cpu = ARC_CPU(cs);
+
+ CPU_PCL(&cpu->env) = value & (~((target_ulong) 3));
+ cpu->env.pc = value;
+}
+
+static bool arc_cpu_has_work(CPUState *cs)
+{
+ return cs->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+static void arc_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb)
+{
+ ARCCPU *cpu = ARC_CPU(cs);
+ CPUARCState *env = &cpu->env;
+
+ CPU_PCL(&cpu->env) = tb->pc & (~((target_ulong) 3));
+ env->pc = tb->pc;
+}
+
+static void arc_cpu_reset(DeviceState *dev)
+{
+ CPUState *s = CPU(dev);
+ ARCCPU *cpu = ARC_CPU(s);
+ ARCCPUClass *arcc = ARC_CPU_GET_CLASS(cpu);
+ CPUARCState *env = &cpu->env;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU)\n");
+ log_cpu_state(s, 0);
+ }
+
+ /* Initialize mmu/reset it. */
+ arc_mmu_init(env);
+
+ arc_mpu_init(cpu);
+
+ arc_resetTIMER(cpu);
+ arc_resetIRQ(cpu);
+
+ arcc->parent_reset(dev);
+
+ memset(env->r, 0, sizeof(env->r));
+ env->lock_lf_var = 0;
+
+ env->stat.is_delay_slot_instruction = 0;
+ /*
+ * kernel expects MPY support to check for presence of
+ * extension core regs r58/r59.
+ *
+ * VERSION32x32=0x06: ARCv2 32x32 Multiply
+ * DSP=0x1: MPY_OPTION 7
+ */
+ cpu->mpy_build = 0x00001006;
+}
+
+static void arc_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
+{
+ ARCCPU *cpu = ARC_CPU(cs);
+
+ switch (cpu->family) {
+ case ARC_OPCODE_ARC700:
+ info->mach = bfd_mach_arc_arc700;
+ break;
+ case ARC_OPCODE_ARC600:
+ info->mach = bfd_mach_arc_arc600;
+ break;
+ case ARC_OPCODE_ARCv2EM:
+ info->mach = bfd_mach_arc_arcv2em;
+ break;
+ case ARC_OPCODE_ARCv2HS:
+ info->mach = bfd_mach_arc_arcv2hs;
+ break;
+ default:
+ info->mach = bfd_mach_arc_arcv2;
+ break;
+ }
+
+ info->print_insn = print_insn_arc;
+ info->endian = BFD_ENDIAN_LITTLE;
+}
+
+
+static void arc_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ ARCCPU *cpu = ARC_CPU(dev);
+ ARCCPUClass *arcc = ARC_CPU_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ cpu_exec_realizefn(cs, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ arc_cpu_register_gdb_regs_for_features(cpu);
+
+ qemu_init_vcpu(cs);
+
+ /*
+ * Initialize build registers depending on the simulation
+ * parameters.
+ */
+ cpu->freq_hz = cpu->cfg.freq_hz;
+
+ cpu->isa_config = 0x02;
+ switch (cpu->cfg.pc_size) {
+ case 16:
+ break;
+ case 20:
+ cpu->isa_config |= 1 << 8;
+ break;
+ case 24:
+ cpu->isa_config |= 2 << 8;
+ break;
+ case 28:
+ cpu->isa_config |= 3 << 8;
+ break;
+ default:
+ cpu->isa_config |= 4 << 8;
+ break;
+ }
+
+ switch (cpu->cfg.lpc_size) {
+ case 0:
+ break;
+ case 8:
+ cpu->isa_config |= 1 << 12;
+ break;
+ case 12:
+ cpu->isa_config |= 2 << 12;
+ break;
+ case 16:
+ cpu->isa_config |= 3 << 12;
+ break;
+ case 20:
+ cpu->isa_config |= 4 << 12;
+ break;
+ case 24:
+ cpu->isa_config |= 5 << 12;
+ break;
+ case 28:
+ cpu->isa_config |= 6 << 12;
+ break;
+ default:
+ cpu->isa_config |= 7 << 12;
+ break;
+ }
+
+ switch (cpu->cfg.addr_size) {
+ case 16:
+ break;
+ case 20:
+ cpu->isa_config |= 1 << 16;
+ break;
+ case 24:
+ cpu->isa_config |= 2 << 16;
+ break;
+ case 28:
+ cpu->isa_config |= 3 << 16;
+ break;
+ default:
+ cpu->isa_config |= 4 << 16;
+ break;
+ }
+
+ cpu->isa_config |= (cpu->cfg.byte_order ? BIT(20) : 0) | BIT(21)
+ | (cpu->cfg.dmp_unaligned ? BIT(22) : 0) | BIT(23)
+ | (cpu->cfg.code_density ? (2 << 24) : 0) | BIT(28);
+
+ arc_initializeTIMER(cpu);
+ arc_initializeIRQ(cpu);
+
+ cpu_reset(cs);
+
+ arcc->parent_realize(dev, errp);
+}
+
+static void arc_cpu_initfn(Object *obj)
+{
+ ARCCPU *cpu = ARC_CPU(obj);
+
+ /* Initialize aux-regs. */
+ arc_aux_regs_init();
+
+ cpu_set_cpustate_pointers(cpu);
+}
+
+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 gchar *arc_gdb_arch_name(CPUState *cs)
+{
+ return g_strdup(GDB_TARGET_STRING);
+}
+
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps arc_tcg_ops = {
+ .initialize = arc_translate_init,
+ .synchronize_from_tb = arc_cpu_synchronize_from_tb,
+ .cpu_exec_interrupt = arc_cpu_exec_interrupt,
+ .tlb_fill = arc_cpu_tlb_fill,
+
+#ifndef CONFIG_USER_ONLY
+ .do_interrupt = arc_cpu_do_interrupt,
+#endif /* !CONFIG_USER_ONLY */
+};
+
+static void arc_cpu_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ CPUClass *cc = CPU_CLASS(oc);
+ ARCCPUClass *arcc = ARC_CPU_CLASS(oc);
+
+ device_class_set_parent_realize(dc, arc_cpu_realizefn,
+ &arcc->parent_realize);
+
+ device_class_set_parent_reset(dc, arc_cpu_reset, &arcc->parent_reset);
+
+ cc->class_by_name = arc_cpu_class_by_name;
+
+ cc->has_work = arc_cpu_has_work;
+ cc->dump_state = arc_cpu_dump_state;
+ cc->set_pc = arc_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ cc->memory_rw_debug = arc_cpu_memory_rw_debug;
+ 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->gdb_read_register = arc_cpu_gdb_read_register;
+ cc->gdb_write_register = arc_cpu_gdb_write_register;
+
+ /* Core GDB support */
+ cc->gdb_core_xml_file = "arc-v2-core.xml";
+ cc->gdb_num_core_regs = GDB_REG_LAST;
+ cc->gdb_arch_name = arc_gdb_arch_name;
+
+ cc->tcg_ops = &arc_tcg_ops;
+
+ device_class_set_props(dc, arc_cpu_properties);
+}
+
+static void arc_any_initfn(Object *obj)
+{
+ /* Set cpu feature flags */
+ ARCCPU *cpu = ARC_CPU(obj);
+ cpu->family = ARC_OPCODE_ARC700;
+}
+
+static void arc600_initfn(Object *obj)
+{
+ ARCCPU *cpu = ARC_CPU(obj);
+ cpu->family = ARC_OPCODE_ARC600;
+}
+
+static void arc700_initfn(Object *obj)
+{
+ ARCCPU *cpu = ARC_CPU(obj);
+ cpu->family = ARC_OPCODE_ARC700;
+}
+
+static void arcem_initfn(Object *obj)
+{
+ ARCCPU *cpu = ARC_CPU(obj);
+ cpu->family = ARC_OPCODE_ARCv2EM;
+}
+
+static void archs_initfn(Object *obj)
+{
+ ARCCPU *cpu = ARC_CPU(obj);
+ cpu->family = ARC_OPCODE_ARCv2HS;
+}
+
+typedef struct ARCCPUInfo {
+ const char *name;
+ void (*initfn)(Object *obj);
+} ARCCPUInfo;
+
+static const ARCCPUInfo arc_cpus[] = {
+ { .name = "arc600", .initfn = arc600_initfn },
+ { .name = "arc700", .initfn = arc700_initfn },
+ { .name = "arcem", .initfn = arcem_initfn },
+ { .name = "archs", .initfn = archs_initfn },
+ { .name = "any", .initfn = arc_any_initfn },
+};
+
+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)
+
+/*-*-indent-tabs-mode:nil;tab-width:4;indent-line-function:'insert-tab'-*-*/
+/* vim: set ts=4 sw=4 et: */
diff --git a/target/arc/cpu.h b/target/arc/cpu.h
new file mode 100644
index 0000000000..37d2a3582f
--- /dev/null
+++ b/target/arc/cpu.h
@@ -0,0 +1,445 @@
+/*
+ * QEMU ARC CPU
+ *
+ * Copyright (c) 2020 Synopsys Inc.
+ * Contributed by Cupertino Miranda <cmiranda at synopsys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CPU_ARC_H
+#define CPU_ARC_H
+
+#include "exec/cpu-defs.h"
+#include "fpu/softfloat.h"
+
+#include "target/arc/arc-common.h"
+#include "target/arc/mmu.h"
+#include "target/arc/mpu.h"
+#include "target/arc/cache.h"
+
+#define ARC_CPU_TYPE_SUFFIX "-" TYPE_ARC_CPU
+#define ARC_CPU_TYPE_NAME(model) model ARC_CPU_TYPE_SUFFIX
+#define CPU_RESOLVING_TYPE TYPE_ARC_CPU
+
+enum arc_features {
+ ARC_FEATURE_ARC5,
+ ARC_FEATURE_ARC600,
+ ARC_FEATURE_ARC700,
+ no_features,
+};
+
+enum arc_endianess {
+ ARC_ENDIANNESS_LE = 0,
+ ARC_ENDIANNESS_BE,
+};
+
+/* U-Boot - kernel ABI */
+#define ARC_UBOOT_CMDLINE 1
+#define ARC_UBOOT_DTB 2
+
+
+#define CPU_GP(env) ((env)->r[26])
+#define CPU_FP(env) ((env)->r[27])
+#define CPU_SP(env) ((env)->r[28])
+#define CPU_ILINK(env) ((env)->r[29])
+#define CPU_ILINK1(env) ((env)->r[29])
+#define CPU_ILINK2(env) ((env)->r[30])
+#define CPU_BLINK(env) ((env)->r[31])
+#define CPU_LP(env) ((env)->r[60])
+#define CPU_IMM(env) ((env)->r[62])
+#define CPU_PCL(env) ((env)->r[63])
+
+enum exception_code_list {
+ EXCP_NO_EXCEPTION = -1,
+ EXCP_RESET = 0,
+ EXCP_MEMORY_ERROR,
+ EXCP_INST_ERROR,
+ EXCP_MACHINE_CHECK,
+ EXCP_TLB_MISS_I,
+ EXCP_TLB_MISS_D,
+ EXCP_PROTV,
+ EXCP_PRIVILEGEV,
+ EXCP_SWI,
+ EXCP_TRAP,
+ EXCP_EXTENSION,
+ EXCP_DIVZERO,
+ EXCP_DCERROR,
+ EXCP_MISALIGNED,
+ EXCP_IRQ,
+ EXCP_LPEND_REACHED = 9000,
+ EXCP_FAKE
+};
+
+
+/*
+ * Status32 register bits
+ * -- Ixxx xxxx xxxU ARRR ESDL ZNCV Udae eeeH --
+ *
+ * I = IE - Interrupt Enable
+ * x = - Reserved
+ * U = US - User sleep mode enable
+ * A = AD - Disable alignment checking
+ * R = RB - Select a register bank
+ * E = ES - EI_S table instruction pending
+ * S = SC - Enable stack checking
+ * D = DZ - RV_DivZero exception enable
+ * L = - Zero-overhead loop disable
+ * Z = - Zero status flag
+ * N = - Negative status flag
+ * C = - Cary status flag
+ * V = - Overflow status flag
+ * U = - User mode
+ * d = DE - Delayed branch is pending
+ * a = AE - Processor is in an exception
+ * e = E - Interrupt priority operating level`I
+ * H = - Halt flag
+ */
+
+/* Flags in pstate */
+#define Hf_b (0)
+#define AEf_b (5)
+#define Uf_b (7)
+#define Lf_b (12)
+#define DZf_b (13)
+#define SCf_b (14)
+#define ESf_b (15)
+#define ADf_b (19)
+#define USf_b (20)
+
+/* Flags with their on fields */
+#define IEf_b (31)
+#define IEf_bS (1)
+
+#define Ef_b (1)
+#define Ef_bS (4)
+
+#define DEf_b (6)
+#define DEf_bS (1)
+
+#define Vf_b (8)
+#define Vf_bS (1)
+#define Cf_b (9)
+#define Cf_bS (1)
+#define Nf_b (10)
+#define Nf_bS (1)
+#define Zf_b (11)
+#define Zf_bS (1)
+
+#define RBf_b (16)
+#define RBf_bS (3)
+
+
+#define PSTATE_MASK \
+ ((1 << Hf_b) \
+ | (1 << AEf_b) \
+ | (1 << Uf_b) \
+ | (1 << Lf_b) \
+ | (1 << DZf_b) \
+ | (1 << SCf_b) \
+ | (1 << ESf_b) \
+ | (1 << ADf_b) \
+ | (1 << USf_b))
+
+#define GET_STATUS_BIT(STAT, BIT) ((STAT.pstate >> BIT##_b) & 0x1)
+#define SET_STATUS_BIT(STAT, BIT, VALUE) { \
+ STAT.pstate &= ~(1 << BIT##_b); \
+ STAT.pstate |= (VALUE << BIT##_b); \
+}
+
+typedef struct {
+ target_ulong pstate;
+
+ target_ulong RBf;
+ target_ulong Ef; /* irq priority treshold. */
+ target_ulong Vf; /* overflow */
+ target_ulong Cf; /* carry */
+ target_ulong Nf; /* negative */
+ target_ulong Zf; /* zero */
+ target_ulong DEf;
+ target_ulong IEf;
+
+ /* Reserved bits */
+
+ /* Next instruction is a delayslot instruction */
+ bool is_delay_slot_instruction;
+} ARCStatus;
+
+/* ARC processor timer module. */
+typedef struct {
+ target_ulong T_Cntrl;
+ target_ulong T_Limit;
+ uint64_t last_clk;
+} ARCTimer;
+
+/* ARC PIC interrupt bancked regs. */
+typedef struct {
+ target_ulong priority;
+ target_ulong trigger;
+ target_ulong pulse_cancel;
+ target_ulong enable;
+ target_ulong pending;
+ target_ulong status;
+} ARCIrq;
+
+typedef struct CPUARCState {
+ target_ulong r[64];
+
+ ARCStatus stat, stat_l1, stat_er;
+
+ struct {
+ target_ulong S2;
+ target_ulong S1;
+ target_ulong CS;
+ } macmod;
+
+ target_ulong intvec;
+
+ target_ulong eret;
+ target_ulong erbta;
+ target_ulong ecr;
+ target_ulong efa;
+ target_ulong bta;
+ target_ulong bta_l1;
+ target_ulong bta_l2;
+
+ target_ulong pc; /* program counter */
+ target_ulong lps; /* loops start */
+ target_ulong lpe; /* loops end */
+
+ target_ulong npc; /* required for LP - zero overhead loops. */
+
+ target_ulong lock_lf_var;
+
+#define TMR_IE (1 << 0)
+#define TMR_NH (1 << 1)
+#define TMR_W (1 << 2)
+#define TMR_IP (1 << 3)
+#define TMR_PD (1 << 4)
+ ARCTimer timer[2]; /* ARC CPU-Timer 0/1 */
+
+ ARCIrq irq_bank[256]; /* IRQ register bank */
+ uint32_t irq_select; /* AUX register */
+ uint32_t aux_irq_act; /* AUX register */
+ uint32_t irq_priority_pending; /* AUX register */
+ uint32_t icause[16]; /* Banked cause register */
+ uint32_t aux_irq_hint; /* AUX register, used to trigger soft irq */
+ uint32_t aux_user_sp;
+ uint32_t aux_irq_ctrl;
+ uint32_t aux_rtc_ctrl;
+ uint32_t aux_rtc_low;
+ uint32_t aux_rtc_high;
+
+ /* Fields required by exception handling. */
+ uint32_t causecode;
+ uint32_t param;
+
+ struct arc_mmu mmu; /* mmu.h */
+ ARCMPU mpu; /* mpu.h */
+ struct arc_cache cache; /* cache.h */
+
+ /* used for propagatinng "hostpc/return address" to sub-functions */
+ uintptr_t host_pc;
+
+ bool stopped;
+
+ /* Fields up to this point are cleared by a CPU reset */
+ struct {} end_reset_fields;
+
+ uint64_t last_clk_rtc;
+
+ void *irq[256];
+ QEMUTimer *cpu_timer[2]; /* Internal timer. */
+ QEMUTimer *cpu_rtc; /* Internal RTC. */
+
+ const struct arc_boot_info *boot_info;
+
+ bool enabled_interrupts;
+} CPUARCState;
+
+/*
+ * ArcCPU:
+ * @env: #CPUMBState
+ *
+ * An ARC CPU.
+ */
+struct ARCCPU {
+ /*< private >*/
+ CPUState parent_obj;
+
+ /*< public >*/
+
+ /* ARC Configuration Settings. */
+ struct {
+ uint32_t addr_size;
+ uint32_t br_bc_entries;
+ uint32_t br_pt_entries;
+ uint32_t br_bc_tag_size;
+ uint32_t external_interrupts;
+ uint32_t intvbase_preset;
+ uint32_t lpc_size;
+ uint32_t mmu_page_size_sel0;
+ uint32_t mmu_page_size_sel1;
+ uint32_t mmu_pae_enabled;
+ uint32_t ntlb_num_entries;
+ uint32_t num_actionpoints;
+ uint32_t number_of_interrupts;
+ uint32_t number_of_levels;
+ uint32_t pct_counters;
+ uint32_t pct_interrupt;
+ uint32_t pc_size;
+ uint32_t rgf_num_regs;
+ uint32_t rgf_banked_regs;
+ uint32_t rgf_num_banks;
+ uint32_t rtt_feature_level;
+ uint32_t smar_stack_entries;
+ uint32_t smart_implementation;
+ uint32_t stlb_num_entries;
+ uint32_t slc_size;
+ uint32_t slc_line_size;
+ uint32_t slc_ways;
+ uint32_t slc_tag_banks;
+ uint32_t slc_tram_delay;
+ uint32_t slc_dbank_width;
+ uint32_t slc_data_banks;
+ uint32_t slc_dram_delay;
+ uint32_t slc_ecc_option;
+ uint32_t freq_hz; /* CPU frequency in hz, needed for timers. */
+ uint8_t br_rs_entries;
+ uint8_t br_tosq_entries;
+ uint8_t br_fb_entries;
+ uint8_t dccm_mem_cycles;
+ uint8_t dccm_mem_bancks;
+ uint8_t dc_mem_cycles;
+ uint8_t ecc_option;
+ uint8_t mpu_num_regions;
+ uint8_t mpy_option;
+ bool aps_feature;
+ bool byte_order;
+ bool bitscan_option;
+ bool br_bc_full_tag;
+ bool code_density;
+ bool code_protect;
+ bool dccm_posedge;
+ bool dc_posedge;
+ bool dmp_unaligned;
+ bool ecc_exception;
+ bool firq_option;
+ bool fpu_dp_option;
+ bool fpu_fma_option;
+ bool fpu_div_option;
+ bool has_actionpoints;
+ bool has_fpu;
+ bool has_interrupts;
+ bool has_mmu;
+ bool has_mpu;
+ bool has_timer_0;
+ bool has_timer_1;
+ bool has_pct;
+ bool has_rtt;
+ bool has_smart;
+ bool rtc_option;
+ bool stack_checking;
+ bool swap_option;
+ bool slc_mem_bus_width;
+ bool slc_data_halfcycle_steal;
+ bool slc_data_add_pre_pipeline;
+ bool uaux_option;
+ } cfg;
+
+ uint32_t family;
+
+ /* Build AUX regs. */
+#define TIMER0_IRQ 16
+#define TIMER1_IRQ 17
+#define TB_T0 (1 << 8)
+#define TB_T1 (1 << 9)
+#define TB_RTC (1 << 10)
+#define TB_P0_MSK (0x0f0000)
+#define TB_P1_MSK (0xf00000)
+ uint32_t freq_hz; /* CPU frequency in hz, needed for timers. */
+
+ uint32_t timer_build; /* Timer configuration AUX register. */
+ uint32_t irq_build; /* Interrupt Build Configuration Register. */
+ uint32_t vecbase_build; /* Interrupt Vector Base Address Configuration. */
+ uint32_t mpy_build; /* Multiply configuration register. */
+ uint32_t isa_config; /* Instruction Set Configuration Register. */
+
+ CPUNegativeOffsetState neg;
+ CPUARCState env;
+};
+
+/* are we in user mode? */
+static inline bool is_user_mode(const CPUARCState *env)
+{
+ return GET_STATUS_BIT(env->stat, Uf) != 0;
+}
+
+#define cpu_list arc_cpu_list
+#define cpu_signal_handler cpu_arc_signal_handler
+#define cpu_init(cpu_model) cpu_generic_init(TYPE_ARC_CPU, cpu_model)
+
+typedef CPUARCState CPUArchState;
+typedef ARCCPU ArchCPU;
+
+#include "exec/cpu-all.h"
+
+static inline int cpu_mmu_index(const CPUARCState *env, bool ifetch)
+{
+ return GET_STATUS_BIT(env->stat, Uf) != 0 ? 1 : 0;
+}
+
+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;
+#ifdef CONFIG_USER_ONLY
+ assert(0); /* Not really supported at the moment. */
+#else
+ *pflags = cpu_mmu_index(env, 0);
+#endif
+}
+
+void arc_translate_init(void);
+
+void arc_cpu_list(void);
+int cpu_arc_exec(CPUState *cpu);
+int cpu_arc_signal_handler(int host_signum, void *pinfo, void *puc);
+int arc_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf,
+ int len, bool is_write);
+void arc_cpu_do_interrupt(CPUState *cpu);
+
+void arc_cpu_dump_state(CPUState *cs, FILE *f, int flags);
+hwaddr arc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int arc_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
+int arc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
+void QEMU_NORETURN arc_raise_exception(CPUARCState *env, int32_t excp_idx);
+
+void not_implemented_mmu_init(struct arc_mmu *mmu);
+bool not_implemented_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+
+void arc_mmu_init(CPUARCState *env);
+bool arc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+hwaddr arc_mmu_debug_translate(CPUARCState *env, vaddr addr);
+void arc_mmu_disable(CPUARCState *env);
+
+#include "exec/cpu-all.h"
+
+#endif /* !defined (CPU_ARC_H) */
diff --git a/target/arc/meson.build b/target/arc/meson.build
new file mode 100644
index 0000000000..9bbfb01f98
--- /dev/null
+++ b/target/arc/meson.build
@@ -0,0 +1,21 @@
+arc_softmmu_ss = ss.source_set()
+arc_softmmu_ss.add(files(
+ 'translate.c',
+ 'helper.c',
+ 'cpu.c',
+ 'op_helper.c',
+ 'gdbstub.c',
+ 'decoder.c',
+ 'regs.c',
+ 'regs-impl.c',
+ 'semfunc.c',
+ 'semfunc-helper.c',
+ 'mmu.c',
+ 'mpu.c',
+ 'timer.c',
+ 'irq.c',
+ 'cache.c',
+))
+
+target_arch += {'arc': arc_softmmu_ss}
+target_softmmu_arch += {'arc': arc_softmmu_ss}
--
2.20.1
More information about the linux-snps-arc
mailing list