1 | /* |
2 | * QEMU RISC-V CPU |
3 | * |
4 | * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu |
5 | * Copyright (c) 2017-2018 SiFive, Inc. |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify it |
8 | * under the terms and conditions of the GNU General Public License, |
9 | * version 2 or later, as published by the Free Software Foundation. |
10 | * |
11 | * This program is distributed in the hope it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. |
15 | * |
16 | * You should have received a copy of the GNU General Public License along with |
17 | * this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ |
19 | |
20 | #include "qemu/osdep.h" |
21 | #include "qemu/qemu-print.h" |
22 | #include "qemu/ctype.h" |
23 | #include "qemu/log.h" |
24 | #include "cpu.h" |
25 | #include "exec/exec-all.h" |
26 | #include "qapi/error.h" |
27 | #include "qemu/error-report.h" |
28 | #include "hw/qdev-properties.h" |
29 | #include "migration/vmstate.h" |
30 | #include "fpu/softfloat-helpers.h" |
31 | |
32 | /* RISC-V CPU definitions */ |
33 | |
34 | static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG" ; |
35 | |
36 | const char * const riscv_int_regnames[] = { |
37 | "zero" , "ra" , "sp" , "gp" , "tp" , "t0" , "t1" , "t2" , |
38 | "s0" , "s1" , "a0" , "a1" , "a2" , "a3" , "a4" , "a5" , |
39 | "a6" , "a7" , "s2" , "s3" , "s4" , "s5" , "s6" , "s7" , |
40 | "s8" , "s9" , "s10" , "s11" , "t3" , "t4" , "t5" , "t6" |
41 | }; |
42 | |
43 | const char * const riscv_fpr_regnames[] = { |
44 | "ft0" , "ft1" , "ft2" , "ft3" , "ft4" , "ft5" , "ft6" , "ft7" , |
45 | "fs0" , "fs1" , "fa0" , "fa1" , "fa2" , "fa3" , "fa4" , "fa5" , |
46 | "fa6" , "fa7" , "fs2" , "fs3" , "fs4" , "fs5" , "fs6" , "fs7" , |
47 | "fs8" , "fs9" , "fs10" , "fs11" , "ft8" , "ft9" , "ft10" , "ft11" |
48 | }; |
49 | |
50 | const char * const riscv_excp_names[] = { |
51 | "misaligned_fetch" , |
52 | "fault_fetch" , |
53 | "illegal_instruction" , |
54 | "breakpoint" , |
55 | "misaligned_load" , |
56 | "fault_load" , |
57 | "misaligned_store" , |
58 | "fault_store" , |
59 | "user_ecall" , |
60 | "supervisor_ecall" , |
61 | "hypervisor_ecall" , |
62 | "machine_ecall" , |
63 | "exec_page_fault" , |
64 | "load_page_fault" , |
65 | "reserved" , |
66 | "store_page_fault" |
67 | }; |
68 | |
69 | const char * const riscv_intr_names[] = { |
70 | "u_software" , |
71 | "s_software" , |
72 | "h_software" , |
73 | "m_software" , |
74 | "u_timer" , |
75 | "s_timer" , |
76 | "h_timer" , |
77 | "m_timer" , |
78 | "u_external" , |
79 | "s_external" , |
80 | "h_external" , |
81 | "m_external" , |
82 | "reserved" , |
83 | "reserved" , |
84 | "reserved" , |
85 | "reserved" |
86 | }; |
87 | |
88 | static void set_misa(CPURISCVState *env, target_ulong misa) |
89 | { |
90 | env->misa_mask = env->misa = misa; |
91 | } |
92 | |
93 | static void set_priv_version(CPURISCVState *env, int priv_ver) |
94 | { |
95 | env->priv_ver = priv_ver; |
96 | } |
97 | |
98 | static void set_feature(CPURISCVState *env, int feature) |
99 | { |
100 | env->features |= (1ULL << feature); |
101 | } |
102 | |
103 | static void set_resetvec(CPURISCVState *env, int resetvec) |
104 | { |
105 | #ifndef CONFIG_USER_ONLY |
106 | env->resetvec = resetvec; |
107 | #endif |
108 | } |
109 | |
110 | static void riscv_any_cpu_init(Object *obj) |
111 | { |
112 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
113 | set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU); |
114 | set_priv_version(env, PRIV_VERSION_1_11_0); |
115 | set_resetvec(env, DEFAULT_RSTVEC); |
116 | } |
117 | |
118 | #if defined(TARGET_RISCV32) |
119 | |
120 | static void riscv_base32_cpu_init(Object *obj) |
121 | { |
122 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
123 | /* We set this in the realise function */ |
124 | set_misa(env, 0); |
125 | } |
126 | |
127 | static void rv32gcsu_priv1_09_1_cpu_init(Object *obj) |
128 | { |
129 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
130 | set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); |
131 | set_priv_version(env, PRIV_VERSION_1_09_1); |
132 | set_resetvec(env, DEFAULT_RSTVEC); |
133 | set_feature(env, RISCV_FEATURE_MMU); |
134 | set_feature(env, RISCV_FEATURE_PMP); |
135 | } |
136 | |
137 | static void rv32gcsu_priv1_10_0_cpu_init(Object *obj) |
138 | { |
139 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
140 | set_misa(env, RV32 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); |
141 | set_priv_version(env, PRIV_VERSION_1_10_0); |
142 | set_resetvec(env, DEFAULT_RSTVEC); |
143 | set_feature(env, RISCV_FEATURE_MMU); |
144 | set_feature(env, RISCV_FEATURE_PMP); |
145 | } |
146 | |
147 | static void rv32imacu_nommu_cpu_init(Object *obj) |
148 | { |
149 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
150 | set_misa(env, RV32 | RVI | RVM | RVA | RVC | RVU); |
151 | set_priv_version(env, PRIV_VERSION_1_10_0); |
152 | set_resetvec(env, DEFAULT_RSTVEC); |
153 | set_feature(env, RISCV_FEATURE_PMP); |
154 | } |
155 | |
156 | #elif defined(TARGET_RISCV64) |
157 | |
158 | static void riscv_base64_cpu_init(Object *obj) |
159 | { |
160 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
161 | /* We set this in the realise function */ |
162 | set_misa(env, 0); |
163 | } |
164 | |
165 | static void rv64gcsu_priv1_09_1_cpu_init(Object *obj) |
166 | { |
167 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
168 | set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); |
169 | set_priv_version(env, PRIV_VERSION_1_09_1); |
170 | set_resetvec(env, DEFAULT_RSTVEC); |
171 | set_feature(env, RISCV_FEATURE_MMU); |
172 | set_feature(env, RISCV_FEATURE_PMP); |
173 | } |
174 | |
175 | static void rv64gcsu_priv1_10_0_cpu_init(Object *obj) |
176 | { |
177 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
178 | set_misa(env, RV64 | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); |
179 | set_priv_version(env, PRIV_VERSION_1_10_0); |
180 | set_resetvec(env, DEFAULT_RSTVEC); |
181 | set_feature(env, RISCV_FEATURE_MMU); |
182 | set_feature(env, RISCV_FEATURE_PMP); |
183 | } |
184 | |
185 | static void rv64imacu_nommu_cpu_init(Object *obj) |
186 | { |
187 | CPURISCVState *env = &RISCV_CPU(obj)->env; |
188 | set_misa(env, RV64 | RVI | RVM | RVA | RVC | RVU); |
189 | set_priv_version(env, PRIV_VERSION_1_10_0); |
190 | set_resetvec(env, DEFAULT_RSTVEC); |
191 | set_feature(env, RISCV_FEATURE_PMP); |
192 | } |
193 | |
194 | #endif |
195 | |
196 | static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) |
197 | { |
198 | ObjectClass *oc; |
199 | char *typename; |
200 | char **cpuname; |
201 | |
202 | cpuname = g_strsplit(cpu_model, "," , 1); |
203 | typename = g_strdup_printf(RISCV_CPU_TYPE_NAME("%s" ), cpuname[0]); |
204 | oc = object_class_by_name(typename); |
205 | g_strfreev(cpuname); |
206 | g_free(typename); |
207 | if (!oc || !object_class_dynamic_cast(oc, TYPE_RISCV_CPU) || |
208 | object_class_is_abstract(oc)) { |
209 | return NULL; |
210 | } |
211 | return oc; |
212 | } |
213 | |
214 | static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) |
215 | { |
216 | RISCVCPU *cpu = RISCV_CPU(cs); |
217 | CPURISCVState *env = &cpu->env; |
218 | int i; |
219 | |
220 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "pc " , env->pc); |
221 | #ifndef CONFIG_USER_ONLY |
222 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mhartid " , env->mhartid); |
223 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mstatus " , env->mstatus); |
224 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mip " , |
225 | (target_ulong)atomic_read(&env->mip)); |
226 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mie " , env->mie); |
227 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mideleg " , env->mideleg); |
228 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "medeleg " , env->medeleg); |
229 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mtvec " , env->mtvec); |
230 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mepc " , env->mepc); |
231 | qemu_fprintf(f, " %s " TARGET_FMT_lx "\n" , "mcause " , env->mcause); |
232 | #endif |
233 | |
234 | for (i = 0; i < 32; i++) { |
235 | qemu_fprintf(f, " %s " TARGET_FMT_lx, |
236 | riscv_int_regnames[i], env->gpr[i]); |
237 | if ((i & 3) == 3) { |
238 | qemu_fprintf(f, "\n" ); |
239 | } |
240 | } |
241 | if (flags & CPU_DUMP_FPU) { |
242 | for (i = 0; i < 32; i++) { |
243 | qemu_fprintf(f, " %s %016" PRIx64, |
244 | riscv_fpr_regnames[i], env->fpr[i]); |
245 | if ((i & 3) == 3) { |
246 | qemu_fprintf(f, "\n" ); |
247 | } |
248 | } |
249 | } |
250 | } |
251 | |
252 | static void riscv_cpu_set_pc(CPUState *cs, vaddr value) |
253 | { |
254 | RISCVCPU *cpu = RISCV_CPU(cs); |
255 | CPURISCVState *env = &cpu->env; |
256 | env->pc = value; |
257 | } |
258 | |
259 | static void riscv_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb) |
260 | { |
261 | RISCVCPU *cpu = RISCV_CPU(cs); |
262 | CPURISCVState *env = &cpu->env; |
263 | env->pc = tb->pc; |
264 | } |
265 | |
266 | static bool riscv_cpu_has_work(CPUState *cs) |
267 | { |
268 | #ifndef CONFIG_USER_ONLY |
269 | RISCVCPU *cpu = RISCV_CPU(cs); |
270 | CPURISCVState *env = &cpu->env; |
271 | /* |
272 | * Definition of the WFI instruction requires it to ignore the privilege |
273 | * mode and delegation registers, but respect individual enables |
274 | */ |
275 | return (atomic_read(&env->mip) & env->mie) != 0; |
276 | #else |
277 | return true; |
278 | #endif |
279 | } |
280 | |
281 | void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, |
282 | target_ulong *data) |
283 | { |
284 | env->pc = data[0]; |
285 | } |
286 | |
287 | static void riscv_cpu_reset(CPUState *cs) |
288 | { |
289 | RISCVCPU *cpu = RISCV_CPU(cs); |
290 | RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); |
291 | CPURISCVState *env = &cpu->env; |
292 | |
293 | mcc->parent_reset(cs); |
294 | #ifndef CONFIG_USER_ONLY |
295 | env->priv = PRV_M; |
296 | env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV); |
297 | env->mcause = 0; |
298 | env->pc = env->resetvec; |
299 | #endif |
300 | cs->exception_index = EXCP_NONE; |
301 | env->load_res = -1; |
302 | set_default_nan_mode(1, &env->fp_status); |
303 | } |
304 | |
305 | static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) |
306 | { |
307 | #if defined(TARGET_RISCV32) |
308 | info->print_insn = print_insn_riscv32; |
309 | #elif defined(TARGET_RISCV64) |
310 | info->print_insn = print_insn_riscv64; |
311 | #endif |
312 | } |
313 | |
314 | static void riscv_cpu_realize(DeviceState *dev, Error **errp) |
315 | { |
316 | CPUState *cs = CPU(dev); |
317 | RISCVCPU *cpu = RISCV_CPU(dev); |
318 | CPURISCVState *env = &cpu->env; |
319 | RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(dev); |
320 | int priv_version = PRIV_VERSION_1_11_0; |
321 | target_ulong target_misa = 0; |
322 | Error *local_err = NULL; |
323 | |
324 | cpu_exec_realizefn(cs, &local_err); |
325 | if (local_err != NULL) { |
326 | error_propagate(errp, local_err); |
327 | return; |
328 | } |
329 | |
330 | if (cpu->cfg.priv_spec) { |
331 | if (!g_strcmp0(cpu->cfg.priv_spec, "v1.11.0" )) { |
332 | priv_version = PRIV_VERSION_1_11_0; |
333 | } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.10.0" )) { |
334 | priv_version = PRIV_VERSION_1_10_0; |
335 | } else if (!g_strcmp0(cpu->cfg.priv_spec, "v1.9.1" )) { |
336 | priv_version = PRIV_VERSION_1_09_1; |
337 | } else { |
338 | error_setg(errp, |
339 | "Unsupported privilege spec version '%s'" , |
340 | cpu->cfg.priv_spec); |
341 | return; |
342 | } |
343 | } |
344 | |
345 | set_priv_version(env, priv_version); |
346 | set_resetvec(env, DEFAULT_RSTVEC); |
347 | |
348 | if (cpu->cfg.mmu) { |
349 | set_feature(env, RISCV_FEATURE_MMU); |
350 | } |
351 | |
352 | if (cpu->cfg.pmp) { |
353 | set_feature(env, RISCV_FEATURE_PMP); |
354 | } |
355 | |
356 | /* If misa isn't set (rv32 and rv64 machines) set it here */ |
357 | if (!env->misa) { |
358 | /* Do some ISA extension error checking */ |
359 | if (cpu->cfg.ext_i && cpu->cfg.ext_e) { |
360 | error_setg(errp, |
361 | "I and E extensions are incompatible" ); |
362 | return; |
363 | } |
364 | |
365 | if (!cpu->cfg.ext_i && !cpu->cfg.ext_e) { |
366 | error_setg(errp, |
367 | "Either I or E extension must be set" ); |
368 | return; |
369 | } |
370 | |
371 | if (cpu->cfg.ext_g && !(cpu->cfg.ext_i & cpu->cfg.ext_m & |
372 | cpu->cfg.ext_a & cpu->cfg.ext_f & |
373 | cpu->cfg.ext_d)) { |
374 | warn_report("Setting G will also set IMAFD" ); |
375 | cpu->cfg.ext_i = true; |
376 | cpu->cfg.ext_m = true; |
377 | cpu->cfg.ext_a = true; |
378 | cpu->cfg.ext_f = true; |
379 | cpu->cfg.ext_d = true; |
380 | } |
381 | |
382 | /* Set the ISA extensions, checks should have happened above */ |
383 | if (cpu->cfg.ext_i) { |
384 | target_misa |= RVI; |
385 | } |
386 | if (cpu->cfg.ext_e) { |
387 | target_misa |= RVE; |
388 | } |
389 | if (cpu->cfg.ext_m) { |
390 | target_misa |= RVM; |
391 | } |
392 | if (cpu->cfg.ext_a) { |
393 | target_misa |= RVA; |
394 | } |
395 | if (cpu->cfg.ext_f) { |
396 | target_misa |= RVF; |
397 | } |
398 | if (cpu->cfg.ext_d) { |
399 | target_misa |= RVD; |
400 | } |
401 | if (cpu->cfg.ext_c) { |
402 | target_misa |= RVC; |
403 | } |
404 | if (cpu->cfg.ext_s) { |
405 | target_misa |= RVS; |
406 | } |
407 | if (cpu->cfg.ext_u) { |
408 | target_misa |= RVU; |
409 | } |
410 | |
411 | set_misa(env, RVXLEN | target_misa); |
412 | } |
413 | |
414 | riscv_cpu_register_gdb_regs_for_features(cs); |
415 | |
416 | qemu_init_vcpu(cs); |
417 | cpu_reset(cs); |
418 | |
419 | mcc->parent_realize(dev, errp); |
420 | } |
421 | |
422 | static void riscv_cpu_init(Object *obj) |
423 | { |
424 | RISCVCPU *cpu = RISCV_CPU(obj); |
425 | |
426 | cpu_set_cpustate_pointers(cpu); |
427 | } |
428 | |
429 | static const VMStateDescription vmstate_riscv_cpu = { |
430 | .name = "cpu" , |
431 | .unmigratable = 1, |
432 | }; |
433 | |
434 | static Property riscv_cpu_properties[] = { |
435 | DEFINE_PROP_BOOL("i" , RISCVCPU, cfg.ext_i, true), |
436 | DEFINE_PROP_BOOL("e" , RISCVCPU, cfg.ext_e, false), |
437 | DEFINE_PROP_BOOL("g" , RISCVCPU, cfg.ext_g, true), |
438 | DEFINE_PROP_BOOL("m" , RISCVCPU, cfg.ext_m, true), |
439 | DEFINE_PROP_BOOL("a" , RISCVCPU, cfg.ext_a, true), |
440 | DEFINE_PROP_BOOL("f" , RISCVCPU, cfg.ext_f, true), |
441 | DEFINE_PROP_BOOL("d" , RISCVCPU, cfg.ext_d, true), |
442 | DEFINE_PROP_BOOL("c" , RISCVCPU, cfg.ext_c, true), |
443 | DEFINE_PROP_BOOL("s" , RISCVCPU, cfg.ext_s, true), |
444 | DEFINE_PROP_BOOL("u" , RISCVCPU, cfg.ext_u, true), |
445 | DEFINE_PROP_BOOL("Counters" , RISCVCPU, cfg.ext_counters, true), |
446 | DEFINE_PROP_BOOL("Zifencei" , RISCVCPU, cfg.ext_ifencei, true), |
447 | DEFINE_PROP_BOOL("Zicsr" , RISCVCPU, cfg.ext_icsr, true), |
448 | DEFINE_PROP_STRING("priv_spec" , RISCVCPU, cfg.priv_spec), |
449 | DEFINE_PROP_BOOL("mmu" , RISCVCPU, cfg.mmu, true), |
450 | DEFINE_PROP_BOOL("pmp" , RISCVCPU, cfg.pmp, true), |
451 | DEFINE_PROP_END_OF_LIST(), |
452 | }; |
453 | |
454 | static void riscv_cpu_class_init(ObjectClass *c, void *data) |
455 | { |
456 | RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); |
457 | CPUClass *cc = CPU_CLASS(c); |
458 | DeviceClass *dc = DEVICE_CLASS(c); |
459 | |
460 | device_class_set_parent_realize(dc, riscv_cpu_realize, |
461 | &mcc->parent_realize); |
462 | |
463 | mcc->parent_reset = cc->reset; |
464 | cc->reset = riscv_cpu_reset; |
465 | |
466 | cc->class_by_name = riscv_cpu_class_by_name; |
467 | cc->has_work = riscv_cpu_has_work; |
468 | cc->do_interrupt = riscv_cpu_do_interrupt; |
469 | cc->cpu_exec_interrupt = riscv_cpu_exec_interrupt; |
470 | cc->dump_state = riscv_cpu_dump_state; |
471 | cc->set_pc = riscv_cpu_set_pc; |
472 | cc->synchronize_from_tb = riscv_cpu_synchronize_from_tb; |
473 | cc->gdb_read_register = riscv_cpu_gdb_read_register; |
474 | cc->gdb_write_register = riscv_cpu_gdb_write_register; |
475 | cc->gdb_num_core_regs = 33; |
476 | #if defined(TARGET_RISCV32) |
477 | cc->gdb_core_xml_file = "riscv-32bit-cpu.xml" ; |
478 | #elif defined(TARGET_RISCV64) |
479 | cc->gdb_core_xml_file = "riscv-64bit-cpu.xml" ; |
480 | #endif |
481 | cc->gdb_stop_before_watchpoint = true; |
482 | cc->disas_set_info = riscv_cpu_disas_set_info; |
483 | #ifndef CONFIG_USER_ONLY |
484 | cc->do_unassigned_access = riscv_cpu_unassigned_access; |
485 | cc->do_unaligned_access = riscv_cpu_do_unaligned_access; |
486 | cc->get_phys_page_debug = riscv_cpu_get_phys_page_debug; |
487 | #endif |
488 | #ifdef CONFIG_TCG |
489 | cc->tcg_initialize = riscv_translate_init; |
490 | cc->tlb_fill = riscv_cpu_tlb_fill; |
491 | #endif |
492 | /* For now, mark unmigratable: */ |
493 | cc->vmsd = &vmstate_riscv_cpu; |
494 | dc->props = riscv_cpu_properties; |
495 | } |
496 | |
497 | char *riscv_isa_string(RISCVCPU *cpu) |
498 | { |
499 | int i; |
500 | const size_t maxlen = sizeof("rv128" ) + sizeof(riscv_exts) + 1; |
501 | char *isa_str = g_new(char, maxlen); |
502 | char *p = isa_str + snprintf(isa_str, maxlen, "rv%d" , TARGET_LONG_BITS); |
503 | for (i = 0; i < sizeof(riscv_exts); i++) { |
504 | if (cpu->env.misa & RV(riscv_exts[i])) { |
505 | *p++ = qemu_tolower(riscv_exts[i]); |
506 | } |
507 | } |
508 | *p = '\0'; |
509 | return isa_str; |
510 | } |
511 | |
512 | static gint riscv_cpu_list_compare(gconstpointer a, gconstpointer b) |
513 | { |
514 | ObjectClass *class_a = (ObjectClass *)a; |
515 | ObjectClass *class_b = (ObjectClass *)b; |
516 | const char *name_a, *name_b; |
517 | |
518 | name_a = object_class_get_name(class_a); |
519 | name_b = object_class_get_name(class_b); |
520 | return strcmp(name_a, name_b); |
521 | } |
522 | |
523 | static void riscv_cpu_list_entry(gpointer data, gpointer user_data) |
524 | { |
525 | const char *typename = object_class_get_name(OBJECT_CLASS(data)); |
526 | int len = strlen(typename) - strlen(RISCV_CPU_TYPE_SUFFIX); |
527 | |
528 | qemu_printf("%.*s\n" , len, typename); |
529 | } |
530 | |
531 | void riscv_cpu_list(void) |
532 | { |
533 | GSList *list; |
534 | |
535 | list = object_class_get_list(TYPE_RISCV_CPU, false); |
536 | list = g_slist_sort(list, riscv_cpu_list_compare); |
537 | g_slist_foreach(list, riscv_cpu_list_entry, NULL); |
538 | g_slist_free(list); |
539 | } |
540 | |
541 | #define DEFINE_CPU(type_name, initfn) \ |
542 | { \ |
543 | .name = type_name, \ |
544 | .parent = TYPE_RISCV_CPU, \ |
545 | .instance_init = initfn \ |
546 | } |
547 | |
548 | static const TypeInfo riscv_cpu_type_infos[] = { |
549 | { |
550 | .name = TYPE_RISCV_CPU, |
551 | .parent = TYPE_CPU, |
552 | .instance_size = sizeof(RISCVCPU), |
553 | .instance_init = riscv_cpu_init, |
554 | .abstract = true, |
555 | .class_size = sizeof(RISCVCPUClass), |
556 | .class_init = riscv_cpu_class_init, |
557 | }, |
558 | DEFINE_CPU(TYPE_RISCV_CPU_ANY, riscv_any_cpu_init), |
559 | #if defined(TARGET_RISCV32) |
560 | DEFINE_CPU(TYPE_RISCV_CPU_BASE32, riscv_base32_cpu_init), |
561 | DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E31, rv32imacu_nommu_cpu_init), |
562 | DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U34, rv32gcsu_priv1_10_0_cpu_init), |
563 | /* Depreacted */ |
564 | DEFINE_CPU(TYPE_RISCV_CPU_RV32IMACU_NOMMU, rv32imacu_nommu_cpu_init), |
565 | DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_09_1, rv32gcsu_priv1_09_1_cpu_init), |
566 | DEFINE_CPU(TYPE_RISCV_CPU_RV32GCSU_V1_10_0, rv32gcsu_priv1_10_0_cpu_init) |
567 | #elif defined(TARGET_RISCV64) |
568 | DEFINE_CPU(TYPE_RISCV_CPU_BASE64, riscv_base64_cpu_init), |
569 | DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_E51, rv64imacu_nommu_cpu_init), |
570 | DEFINE_CPU(TYPE_RISCV_CPU_SIFIVE_U54, rv64gcsu_priv1_10_0_cpu_init), |
571 | /* Deprecated */ |
572 | DEFINE_CPU(TYPE_RISCV_CPU_RV64IMACU_NOMMU, rv64imacu_nommu_cpu_init), |
573 | DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_09_1, rv64gcsu_priv1_09_1_cpu_init), |
574 | DEFINE_CPU(TYPE_RISCV_CPU_RV64GCSU_V1_10_0, rv64gcsu_priv1_10_0_cpu_init) |
575 | #endif |
576 | }; |
577 | |
578 | DEFINE_TYPES(riscv_cpu_type_infos) |
579 | |