summaryrefslogtreecommitdiff
path: root/target/loongarch/cpu.c
diff options
context:
space:
mode:
authorSong Gao <gaosong@loongson.cn>2022-06-06 20:42:52 +0800
committerRichard Henderson <richard.henderson@linaro.org>2022-06-06 18:09:03 +0000
commit228021f05ebfd89a3abc225d47a0d0e6c139dade (patch)
tree870881ac9e6f00bc26acb2706925ad5c9036b4e7 /target/loongarch/cpu.c
parent64baad62cd3d9f2e57f65a8f3be7b5639a77e0b4 (diff)
target/loongarch: Add core definition
This patch adds target state header, target definitions and initialization routines. Signed-off-by: Song Gao <gaosong@loongson.cn> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-Id: <20220606124333.2060567-3-yangxiaojuan@loongson.cn> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target/loongarch/cpu.c')
-rw-r--r--target/loongarch/cpu.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
new file mode 100644
index 0000000000..1f8e37906a
--- /dev/null
+++ b/target/loongarch/cpu.c
@@ -0,0 +1,324 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch CPU
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "qemu/qemu-print.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "sysemu/qtest.h"
+#include "exec/exec-all.h"
+#include "qapi/qapi-commands-machine-target.h"
+#include "cpu.h"
+#include "internals.h"
+#include "fpu/softfloat-helpers.h"
+
+const char * const regnames[32] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+};
+
+const char * const fregnames[32] = {
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+};
+
+static const char * const excp_names[] = {
+ [EXCCODE_INT] = "Interrupt",
+ [EXCCODE_PIL] = "Page invalid exception for load",
+ [EXCCODE_PIS] = "Page invalid exception for store",
+ [EXCCODE_PIF] = "Page invalid exception for fetch",
+ [EXCCODE_PME] = "Page modified exception",
+ [EXCCODE_PNR] = "Page Not Readable exception",
+ [EXCCODE_PNX] = "Page Not Executable exception",
+ [EXCCODE_PPI] = "Page Privilege error",
+ [EXCCODE_ADEF] = "Address error for instruction fetch",
+ [EXCCODE_ADEM] = "Address error for Memory access",
+ [EXCCODE_SYS] = "Syscall",
+ [EXCCODE_BRK] = "Break",
+ [EXCCODE_INE] = "Instruction Non-Existent",
+ [EXCCODE_IPE] = "Instruction privilege error",
+ [EXCCODE_FPE] = "Floating Point Exception",
+ [EXCCODE_DBP] = "Debug breakpoint",
+};
+
+const char *loongarch_exception_name(int32_t exception)
+{
+ assert(excp_names[exception]);
+ return excp_names[exception];
+}
+
+void G_NORETURN do_raise_exception(CPULoongArchState *env,
+ uint32_t exception,
+ uintptr_t pc)
+{
+ CPUState *cs = env_cpu(env);
+
+ qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
+ __func__,
+ exception,
+ loongarch_exception_name(exception));
+ cs->exception_index = exception;
+
+ cpu_loop_exit_restore(cs, pc);
+}
+
+static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ env->pc = value;
+}
+
+#ifdef CONFIG_TCG
+static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
+ const TranslationBlock *tb)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ env->pc = tb->pc;
+}
+#endif /* CONFIG_TCG */
+
+static void loongarch_la464_initfn(Object *obj)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+ CPULoongArchState *env = &cpu->env;
+ int i;
+
+ for (i = 0; i < 21; i++) {
+ env->cpucfg[i] = 0x0;
+ }
+
+ env->cpucfg[0] = 0x14c010; /* PRID */
+
+ uint32_t data = 0;
+ data = FIELD_DP32(data, CPUCFG1, ARCH, 2);
+ data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
+ data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
+ data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f);
+ data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f);
+ data = FIELD_DP32(data, CPUCFG1, UAL, 1);
+ data = FIELD_DP32(data, CPUCFG1, RI, 1);
+ data = FIELD_DP32(data, CPUCFG1, EP, 1);
+ data = FIELD_DP32(data, CPUCFG1, RPLV, 1);
+ data = FIELD_DP32(data, CPUCFG1, HP, 1);
+ data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1);
+ env->cpucfg[1] = data;
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG2, FP, 1);
+ data = FIELD_DP32(data, CPUCFG2, FP_SP, 1);
+ data = FIELD_DP32(data, CPUCFG2, FP_DP, 1);
+ data = FIELD_DP32(data, CPUCFG2, FP_VER, 1);
+ data = FIELD_DP32(data, CPUCFG2, LLFTP, 1);
+ data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
+ data = FIELD_DP32(data, CPUCFG2, LAM, 1);
+ env->cpucfg[2] = data;
+
+ env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1);
+ data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
+ env->cpucfg[5] = data;
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
+ data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
+ data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1);
+ data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1);
+ data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1);
+ data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1);
+ data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1);
+ data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1);
+ env->cpucfg[16] = data;
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3);
+ data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8);
+ data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6);
+ env->cpucfg[17] = data;
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3);
+ data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8);
+ data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6);
+ env->cpucfg[18] = data;
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15);
+ data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8);
+ data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6);
+ env->cpucfg[19] = data;
+
+ data = 0;
+ data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15);
+ data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14);
+ data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 6);
+ env->cpucfg[20] = data;
+}
+
+static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
+{
+ const char *typename = object_class_get_name(OBJECT_CLASS(data));
+
+ qemu_printf("%s\n", typename);
+}
+
+void loongarch_cpu_list(void)
+{
+ GSList *list;
+ list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false);
+ g_slist_foreach(list, loongarch_cpu_list_entry, NULL);
+ g_slist_free(list);
+}
+
+static void loongarch_cpu_reset(DeviceState *dev)
+{
+ CPUState *cs = CPU(dev);
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
+ CPULoongArchState *env = &cpu->env;
+
+ lacc->parent_reset(dev);
+
+ env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
+ env->fcsr0 = 0x0;
+
+ cs->exception_index = -1;
+}
+
+static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
+{
+ info->print_insn = print_insn_loongarch;
+}
+
+static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
+{
+ CPUState *cs = CPU(dev);
+ LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
+ Error *local_err = NULL;
+
+ cpu_exec_realizefn(cs, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ cpu_reset(cs);
+ qemu_init_vcpu(cs);
+
+ lacc->parent_realize(dev, errp);
+}
+
+static void loongarch_cpu_init(Object *obj)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+ cpu_set_cpustate_pointers(cpu);
+}
+
+static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
+{
+ ObjectClass *oc;
+ char *typename;
+
+ typename = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model);
+ oc = object_class_by_name(typename);
+ g_free(typename);
+ return oc;
+}
+
+void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ int i;
+
+ qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
+ qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0,
+ get_float_exception_flags(&env->fp_status));
+
+ /* gpr */
+ for (i = 0; i < 32; i++) {
+ if ((i & 3) == 0) {
+ qemu_fprintf(f, " GPR%02d:", i);
+ }
+ qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+
+ /* fpr */
+ if (flags & CPU_DUMP_FPU) {
+ for (i = 0; i < 32; i++) {
+ qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]);
+ if ((i & 3) == 3) {
+ qemu_fprintf(f, "\n");
+ }
+ }
+ }
+}
+
+#ifdef CONFIG_TCG
+#include "hw/core/tcg-cpu-ops.h"
+
+static struct TCGCPUOps loongarch_tcg_ops = {
+ .initialize = loongarch_translate_init,
+ .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
+};
+#endif /* CONFIG_TCG */
+
+static void loongarch_cpu_class_init(ObjectClass *c, void *data)
+{
+ LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
+ CPUClass *cc = CPU_CLASS(c);
+ DeviceClass *dc = DEVICE_CLASS(c);
+
+ device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
+ &lacc->parent_realize);
+ device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
+
+ cc->class_by_name = loongarch_cpu_class_by_name;
+ cc->dump_state = loongarch_cpu_dump_state;
+ cc->set_pc = loongarch_cpu_set_pc;
+ cc->disas_set_info = loongarch_cpu_disas_set_info;
+#ifdef CONFIG_TCG
+ cc->tcg_ops = &loongarch_tcg_ops;
+#endif
+}
+
+#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \
+ { \
+ .parent = TYPE_LOONGARCH_CPU, \
+ .instance_init = initfn, \
+ .name = LOONGARCH_CPU_TYPE_NAME(model), \
+ }
+
+static const TypeInfo loongarch_cpu_type_infos[] = {
+ {
+ .name = TYPE_LOONGARCH_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(LoongArchCPU),
+ .instance_init = loongarch_cpu_init,
+
+ .abstract = true,
+ .class_size = sizeof(LoongArchCPUClass),
+ .class_init = loongarch_cpu_class_init,
+ },
+ DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn),
+};
+
+DEFINE_TYPES(loongarch_cpu_type_infos)