]>
Commit | Line | Data |
---|---|---|
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" | |
2d45085a | 14 | #include "sysemu/tcg.h" |
8dcbad51 TZ |
15 | #include "sysemu/kvm.h" |
16 | #include "kvm/kvm_loongarch.h" | |
228021f0 | 17 | #include "exec/exec-all.h" |
228021f0 SG |
18 | #include "cpu.h" |
19 | #include "internals.h" | |
20 | #include "fpu/softfloat-helpers.h" | |
398cecb9 | 21 | #include "cpu-csr.h" |
c0f6cd9f | 22 | #ifndef CONFIG_USER_ONLY |
f84a2aac | 23 | #include "sysemu/reset.h" |
c0f6cd9f | 24 | #endif |
008a3b16 | 25 | #include "vec.h" |
8dcbad51 TZ |
26 | #ifdef CONFIG_KVM |
27 | #include <linux/kvm.h> | |
28 | #endif | |
2d45085a TZ |
29 | #ifdef CONFIG_TCG |
30 | #include "exec/cpu_ldst.h" | |
31 | #include "tcg/tcg.h" | |
32 | #endif | |
228021f0 SG |
33 | |
34 | const char * const regnames[32] = { | |
35 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
36 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | |
37 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | |
38 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | |
39 | }; | |
40 | ||
41 | const char * const fregnames[32] = { | |
42 | "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", | |
43 | "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", | |
44 | "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", | |
45 | "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", | |
46 | }; | |
47 | ||
48 | static const char * const excp_names[] = { | |
49 | [EXCCODE_INT] = "Interrupt", | |
50 | [EXCCODE_PIL] = "Page invalid exception for load", | |
51 | [EXCCODE_PIS] = "Page invalid exception for store", | |
52 | [EXCCODE_PIF] = "Page invalid exception for fetch", | |
53 | [EXCCODE_PME] = "Page modified exception", | |
54 | [EXCCODE_PNR] = "Page Not Readable exception", | |
55 | [EXCCODE_PNX] = "Page Not Executable exception", | |
56 | [EXCCODE_PPI] = "Page Privilege error", | |
57 | [EXCCODE_ADEF] = "Address error for instruction fetch", | |
58 | [EXCCODE_ADEM] = "Address error for Memory access", | |
59 | [EXCCODE_SYS] = "Syscall", | |
60 | [EXCCODE_BRK] = "Break", | |
61 | [EXCCODE_INE] = "Instruction Non-Existent", | |
62 | [EXCCODE_IPE] = "Instruction privilege error", | |
2419978c | 63 | [EXCCODE_FPD] = "Floating Point Disabled", |
228021f0 SG |
64 | [EXCCODE_FPE] = "Floating Point Exception", |
65 | [EXCCODE_DBP] = "Debug breakpoint", | |
7fe7eea6 | 66 | [EXCCODE_BCE] = "Bound Check Exception", |
a3f3db5c | 67 | [EXCCODE_SXD] = "128 bit vector instructions Disable exception", |
b8f1bdf3 | 68 | [EXCCODE_ASXD] = "256 bit vector instructions Disable exception", |
228021f0 SG |
69 | }; |
70 | ||
71 | const char *loongarch_exception_name(int32_t exception) | |
72 | { | |
73 | assert(excp_names[exception]); | |
74 | return excp_names[exception]; | |
75 | } | |
76 | ||
77 | void G_NORETURN do_raise_exception(CPULoongArchState *env, | |
78 | uint32_t exception, | |
79 | uintptr_t pc) | |
80 | { | |
81 | CPUState *cs = env_cpu(env); | |
82 | ||
83 | qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n", | |
84 | __func__, | |
85 | exception, | |
86 | loongarch_exception_name(exception)); | |
87 | cs->exception_index = exception; | |
88 | ||
89 | cpu_loop_exit_restore(cs, pc); | |
90 | } | |
91 | ||
92 | static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) | |
93 | { | |
94 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
95 | CPULoongArchState *env = &cpu->env; | |
96 | ||
2f6478ff | 97 | set_pc(env, value); |
228021f0 SG |
98 | } |
99 | ||
e4fdf9df RH |
100 | static vaddr loongarch_cpu_get_pc(CPUState *cs) |
101 | { | |
102 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
103 | CPULoongArchState *env = &cpu->env; | |
104 | ||
105 | return env->pc; | |
106 | } | |
107 | ||
0093b9a5 | 108 | #ifndef CONFIG_USER_ONLY |
a8a506c3 XY |
109 | #include "hw/loongarch/virt.h" |
110 | ||
f757a2cd XY |
111 | void loongarch_cpu_set_irq(void *opaque, int irq, int level) |
112 | { | |
113 | LoongArchCPU *cpu = opaque; | |
114 | CPULoongArchState *env = &cpu->env; | |
115 | CPUState *cs = CPU(cpu); | |
116 | ||
117 | if (irq < 0 || irq >= N_IRQS) { | |
118 | return; | |
119 | } | |
120 | ||
8dcbad51 TZ |
121 | if (kvm_enabled()) { |
122 | kvm_loongarch_set_interrupt(cpu, irq, level); | |
123 | } else if (tcg_enabled()) { | |
2d45085a TZ |
124 | env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0); |
125 | if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) { | |
126 | cpu_interrupt(cs, CPU_INTERRUPT_HARD); | |
127 | } else { | |
128 | cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD); | |
129 | } | |
f757a2cd XY |
130 | } |
131 | } | |
132 | ||
133 | static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env) | |
134 | { | |
135 | bool ret = 0; | |
136 | ||
137 | ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) && | |
138 | !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST))); | |
139 | ||
140 | return ret; | |
141 | } | |
142 | ||
143 | /* Check if there is pending and not masked out interrupt */ | |
144 | static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env) | |
145 | { | |
146 | uint32_t pending; | |
147 | uint32_t status; | |
f757a2cd XY |
148 | |
149 | pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); | |
150 | status = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); | |
151 | ||
66997c42 | 152 | return (pending & status) != 0; |
f757a2cd | 153 | } |
2d45085a | 154 | #endif |
f757a2cd | 155 | |
2d45085a TZ |
156 | #ifdef CONFIG_TCG |
157 | #ifndef CONFIG_USER_ONLY | |
f757a2cd XY |
158 | static void loongarch_cpu_do_interrupt(CPUState *cs) |
159 | { | |
160 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
161 | CPULoongArchState *env = &cpu->env; | |
162 | bool update_badinstr = 1; | |
163 | int cause = -1; | |
164 | const char *name; | |
165 | bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR); | |
166 | uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS); | |
167 | ||
168 | if (cs->exception_index != EXCCODE_INT) { | |
169 | if (cs->exception_index < 0 || | |
e4ad16f4 | 170 | cs->exception_index >= ARRAY_SIZE(excp_names)) { |
f757a2cd XY |
171 | name = "unknown"; |
172 | } else { | |
173 | name = excp_names[cs->exception_index]; | |
174 | } | |
175 | ||
176 | qemu_log_mask(CPU_LOG_INT, | |
177 | "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx | |
178 | " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__, | |
179 | env->pc, env->CSR_ERA, env->CSR_TLBRERA, name); | |
180 | } | |
181 | ||
182 | switch (cs->exception_index) { | |
183 | case EXCCODE_DBP: | |
184 | env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1); | |
185 | env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC); | |
186 | goto set_DERA; | |
187 | set_DERA: | |
188 | env->CSR_DERA = env->pc; | |
189 | env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1); | |
2f6478ff | 190 | set_pc(env, env->CSR_EENTRY + 0x480); |
f757a2cd XY |
191 | break; |
192 | case EXCCODE_INT: | |
193 | if (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) { | |
194 | env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1); | |
195 | goto set_DERA; | |
196 | } | |
197 | QEMU_FALLTHROUGH; | |
198 | case EXCCODE_PIF: | |
8752b130 | 199 | case EXCCODE_ADEF: |
f757a2cd XY |
200 | cause = cs->exception_index; |
201 | update_badinstr = 0; | |
202 | break; | |
f757a2cd XY |
203 | case EXCCODE_SYS: |
204 | case EXCCODE_BRK: | |
7d552f0e SG |
205 | case EXCCODE_INE: |
206 | case EXCCODE_IPE: | |
2419978c | 207 | case EXCCODE_FPD: |
7d552f0e | 208 | case EXCCODE_FPE: |
a3f3db5c | 209 | case EXCCODE_SXD: |
b8f1bdf3 | 210 | case EXCCODE_ASXD: |
7d552f0e SG |
211 | env->CSR_BADV = env->pc; |
212 | QEMU_FALLTHROUGH; | |
2e2ca3c8 | 213 | case EXCCODE_BCE: |
7d552f0e | 214 | case EXCCODE_ADEM: |
f757a2cd XY |
215 | case EXCCODE_PIL: |
216 | case EXCCODE_PIS: | |
217 | case EXCCODE_PME: | |
218 | case EXCCODE_PNR: | |
219 | case EXCCODE_PNX: | |
220 | case EXCCODE_PPI: | |
f757a2cd XY |
221 | cause = cs->exception_index; |
222 | break; | |
223 | default: | |
e4ad16f4 XY |
224 | qemu_log("Error: exception(%d) has not been supported\n", |
225 | cs->exception_index); | |
f757a2cd XY |
226 | abort(); |
227 | } | |
228 | ||
229 | if (update_badinstr) { | |
230 | env->CSR_BADI = cpu_ldl_code(env, env->pc); | |
231 | } | |
232 | ||
233 | /* Save PLV and IE */ | |
234 | if (tlbfill) { | |
235 | env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV, | |
236 | FIELD_EX64(env->CSR_CRMD, | |
237 | CSR_CRMD, PLV)); | |
238 | env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE, | |
239 | FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)); | |
240 | /* set the DA mode */ | |
241 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); | |
242 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); | |
243 | env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, | |
244 | PC, (env->pc >> 2)); | |
245 | } else { | |
a6b129c8 SG |
246 | env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, |
247 | EXCODE_MCODE(cause)); | |
248 | env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ESUBCODE, | |
249 | EXCODE_SUBCODE(cause)); | |
f757a2cd XY |
250 | env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV, |
251 | FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV)); | |
252 | env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE, | |
253 | FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE)); | |
254 | env->CSR_ERA = env->pc; | |
255 | } | |
256 | ||
257 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); | |
258 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); | |
259 | ||
46233676 XY |
260 | if (vec_size) { |
261 | vec_size = (1 << vec_size) * 4; | |
262 | } | |
263 | ||
f757a2cd XY |
264 | if (cs->exception_index == EXCCODE_INT) { |
265 | /* Interrupt */ | |
266 | uint32_t vector = 0; | |
267 | uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS); | |
268 | pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE); | |
269 | ||
270 | /* Find the highest-priority interrupt. */ | |
271 | vector = 31 - clz32(pending); | |
2f6478ff JC |
272 | set_pc(env, env->CSR_EENTRY + \ |
273 | (EXCCODE_EXTERNAL_INT + vector) * vec_size); | |
f757a2cd XY |
274 | qemu_log_mask(CPU_LOG_INT, |
275 | "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx | |
276 | " cause %d\n" " A " TARGET_FMT_lx " D " | |
277 | TARGET_FMT_lx " vector = %d ExC " TARGET_FMT_lx "ExS" | |
278 | TARGET_FMT_lx "\n", | |
279 | __func__, env->pc, env->CSR_ERA, | |
280 | cause, env->CSR_BADV, env->CSR_DERA, vector, | |
281 | env->CSR_ECFG, env->CSR_ESTAT); | |
282 | } else { | |
283 | if (tlbfill) { | |
2f6478ff | 284 | set_pc(env, env->CSR_TLBRENTRY); |
f757a2cd | 285 | } else { |
2f6478ff | 286 | set_pc(env, env->CSR_EENTRY + EXCODE_MCODE(cause) * vec_size); |
f757a2cd XY |
287 | } |
288 | qemu_log_mask(CPU_LOG_INT, | |
289 | "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx | |
290 | " cause %d%s\n, ESTAT " TARGET_FMT_lx | |
291 | " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx | |
292 | "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu | |
293 | " cpu %d asid " TARGET_FMT_lx "\n", __func__, env->pc, | |
294 | tlbfill ? env->CSR_TLBRERA : env->CSR_ERA, | |
295 | cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT, | |
296 | env->CSR_ECFG, | |
297 | tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV, | |
298 | env->CSR_BADI, env->gpr[11], cs->cpu_index, | |
299 | env->CSR_ASID); | |
300 | } | |
301 | cs->exception_index = -1; | |
302 | } | |
303 | ||
304 | static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, | |
305 | vaddr addr, unsigned size, | |
306 | MMUAccessType access_type, | |
307 | int mmu_idx, MemTxAttrs attrs, | |
308 | MemTxResult response, | |
309 | uintptr_t retaddr) | |
310 | { | |
311 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
312 | CPULoongArchState *env = &cpu->env; | |
313 | ||
314 | if (access_type == MMU_INST_FETCH) { | |
315 | do_raise_exception(env, EXCCODE_ADEF, retaddr); | |
316 | } else { | |
317 | do_raise_exception(env, EXCCODE_ADEM, retaddr); | |
318 | } | |
319 | } | |
320 | ||
321 | static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | |
322 | { | |
323 | if (interrupt_request & CPU_INTERRUPT_HARD) { | |
324 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
325 | CPULoongArchState *env = &cpu->env; | |
326 | ||
327 | if (cpu_loongarch_hw_interrupts_enabled(env) && | |
328 | cpu_loongarch_hw_interrupts_pending(env)) { | |
329 | /* Raise it */ | |
330 | cs->exception_index = EXCCODE_INT; | |
331 | loongarch_cpu_do_interrupt(cs); | |
332 | return true; | |
333 | } | |
334 | } | |
335 | return false; | |
336 | } | |
0093b9a5 | 337 | #endif |
f757a2cd | 338 | |
228021f0 SG |
339 | static void loongarch_cpu_synchronize_from_tb(CPUState *cs, |
340 | const TranslationBlock *tb) | |
341 | { | |
342 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
343 | CPULoongArchState *env = &cpu->env; | |
344 | ||
e83cf1c1 | 345 | tcg_debug_assert(!(cs->tcg_cflags & CF_PCREL)); |
2f6478ff | 346 | set_pc(env, tb->pc); |
228021f0 | 347 | } |
ab27940f RH |
348 | |
349 | static void loongarch_restore_state_to_opc(CPUState *cs, | |
350 | const TranslationBlock *tb, | |
351 | const uint64_t *data) | |
352 | { | |
353 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
354 | CPULoongArchState *env = &cpu->env; | |
355 | ||
2f6478ff | 356 | set_pc(env, data[0]); |
ab27940f | 357 | } |
228021f0 SG |
358 | #endif /* CONFIG_TCG */ |
359 | ||
f757a2cd XY |
360 | static bool loongarch_cpu_has_work(CPUState *cs) |
361 | { | |
0093b9a5 SG |
362 | #ifdef CONFIG_USER_ONLY |
363 | return true; | |
364 | #else | |
f757a2cd XY |
365 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); |
366 | CPULoongArchState *env = &cpu->env; | |
367 | bool has_work = false; | |
368 | ||
369 | if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && | |
370 | cpu_loongarch_hw_interrupts_pending(env)) { | |
371 | has_work = true; | |
372 | } | |
373 | ||
374 | return has_work; | |
0093b9a5 | 375 | #endif |
f757a2cd XY |
376 | } |
377 | ||
228021f0 SG |
378 | static void loongarch_la464_initfn(Object *obj) |
379 | { | |
380 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
381 | CPULoongArchState *env = &cpu->env; | |
382 | int i; | |
383 | ||
384 | for (i = 0; i < 21; i++) { | |
385 | env->cpucfg[i] = 0x0; | |
386 | } | |
387 | ||
fda3f15b | 388 | cpu->dtb_compatible = "loongarch,Loongson-3A5000"; |
228021f0 SG |
389 | env->cpucfg[0] = 0x14c010; /* PRID */ |
390 | ||
391 | uint32_t data = 0; | |
392 | data = FIELD_DP32(data, CPUCFG1, ARCH, 2); | |
393 | data = FIELD_DP32(data, CPUCFG1, PGMMU, 1); | |
394 | data = FIELD_DP32(data, CPUCFG1, IOCSR, 1); | |
395 | data = FIELD_DP32(data, CPUCFG1, PALEN, 0x2f); | |
396 | data = FIELD_DP32(data, CPUCFG1, VALEN, 0x2f); | |
397 | data = FIELD_DP32(data, CPUCFG1, UAL, 1); | |
398 | data = FIELD_DP32(data, CPUCFG1, RI, 1); | |
399 | data = FIELD_DP32(data, CPUCFG1, EP, 1); | |
400 | data = FIELD_DP32(data, CPUCFG1, RPLV, 1); | |
401 | data = FIELD_DP32(data, CPUCFG1, HP, 1); | |
402 | data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); | |
403 | env->cpucfg[1] = data; | |
404 | ||
405 | data = 0; | |
406 | data = FIELD_DP32(data, CPUCFG2, FP, 1); | |
407 | data = FIELD_DP32(data, CPUCFG2, FP_SP, 1); | |
408 | data = FIELD_DP32(data, CPUCFG2, FP_DP, 1); | |
409 | data = FIELD_DP32(data, CPUCFG2, FP_VER, 1); | |
c6c2fec4 | 410 | data = FIELD_DP32(data, CPUCFG2, LSX, 1), |
2cd81e37 | 411 | data = FIELD_DP32(data, CPUCFG2, LASX, 1), |
228021f0 SG |
412 | data = FIELD_DP32(data, CPUCFG2, LLFTP, 1); |
413 | data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1); | |
0b360727 | 414 | data = FIELD_DP32(data, CPUCFG2, LSPW, 1); |
228021f0 SG |
415 | data = FIELD_DP32(data, CPUCFG2, LAM, 1); |
416 | env->cpucfg[2] = data; | |
417 | ||
418 | env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */ | |
419 | ||
420 | data = 0; | |
421 | data = FIELD_DP32(data, CPUCFG5, CC_MUL, 1); | |
422 | data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1); | |
423 | env->cpucfg[5] = data; | |
424 | ||
425 | data = 0; | |
426 | data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1); | |
427 | data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1); | |
428 | data = FIELD_DP32(data, CPUCFG16, L2_IUPRE, 1); | |
429 | data = FIELD_DP32(data, CPUCFG16, L2_IUUNIFY, 1); | |
430 | data = FIELD_DP32(data, CPUCFG16, L2_IUPRIV, 1); | |
431 | data = FIELD_DP32(data, CPUCFG16, L3_IUPRE, 1); | |
432 | data = FIELD_DP32(data, CPUCFG16, L3_IUUNIFY, 1); | |
433 | data = FIELD_DP32(data, CPUCFG16, L3_IUINCL, 1); | |
434 | env->cpucfg[16] = data; | |
435 | ||
436 | data = 0; | |
437 | data = FIELD_DP32(data, CPUCFG17, L1IU_WAYS, 3); | |
438 | data = FIELD_DP32(data, CPUCFG17, L1IU_SETS, 8); | |
439 | data = FIELD_DP32(data, CPUCFG17, L1IU_SIZE, 6); | |
440 | env->cpucfg[17] = data; | |
441 | ||
442 | data = 0; | |
443 | data = FIELD_DP32(data, CPUCFG18, L1D_WAYS, 3); | |
444 | data = FIELD_DP32(data, CPUCFG18, L1D_SETS, 8); | |
445 | data = FIELD_DP32(data, CPUCFG18, L1D_SIZE, 6); | |
446 | env->cpucfg[18] = data; | |
447 | ||
448 | data = 0; | |
449 | data = FIELD_DP32(data, CPUCFG19, L2IU_WAYS, 15); | |
450 | data = FIELD_DP32(data, CPUCFG19, L2IU_SETS, 8); | |
451 | data = FIELD_DP32(data, CPUCFG19, L2IU_SIZE, 6); | |
452 | env->cpucfg[19] = data; | |
453 | ||
454 | data = 0; | |
455 | data = FIELD_DP32(data, CPUCFG20, L3IU_WAYS, 15); | |
456 | data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14); | |
fa90456f | 457 | data = FIELD_DP32(data, CPUCFG20, L3IU_SIZE, 6); |
228021f0 | 458 | env->cpucfg[20] = data; |
398cecb9 XY |
459 | |
460 | env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa); | |
464136ce | 461 | loongarch_cpu_post_init(obj); |
228021f0 SG |
462 | } |
463 | ||
bb8710cf JC |
464 | static void loongarch_la132_initfn(Object *obj) |
465 | { | |
466 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
467 | CPULoongArchState *env = &cpu->env; | |
468 | ||
469 | int i; | |
470 | ||
471 | for (i = 0; i < 21; i++) { | |
472 | env->cpucfg[i] = 0x0; | |
473 | } | |
474 | ||
475 | cpu->dtb_compatible = "loongarch,Loongson-1C103"; | |
476 | env->cpucfg[0] = 0x148042; /* PRID */ | |
477 | ||
478 | uint32_t data = 0; | |
479 | data = FIELD_DP32(data, CPUCFG1, ARCH, 1); /* LA32 */ | |
480 | data = FIELD_DP32(data, CPUCFG1, PGMMU, 1); | |
481 | data = FIELD_DP32(data, CPUCFG1, IOCSR, 1); | |
482 | data = FIELD_DP32(data, CPUCFG1, PALEN, 0x1f); /* 32 bits */ | |
483 | data = FIELD_DP32(data, CPUCFG1, VALEN, 0x1f); /* 32 bits */ | |
484 | data = FIELD_DP32(data, CPUCFG1, UAL, 1); | |
485 | data = FIELD_DP32(data, CPUCFG1, RI, 0); | |
486 | data = FIELD_DP32(data, CPUCFG1, EP, 0); | |
487 | data = FIELD_DP32(data, CPUCFG1, RPLV, 0); | |
488 | data = FIELD_DP32(data, CPUCFG1, HP, 1); | |
489 | data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); | |
490 | env->cpucfg[1] = data; | |
491 | } | |
492 | ||
d6f07732 SG |
493 | static void loongarch_max_initfn(Object *obj) |
494 | { | |
495 | /* '-cpu max' for TCG: we use cpu la464. */ | |
496 | loongarch_la464_initfn(obj); | |
497 | } | |
498 | ||
f78b49ae | 499 | static void loongarch_cpu_reset_hold(Object *obj) |
228021f0 | 500 | { |
f78b49ae | 501 | CPUState *cs = CPU(obj); |
228021f0 SG |
502 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); |
503 | LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu); | |
504 | CPULoongArchState *env = &cpu->env; | |
505 | ||
f78b49ae PM |
506 | if (lacc->parent_phases.hold) { |
507 | lacc->parent_phases.hold(obj); | |
508 | } | |
228021f0 SG |
509 | |
510 | env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3; | |
511 | env->fcsr0 = 0x0; | |
512 | ||
398cecb9 XY |
513 | int n; |
514 | /* Set csr registers value after reset */ | |
515 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0); | |
516 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0); | |
517 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1); | |
518 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0); | |
519 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1); | |
520 | env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1); | |
521 | ||
522 | env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0); | |
523 | env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0); | |
524 | env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0); | |
525 | env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0); | |
526 | ||
527 | env->CSR_MISC = 0; | |
528 | ||
529 | env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0); | |
530 | env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0); | |
531 | ||
532 | env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2)); | |
533 | env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0); | |
62784656 | 534 | env->CSR_CPUID = cs->cpu_index; |
398cecb9 XY |
535 | env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0); |
536 | env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0); | |
537 | env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); | |
538 | env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0); | |
62784656 | 539 | env->CSR_TID = cs->cpu_index; |
398cecb9 XY |
540 | |
541 | env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2); | |
542 | env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63); | |
543 | env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7); | |
544 | env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8); | |
545 | ||
546 | for (n = 0; n < 4; n++) { | |
547 | env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0); | |
548 | env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0); | |
549 | env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0); | |
550 | env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0); | |
551 | } | |
552 | ||
0093b9a5 | 553 | #ifndef CONFIG_USER_ONLY |
f757a2cd | 554 | env->pc = 0x1c000000; |
3517fb72 | 555 | memset(env->tlb, 0, sizeof(env->tlb)); |
f8447436 TZ |
556 | if (kvm_enabled()) { |
557 | kvm_arch_reset_vcpu(env); | |
558 | } | |
0093b9a5 | 559 | #endif |
f757a2cd | 560 | |
2d45085a | 561 | #ifdef CONFIG_TCG |
d578ca6c | 562 | restore_fp_status(env); |
2d45085a | 563 | #endif |
228021f0 SG |
564 | cs->exception_index = -1; |
565 | } | |
566 | ||
567 | static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) | |
568 | { | |
569 | info->print_insn = print_insn_loongarch; | |
570 | } | |
571 | ||
572 | static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) | |
573 | { | |
574 | CPUState *cs = CPU(dev); | |
575 | LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(dev); | |
576 | Error *local_err = NULL; | |
577 | ||
578 | cpu_exec_realizefn(cs, &local_err); | |
579 | if (local_err != NULL) { | |
580 | error_propagate(errp, local_err); | |
581 | return; | |
582 | } | |
583 | ||
ca61e750 XY |
584 | loongarch_cpu_register_gdb_regs_for_features(cs); |
585 | ||
228021f0 SG |
586 | cpu_reset(cs); |
587 | qemu_init_vcpu(cs); | |
588 | ||
589 | lacc->parent_realize(dev, errp); | |
590 | } | |
591 | ||
464136ce SG |
592 | static bool loongarch_get_lsx(Object *obj, Error **errp) |
593 | { | |
594 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
595 | bool ret; | |
596 | ||
597 | if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) { | |
598 | ret = true; | |
599 | } else { | |
600 | ret = false; | |
601 | } | |
602 | return ret; | |
603 | } | |
604 | ||
605 | static void loongarch_set_lsx(Object *obj, bool value, Error **errp) | |
606 | { | |
607 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
608 | ||
609 | if (value) { | |
610 | cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1); | |
611 | } else { | |
612 | cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 0); | |
613 | cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0); | |
614 | } | |
615 | } | |
616 | ||
617 | static bool loongarch_get_lasx(Object *obj, Error **errp) | |
618 | { | |
619 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
620 | bool ret; | |
621 | ||
622 | if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) { | |
623 | ret = true; | |
624 | } else { | |
625 | ret = false; | |
626 | } | |
627 | return ret; | |
628 | } | |
629 | ||
630 | static void loongarch_set_lasx(Object *obj, bool value, Error **errp) | |
631 | { | |
632 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
633 | ||
634 | if (value) { | |
635 | if (!FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) { | |
636 | cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1); | |
637 | } | |
638 | cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 1); | |
639 | } else { | |
640 | cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0); | |
641 | } | |
642 | } | |
643 | ||
644 | void loongarch_cpu_post_init(Object *obj) | |
645 | { | |
646 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); | |
647 | ||
648 | if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) { | |
649 | object_property_add_bool(obj, "lsx", loongarch_get_lsx, | |
650 | loongarch_set_lsx); | |
651 | } | |
652 | if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) { | |
653 | object_property_add_bool(obj, "lasx", loongarch_get_lasx, | |
654 | loongarch_set_lasx); | |
655 | } | |
656 | } | |
657 | ||
228021f0 SG |
658 | static void loongarch_cpu_init(Object *obj) |
659 | { | |
0093b9a5 | 660 | #ifndef CONFIG_USER_ONLY |
8fa08d7e | 661 | LoongArchCPU *cpu = LOONGARCH_CPU(obj); |
8fa08d7e | 662 | |
f757a2cd | 663 | qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS); |
2d45085a | 664 | #ifdef CONFIG_TCG |
dd615fa4 XY |
665 | timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL, |
666 | &loongarch_constant_timer_cb, cpu); | |
2d45085a | 667 | #endif |
0093b9a5 | 668 | #endif |
228021f0 SG |
669 | } |
670 | ||
671 | static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) | |
672 | { | |
673 | ObjectClass *oc; | |
228021f0 | 674 | |
c254f7af XY |
675 | oc = object_class_by_name(cpu_model); |
676 | if (!oc) { | |
e83cf1c1 | 677 | g_autofree char *typename |
c254f7af XY |
678 | = g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); |
679 | oc = object_class_by_name(typename); | |
c254f7af XY |
680 | } |
681 | ||
d5be19f5 | 682 | return oc; |
228021f0 SG |
683 | } |
684 | ||
685 | void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) | |
686 | { | |
687 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
688 | CPULoongArchState *env = &cpu->env; | |
689 | int i; | |
690 | ||
691 | qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc); | |
692 | qemu_fprintf(f, " FCSR0 0x%08x fp_status 0x%02x\n", env->fcsr0, | |
693 | get_float_exception_flags(&env->fp_status)); | |
694 | ||
695 | /* gpr */ | |
696 | for (i = 0; i < 32; i++) { | |
697 | if ((i & 3) == 0) { | |
698 | qemu_fprintf(f, " GPR%02d:", i); | |
699 | } | |
700 | qemu_fprintf(f, " %s %016" PRIx64, regnames[i], env->gpr[i]); | |
701 | if ((i & 3) == 3) { | |
702 | qemu_fprintf(f, "\n"); | |
703 | } | |
704 | } | |
705 | ||
7e1c521e XY |
706 | qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD); |
707 | qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD); | |
708 | qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN); | |
709 | qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT); | |
710 | qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA); | |
711 | qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV); | |
712 | qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI); | |
713 | qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY); | |
714 | qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 "," | |
715 | " PRCFG3=%016" PRIx64 "\n", | |
716 | env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); | |
717 | qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY); | |
718 | qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV); | |
719 | qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA); | |
be45144b BM |
720 | qemu_fprintf(f, "TCFG=%016" PRIx64 "\n", env->CSR_TCFG); |
721 | qemu_fprintf(f, "TVAL=%016" PRIx64 "\n", env->CSR_TVAL); | |
7e1c521e | 722 | |
228021f0 SG |
723 | /* fpr */ |
724 | if (flags & CPU_DUMP_FPU) { | |
725 | for (i = 0; i < 32; i++) { | |
16f5396c | 726 | qemu_fprintf(f, " %s %016" PRIx64, fregnames[i], env->fpr[i].vreg.D(0)); |
228021f0 SG |
727 | if ((i & 3) == 3) { |
728 | qemu_fprintf(f, "\n"); | |
729 | } | |
730 | } | |
731 | } | |
732 | } | |
733 | ||
734 | #ifdef CONFIG_TCG | |
735 | #include "hw/core/tcg-cpu-ops.h" | |
736 | ||
2889fb8b | 737 | static const TCGCPUOps loongarch_tcg_ops = { |
228021f0 SG |
738 | .initialize = loongarch_translate_init, |
739 | .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, | |
ab27940f | 740 | .restore_state_to_opc = loongarch_restore_state_to_opc, |
7e1c521e | 741 | |
0093b9a5 | 742 | #ifndef CONFIG_USER_ONLY |
7e1c521e | 743 | .tlb_fill = loongarch_cpu_tlb_fill, |
f757a2cd XY |
744 | .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, |
745 | .do_interrupt = loongarch_cpu_do_interrupt, | |
746 | .do_transaction_failed = loongarch_cpu_do_transaction_failed, | |
0093b9a5 | 747 | #endif |
228021f0 SG |
748 | }; |
749 | #endif /* CONFIG_TCG */ | |
750 | ||
0093b9a5 | 751 | #ifndef CONFIG_USER_ONLY |
7e1c521e XY |
752 | #include "hw/core/sysemu-cpu-ops.h" |
753 | ||
754 | static const struct SysemuCPUOps loongarch_sysemu_ops = { | |
755 | .get_phys_page_debug = loongarch_cpu_get_phys_page_debug, | |
756 | }; | |
14f21f67 BM |
757 | |
758 | static int64_t loongarch_cpu_get_arch_id(CPUState *cs) | |
759 | { | |
760 | LoongArchCPU *cpu = LOONGARCH_CPU(cs); | |
761 | ||
762 | return cpu->phy_id; | |
763 | } | |
0093b9a5 | 764 | #endif |
7e1c521e | 765 | |
228021f0 SG |
766 | static void loongarch_cpu_class_init(ObjectClass *c, void *data) |
767 | { | |
768 | LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); | |
769 | CPUClass *cc = CPU_CLASS(c); | |
770 | DeviceClass *dc = DEVICE_CLASS(c); | |
f78b49ae | 771 | ResettableClass *rc = RESETTABLE_CLASS(c); |
228021f0 SG |
772 | |
773 | device_class_set_parent_realize(dc, loongarch_cpu_realizefn, | |
774 | &lacc->parent_realize); | |
f78b49ae PM |
775 | resettable_class_set_parent_phases(rc, NULL, loongarch_cpu_reset_hold, NULL, |
776 | &lacc->parent_phases); | |
228021f0 SG |
777 | |
778 | cc->class_by_name = loongarch_cpu_class_by_name; | |
f757a2cd | 779 | cc->has_work = loongarch_cpu_has_work; |
228021f0 SG |
780 | cc->dump_state = loongarch_cpu_dump_state; |
781 | cc->set_pc = loongarch_cpu_set_pc; | |
e4fdf9df | 782 | cc->get_pc = loongarch_cpu_get_pc; |
0093b9a5 | 783 | #ifndef CONFIG_USER_ONLY |
14f21f67 | 784 | cc->get_arch_id = loongarch_cpu_get_arch_id; |
67ebd42a | 785 | dc->vmsd = &vmstate_loongarch_cpu; |
7e1c521e | 786 | cc->sysemu_ops = &loongarch_sysemu_ops; |
0093b9a5 | 787 | #endif |
228021f0 | 788 | cc->disas_set_info = loongarch_cpu_disas_set_info; |
ca61e750 XY |
789 | cc->gdb_read_register = loongarch_cpu_gdb_read_register; |
790 | cc->gdb_write_register = loongarch_cpu_gdb_write_register; | |
ca61e750 XY |
791 | cc->gdb_stop_before_watchpoint = true; |
792 | ||
228021f0 SG |
793 | #ifdef CONFIG_TCG |
794 | cc->tcg_ops = &loongarch_tcg_ops; | |
795 | #endif | |
796 | } | |
797 | ||
a6506838 | 798 | static const gchar *loongarch32_gdb_arch_name(CPUState *cs) |
ebda3036 | 799 | { |
a6506838 | 800 | return "loongarch32"; |
ebda3036 JC |
801 | } |
802 | ||
6cbba3e9 JC |
803 | static void loongarch32_cpu_class_init(ObjectClass *c, void *data) |
804 | { | |
ebda3036 JC |
805 | CPUClass *cc = CPU_CLASS(c); |
806 | ||
807 | cc->gdb_num_core_regs = 35; | |
808 | cc->gdb_core_xml_file = "loongarch-base32.xml"; | |
809 | cc->gdb_arch_name = loongarch32_gdb_arch_name; | |
6cbba3e9 JC |
810 | } |
811 | ||
a6506838 | 812 | static const gchar *loongarch64_gdb_arch_name(CPUState *cs) |
e389358e | 813 | { |
a6506838 | 814 | return "loongarch64"; |
e389358e PMD |
815 | } |
816 | ||
817 | static void loongarch64_cpu_class_init(ObjectClass *c, void *data) | |
818 | { | |
819 | CPUClass *cc = CPU_CLASS(c); | |
820 | ||
821 | cc->gdb_num_core_regs = 35; | |
822 | cc->gdb_core_xml_file = "loongarch-base64.xml"; | |
823 | cc->gdb_arch_name = loongarch64_gdb_arch_name; | |
824 | } | |
825 | ||
146f2354 | 826 | #define DEFINE_LOONGARCH_CPU_TYPE(size, model, initfn) \ |
228021f0 | 827 | { \ |
146f2354 | 828 | .parent = TYPE_LOONGARCH##size##_CPU, \ |
228021f0 SG |
829 | .instance_init = initfn, \ |
830 | .name = LOONGARCH_CPU_TYPE_NAME(model), \ | |
831 | } | |
832 | ||
833 | static const TypeInfo loongarch_cpu_type_infos[] = { | |
834 | { | |
835 | .name = TYPE_LOONGARCH_CPU, | |
836 | .parent = TYPE_CPU, | |
837 | .instance_size = sizeof(LoongArchCPU), | |
f669c992 | 838 | .instance_align = __alignof(LoongArchCPU), |
228021f0 SG |
839 | .instance_init = loongarch_cpu_init, |
840 | ||
841 | .abstract = true, | |
842 | .class_size = sizeof(LoongArchCPUClass), | |
843 | .class_init = loongarch_cpu_class_init, | |
844 | }, | |
6cbba3e9 JC |
845 | { |
846 | .name = TYPE_LOONGARCH32_CPU, | |
847 | .parent = TYPE_LOONGARCH_CPU, | |
848 | ||
849 | .abstract = true, | |
850 | .class_init = loongarch32_cpu_class_init, | |
851 | }, | |
146f2354 PMD |
852 | { |
853 | .name = TYPE_LOONGARCH64_CPU, | |
854 | .parent = TYPE_LOONGARCH_CPU, | |
855 | ||
856 | .abstract = true, | |
e389358e | 857 | .class_init = loongarch64_cpu_class_init, |
146f2354 PMD |
858 | }, |
859 | DEFINE_LOONGARCH_CPU_TYPE(64, "la464", loongarch_la464_initfn), | |
bb8710cf | 860 | DEFINE_LOONGARCH_CPU_TYPE(32, "la132", loongarch_la132_initfn), |
d6f07732 | 861 | DEFINE_LOONGARCH_CPU_TYPE(64, "max", loongarch_max_initfn), |
228021f0 SG |
862 | }; |
863 | ||
864 | DEFINE_TYPES(loongarch_cpu_type_infos) |