]> git.proxmox.com Git - mirror_qemu.git/blame - target/loongarch/cpu.c
target/loongarch: Add core definition
[mirror_qemu.git] / target / loongarch / cpu.c
CommitLineData
228021f0
SG
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * QEMU LoongArch CPU
4 *
5 * Copyright (c) 2021 Loongson Technology Corporation Limited
6 */
7
8#include "qemu/osdep.h"
9#include "qemu/log.h"
10#include "qemu/qemu-print.h"
11#include "qapi/error.h"
12#include "qemu/module.h"
13#include "sysemu/qtest.h"
14#include "exec/exec-all.h"
15#include "qapi/qapi-commands-machine-target.h"
16#include "cpu.h"
17#include "internals.h"
18#include "fpu/softfloat-helpers.h"
19
20const char * const regnames[32] = {
21 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
22 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
23 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
24 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
25};
26
27const char * const fregnames[32] = {
28 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
29 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
30 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
31 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
32};
33
34static const char * const excp_names[] = {
35 [EXCCODE_INT] = "Interrupt",
36 [EXCCODE_PIL] = "Page invalid exception for load",
37 [EXCCODE_PIS] = "Page invalid exception for store",
38 [EXCCODE_PIF] = "Page invalid exception for fetch",
39 [EXCCODE_PME] = "Page modified exception",
40 [EXCCODE_PNR] = "Page Not Readable exception",
41 [EXCCODE_PNX] = "Page Not Executable exception",
42 [EXCCODE_PPI] = "Page Privilege error",
43 [EXCCODE_ADEF] = "Address error for instruction fetch",
44 [EXCCODE_ADEM] = "Address error for Memory access",
45 [EXCCODE_SYS] = "Syscall",
46 [EXCCODE_BRK] = "Break",
47 [EXCCODE_INE] = "Instruction Non-Existent",
48 [EXCCODE_IPE] = "Instruction privilege error",
49 [EXCCODE_FPE] = "Floating Point Exception",
50 [EXCCODE_DBP] = "Debug breakpoint",
51};
52
53const char *loongarch_exception_name(int32_t exception)
54{
55 assert(excp_names[exception]);
56 return excp_names[exception];
57}
58
59void G_NORETURN do_raise_exception(CPULoongArchState *env,
60 uint32_t exception,
61 uintptr_t pc)
62{
63 CPUState *cs = env_cpu(env);
64
65 qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
66 __func__,
67 exception,
68 loongarch_exception_name(exception));
69 cs->exception_index = exception;
70
71 cpu_loop_exit_restore(cs, pc);
72}
73
74static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
75{
76 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
77 CPULoongArchState *env = &cpu->env;
78
79 env->pc = value;
80}
81
82#ifdef CONFIG_TCG
83static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
84 const TranslationBlock *tb)
85{
86 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
87 CPULoongArchState *env = &cpu->env;
88
89 env->pc = tb->pc;
90}
91#endif /* CONFIG_TCG */
92
93static void loongarch_la464_initfn(Object *obj)
94{
95 LoongArchCPU *cpu = LOONGARCH_CPU(obj);
96 CPULoongArchState *env = &cpu->env;
97 int i;
98
99 for (i = 0; i < 21; i++) {
100 env->cpucfg[i] = 0x0;
101 }
102
103 env->cpucfg[0] = 0x14c010; /* PRID */
104
105 uint32_t data = 0;
106 data = FIELD_DP32(data, CPUCFG1, ARCH, 2);
107 data = FIELD_DP32(data, CPUCFG1, PGMMU, 1);
108 data = FIELD_DP32(data, CPUCFG1, IOCSR, 1);
109 data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f);
110 data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f);
111 data = FIELD_DP32(data, CPUCFG1, UAL, 1);
112 data = FIELD_DP32(data, CPUCFG1, RI, 1);
113 data = FIELD_DP32(data, CPUCFG1, EP, 1);
114 data = FIELD_DP32(data, CPUCFG1, RPLV, 1);
115 data = FIELD_DP32(data, CPUCFG1, HP, 1);
116 data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1);
117 env->cpucfg[1] = data;
118
119 data = 0;
120 data = FIELD_DP32(data, CPUCFG2, FP, 1);
121 data = FIELD_DP32(data, CPUCFG2, FP_SP, 1);
122 data = FIELD_DP32(data, CPUCFG2, FP_DP, 1);
123 data = FIELD_DP32(data, CPUCFG2, FP_VER, 1);
124 data = FIELD_DP32(data, CPUCFG2, LLFTP, 1);
125 data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
126 data = FIELD_DP32(data, CPUCFG2, LAM, 1);
127 env->cpucfg[2] = data;
128
129 env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */
130
131 data = 0;
132 data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1);
133 data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
134 env->cpucfg[5] = data;
135
136 data = 0;
137 data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
138 data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
139 data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1);
140 data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1);
141 data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1);
142 data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1);
143 data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1);
144 data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1);
145 env->cpucfg[16] = data;
146
147 data = 0;
148 data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3);
149 data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8);
150 data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6);
151 env->cpucfg[17] = data;
152
153 data = 0;
154 data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3);
155 data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8);
156 data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6);
157 env->cpucfg[18] = data;
158
159 data = 0;
160 data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15);
161 data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8);
162 data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6);
163 env->cpucfg[19] = data;
164
165 data = 0;
166 data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15);
167 data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14);
168 data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 6);
169 env->cpucfg[20] = data;
170}
171
172static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
173{
174 const char *typename = object_class_get_name(OBJECT_CLASS(data));
175
176 qemu_printf("%s\n", typename);
177}
178
179void loongarch_cpu_list(void)
180{
181 GSList *list;
182 list = object_class_get_list_sorted(TYPE_LOONGARCH_CPU, false);
183 g_slist_foreach(list, loongarch_cpu_list_entry, NULL);
184 g_slist_free(list);
185}
186
187static void loongarch_cpu_reset(DeviceState *dev)
188{
189 CPUState *cs = CPU(dev);
190 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
191 LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
192 CPULoongArchState *env = &cpu->env;
193
194 lacc->parent_reset(dev);
195
196 env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
197 env->fcsr0 = 0x0;
198
199 cs->exception_index = -1;
200}
201
202static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
203{
204 info->print_insn = print_insn_loongarch;
205}
206
207static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
208{
209 CPUState *cs = CPU(dev);
210 LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
211 Error *local_err = NULL;
212
213 cpu_exec_realizefn(cs, &local_err);
214 if (local_err != NULL) {
215 error_propagate(errp, local_err);
216 return;
217 }
218
219 cpu_reset(cs);
220 qemu_init_vcpu(cs);
221
222 lacc->parent_realize(dev, errp);
223}
224
225static void loongarch_cpu_init(Object *obj)
226{
227 LoongArchCPU *cpu = LOONGARCH_CPU(obj);
228
229 cpu_set_cpustate_pointers(cpu);
230}
231
232static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
233{
234 ObjectClass *oc;
235 char *typename;
236
237 typename = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model);
238 oc = object_class_by_name(typename);
239 g_free(typename);
240 return oc;
241}
242
243void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
244{
245 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
246 CPULoongArchState *env = &cpu->env;
247 int i;
248
249 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
250 qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0,
251 get_float_exception_flags(&env->fp_status));
252
253 /* gpr */
254 for (i = 0; i < 32; i++) {
255 if ((i & 3) == 0) {
256 qemu_fprintf(f, " GPR%02d:", i);
257 }
258 qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]);
259 if ((i & 3) == 3) {
260 qemu_fprintf(f, "\n");
261 }
262 }
263
264 /* fpr */
265 if (flags & CPU_DUMP_FPU) {
266 for (i = 0; i < 32; i++) {
267 qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]);
268 if ((i & 3) == 3) {
269 qemu_fprintf(f, "\n");
270 }
271 }
272 }
273}
274
275#ifdef CONFIG_TCG
276#include "hw/core/tcg-cpu-ops.h"
277
278static struct TCGCPUOps loongarch_tcg_ops = {
279 .initialize = loongarch_translate_init,
280 .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
281};
282#endif /* CONFIG_TCG */
283
284static void loongarch_cpu_class_init(ObjectClass *c, void *data)
285{
286 LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
287 CPUClass *cc = CPU_CLASS(c);
288 DeviceClass *dc = DEVICE_CLASS(c);
289
290 device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
291 &lacc->parent_realize);
292 device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
293
294 cc->class_by_name = loongarch_cpu_class_by_name;
295 cc->dump_state = loongarch_cpu_dump_state;
296 cc->set_pc = loongarch_cpu_set_pc;
297 cc->disas_set_info = loongarch_cpu_disas_set_info;
298#ifdef CONFIG_TCG
299 cc->tcg_ops = &loongarch_tcg_ops;
300#endif
301}
302
303#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \
304 { \
305 .parent = TYPE_LOONGARCH_CPU, \
306 .instance_init = initfn, \
307 .name = LOONGARCH_CPU_TYPE_NAME(model), \
308 }
309
310static const TypeInfo loongarch_cpu_type_infos[] = {
311 {
312 .name = TYPE_LOONGARCH_CPU,
313 .parent = TYPE_CPU,
314 .instance_size = sizeof(LoongArchCPU),
315 .instance_init = loongarch_cpu_init,
316
317 .abstract = true,
318 .class_size = sizeof(LoongArchCPUClass),
319 .class_init = loongarch_cpu_class_init,
320 },
321 DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn),
322};
323
324DEFINE_TYPES(loongarch_cpu_type_infos)