]> git.proxmox.com Git - mirror_qemu.git/blame - target/loongarch/cpu.c
target/loongarch: Add system emulation introduction
[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
d578ca6c 199 restore_fp_status(env);
228021f0
SG
200 cs->exception_index = -1;
201}
202
203static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
204{
205 info->print_insn = print_insn_loongarch;
206}
207
208static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
209{
210 CPUState *cs = CPU(dev);
211 LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev);
212 Error *local_err = NULL;
213
214 cpu_exec_realizefn(cs, &local_err);
215 if (local_err != NULL) {
216 error_propagate(errp, local_err);
217 return;
218 }
219
220 cpu_reset(cs);
221 qemu_init_vcpu(cs);
222
223 lacc->parent_realize(dev, errp);
224}
225
226static void loongarch_cpu_init(Object *obj)
227{
228 LoongArchCPU *cpu = LOONGARCH_CPU(obj);
229
230 cpu_set_cpustate_pointers(cpu);
231}
232
233static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
234{
235 ObjectClass *oc;
236 char *typename;
237
238 typename = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model);
239 oc = object_class_by_name(typename);
240 g_free(typename);
241 return oc;
242}
243
244void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
245{
246 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
247 CPULoongArchState *env = &cpu->env;
248 int i;
249
250 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
251 qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0,
252 get_float_exception_flags(&env->fp_status));
253
254 /* gpr */
255 for (i = 0; i < 32; i++) {
256 if ((i & 3) == 0) {
257 qemu_fprintf(f, " GPR%02d:", i);
258 }
259 qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]);
260 if ((i & 3) == 3) {
261 qemu_fprintf(f, "\n");
262 }
263 }
264
265 /* fpr */
266 if (flags & CPU_DUMP_FPU) {
267 for (i = 0; i < 32; i++) {
268 qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i]);
269 if ((i & 3) == 3) {
270 qemu_fprintf(f, "\n");
271 }
272 }
273 }
274}
275
276#ifdef CONFIG_TCG
277#include "hw/core/tcg-cpu-ops.h"
278
279static struct TCGCPUOps loongarch_tcg_ops = {
280 .initialize = loongarch_translate_init,
281 .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
282};
283#endif /* CONFIG_TCG */
284
285static void loongarch_cpu_class_init(ObjectClass *c, void *data)
286{
287 LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
288 CPUClass *cc = CPU_CLASS(c);
289 DeviceClass *dc = DEVICE_CLASS(c);
290
291 device_class_set_parent_realize(dc, loongarch_cpu_realizefn,
292 &lacc->parent_realize);
293 device_class_set_parent_reset(dc, loongarch_cpu_reset, &lacc->parent_reset);
294
295 cc->class_by_name = loongarch_cpu_class_by_name;
296 cc->dump_state = loongarch_cpu_dump_state;
297 cc->set_pc = loongarch_cpu_set_pc;
298 cc->disas_set_info = loongarch_cpu_disas_set_info;
299#ifdef CONFIG_TCG
300 cc->tcg_ops = &loongarch_tcg_ops;
301#endif
302}
303
304#define DEFINE_LOONGARCH_CPU_TYPE(model, initfn) \
305 { \
306 .parent = TYPE_LOONGARCH_CPU, \
307 .instance_init = initfn, \
308 .name = LOONGARCH_CPU_TYPE_NAME(model), \
309 }
310
311static const TypeInfo loongarch_cpu_type_infos[] = {
312 {
313 .name = TYPE_LOONGARCH_CPU,
314 .parent = TYPE_CPU,
315 .instance_size = sizeof(LoongArchCPU),
316 .instance_init = loongarch_cpu_init,
317
318 .abstract = true,
319 .class_size = sizeof(LoongArchCPUClass),
320 .class_init = loongarch_cpu_class_init,
321 },
322 DEFINE_LOONGARCH_CPU_TYPE("la464", loongarch_la464_initfn),
323};
324
325DEFINE_TYPES(loongarch_cpu_type_infos)