]> git.proxmox.com Git - mirror_qemu.git/blame - target/mips/cpu.c
Replace TARGET_WORDS_BIGENDIAN
[mirror_qemu.git] / target / mips / cpu.c
CommitLineData
0f71a709
AF
1/*
2 * QEMU MIPS CPU
3 *
4 * Copyright (c) 2012 SUSE LINUX Products GmbH
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/lgpl-2.1.html>
19 */
20
c684822a 21#include "qemu/osdep.h"
8a6359f9 22#include "qemu/cutils.h"
c20cf02b 23#include "qemu/qemu-print.h"
da34e65c 24#include "qapi/error.h"
0f71a709 25#include "cpu.h"
26aa3d9a 26#include "internal.h"
14c03ab9 27#include "kvm_mips.h"
0b8fa32f 28#include "qemu/module.h"
14c03ab9 29#include "sysemu/kvm.h"
8a6359f9 30#include "sysemu/qtest.h"
63c91552 31#include "exec/exec-all.h"
d0bec217 32#include "hw/qdev-properties.h"
a0713e85 33#include "hw/qdev-clock.h"
6b5fe137 34#include "semihosting/semihost.h"
a10b453a 35#include "qapi/qapi-commands-machine-target.h"
03e4d95c 36#include "fpu_helper.h"
0f71a709 37
06106772 38const char regnames[32][3] = {
adbf1be3
PMD
39 "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
40 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
41 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
42 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
43};
44
4d169b9c
PMD
45static void fpu_dump_fpr(fpr_t *fpr, FILE *f, bool is_fpu64)
46{
47 if (is_fpu64) {
48 qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu: %13g\n",
49 fpr->w[FP_ENDIAN_IDX], fpr->d,
50 (double)fpr->fd,
51 (double)fpr->fs[FP_ENDIAN_IDX],
52 (double)fpr->fs[!FP_ENDIAN_IDX]);
53 } else {
54 fpr_t tmp;
55
56 tmp.w[FP_ENDIAN_IDX] = fpr->w[FP_ENDIAN_IDX];
57 tmp.w[!FP_ENDIAN_IDX] = (fpr + 1)->w[FP_ENDIAN_IDX];
58 qemu_fprintf(f, "w:%08x d:%016" PRIx64 " fd:%13g fs:%13g psu:%13g\n",
59 tmp.w[FP_ENDIAN_IDX], tmp.d,
60 (double)tmp.fd,
61 (double)tmp.fs[FP_ENDIAN_IDX],
62 (double)tmp.fs[!FP_ENDIAN_IDX]);
63 }
64}
65
4f14ce4b
PMD
66static void fpu_dump_state(CPUMIPSState *env, FILE *f, int flags)
67{
68 int i;
4d169b9c 69 bool is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
4f14ce4b
PMD
70
71 qemu_fprintf(f,
72 "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%02x\n",
73 env->active_fpu.fcr0, env->active_fpu.fcr31, is_fpu64,
74 get_float_exception_flags(&env->active_fpu.fp_status));
75 for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
76 qemu_fprintf(f, "%3s: ", fregnames[i]);
4d169b9c 77 fpu_dump_fpr(&env->active_fpu.fpr[i], f, is_fpu64);
4f14ce4b 78 }
4f14ce4b
PMD
79}
80
81static void mips_cpu_dump_state(CPUState *cs, FILE *f, int flags)
82{
83 MIPSCPU *cpu = MIPS_CPU(cs);
84 CPUMIPSState *env = &cpu->env;
85 int i;
86
87 qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx
88 " LO=0x" TARGET_FMT_lx " ds %04x "
89 TARGET_FMT_lx " " TARGET_FMT_ld "\n",
90 env->active_tc.PC, env->active_tc.HI[0], env->active_tc.LO[0],
91 env->hflags, env->btarget, env->bcond);
92 for (i = 0; i < 32; i++) {
93 if ((i & 3) == 0) {
94 qemu_fprintf(f, "GPR%02d:", i);
95 }
96 qemu_fprintf(f, " %s " TARGET_FMT_lx,
97 regnames[i], env->active_tc.gpr[i]);
98 if ((i & 3) == 3) {
99 qemu_fprintf(f, "\n");
100 }
101 }
102
103 qemu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x"
104 TARGET_FMT_lx "\n",
105 env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
106 qemu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%016"
107 PRIx64 "\n",
108 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
109 qemu_fprintf(f, " Config2 0x%08x Config3 0x%08x\n",
110 env->CP0_Config2, env->CP0_Config3);
111 qemu_fprintf(f, " Config4 0x%08x Config5 0x%08x\n",
112 env->CP0_Config4, env->CP0_Config5);
113 if ((flags & CPU_DUMP_FPU) && (env->hflags & MIPS_HFLAG_FPU)) {
114 fpu_dump_state(env, f, flags);
115 }
116}
117
e9927723
PMD
118void cpu_set_exception_base(int vp_index, target_ulong address)
119{
120 MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
121 vp->env.exception_base = address;
122}
123
f45748f1
AF
124static void mips_cpu_set_pc(CPUState *cs, vaddr value)
125{
126 MIPSCPU *cpu = MIPS_CPU(cs);
f45748f1 127
533fc64f 128 mips_env_set_pc(&cpu->env, value);
f45748f1
AF
129}
130
8c2e1b00
AF
131static bool mips_cpu_has_work(CPUState *cs)
132{
133 MIPSCPU *cpu = MIPS_CPU(cs);
134 CPUMIPSState *env = &cpu->env;
135 bool has_work = false;
136
cf02a116
AM
137 /*
138 * Prior to MIPS Release 6 it is implementation dependent if non-enabled
139 * interrupts wake-up the CPU, however most of the implementations only
140 * check for interrupts that can be taken.
141 */
8c2e1b00
AF
142 if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
143 cpu_mips_hw_interrupts_pending(env)) {
7540a43a 144 if (cpu_mips_hw_interrupts_enabled(env) ||
2e211e0a 145 (env->insn_flags & ISA_MIPS_R6)) {
71ca034a
LA
146 has_work = true;
147 }
8c2e1b00
AF
148 }
149
150 /* MIPS-MT has the ability to halt the CPU. */
17c2c320 151 if (ase_mt_available(env)) {
cf02a116
AM
152 /*
153 * The QEMU model will issue an _WAKE request whenever the CPUs
154 * should be woken up.
155 */
8c2e1b00
AF
156 if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
157 has_work = true;
158 }
159
160 if (!mips_vpe_active(env)) {
161 has_work = false;
162 }
163 }
01bc435b
YK
164 /* MIPS Release 6 has the ability to halt the CPU. */
165 if (env->CP0_Config5 & (1 << CP0C5_VP)) {
166 if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
167 has_work = true;
168 }
169 if (!mips_vp_active(env)) {
170 has_work = false;
171 }
172 }
8c2e1b00
AF
173 return has_work;
174}
175
0dc351ca 176#include "cpu-defs.c.inc"
c20cf02b 177
9bcd41d4 178static void mips_cpu_reset(DeviceState *dev)
c20cf02b 179{
9bcd41d4
PMD
180 CPUState *cs = CPU(dev);
181 MIPSCPU *cpu = MIPS_CPU(cs);
182 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu);
183 CPUMIPSState *env = &cpu->env;
184
185 mcc->parent_reset(dev);
186
187 memset(env, 0, offsetof(CPUMIPSState, end_reset_fields));
c20cf02b
PMD
188
189 /* Reset registers to their default values */
190 env->CP0_PRid = env->cpu_model->CP0_PRid;
191 env->CP0_Config0 = env->cpu_model->CP0_Config0;
ee3eb3a7 192#if TARGET_BIG_ENDIAN
c20cf02b
PMD
193 env->CP0_Config0 |= (1 << CP0C0_BE);
194#endif
195 env->CP0_Config1 = env->cpu_model->CP0_Config1;
196 env->CP0_Config2 = env->cpu_model->CP0_Config2;
197 env->CP0_Config3 = env->cpu_model->CP0_Config3;
198 env->CP0_Config4 = env->cpu_model->CP0_Config4;
199 env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask;
200 env->CP0_Config5 = env->cpu_model->CP0_Config5;
201 env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
202 env->CP0_Config6 = env->cpu_model->CP0_Config6;
203 env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
204 env->CP0_Config7 = env->cpu_model->CP0_Config7;
205 env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
206 env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
207 << env->cpu_model->CP0_LLAddr_shift;
208 env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
209 env->SYNCI_Step = env->cpu_model->SYNCI_Step;
210 env->CCRes = env->cpu_model->CCRes;
211 env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
212 env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
213 env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
214 env->current_tc = 0;
215 env->SEGBITS = env->cpu_model->SEGBITS;
216 env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
217#if defined(TARGET_MIPS64)
218 if (env->cpu_model->insn_flags & ISA_MIPS3) {
219 env->SEGMask |= 3ULL << 62;
220 }
221#endif
222 env->PABITS = env->cpu_model->PABITS;
223 env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
224 env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
225 env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
226 env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
227 env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
228 env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
229 env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
230 env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
231 env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
232 env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
233 env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
234 env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
235 env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
236 env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
237 env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
238 env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
239 env->msair = env->cpu_model->MSAIR;
240 env->insn_flags = env->cpu_model->insn_flags;
241
242#if defined(CONFIG_USER_ONLY)
243 env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
244# ifdef TARGET_MIPS64
245 /* Enable 64-bit register mode. */
246 env->CP0_Status |= (1 << CP0St_PX);
247# endif
248# ifdef TARGET_ABI_MIPSN64
249 /* Enable 64-bit address mode. */
250 env->CP0_Status |= (1 << CP0St_UX);
251# endif
252 /*
253 * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
254 * hardware registers.
255 */
256 env->CP0_HWREna |= 0x0000000F;
257 if (env->CP0_Config1 & (1 << CP0C1_FP)) {
258 env->CP0_Status |= (1 << CP0St_CU1);
259 }
260 if (env->CP0_Config3 & (1 << CP0C3_DSPP)) {
261 env->CP0_Status |= (1 << CP0St_MX);
262 }
263# if defined(TARGET_MIPS64)
264 /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */
265 if ((env->CP0_Config1 & (1 << CP0C1_FP)) &&
266 (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
267 env->CP0_Status |= (1 << CP0St_FR);
268 }
269# endif
270#else /* !CONFIG_USER_ONLY */
271 if (env->hflags & MIPS_HFLAG_BMASK) {
272 /*
273 * If the exception was raised from a delay slot,
274 * come back to the jump.
275 */
276 env->CP0_ErrorEPC = (env->active_tc.PC
277 - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4));
278 } else {
279 env->CP0_ErrorEPC = env->active_tc.PC;
280 }
281 env->active_tc.PC = env->exception_base;
282 env->CP0_Random = env->tlb->nb_tlb - 1;
283 env->tlb->tlb_in_use = env->tlb->nb_tlb;
284 env->CP0_Wired = 0;
285 env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
286 env->CP0_EBase = (cs->cpu_index & 0x3FF);
287 if (mips_um_ksegs_enabled()) {
288 env->CP0_EBase |= 0x40000000;
289 } else {
290 env->CP0_EBase |= (int32_t)0x80000000;
291 }
292 if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) {
293 env->CP0_CMGCRBase = 0x1fbf8000 >> 4;
294 }
295 env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
296 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
297 env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
298 /*
299 * Vectored interrupts not implemented, timer on int 7,
300 * no performance counters.
301 */
302 env->CP0_IntCtl = 0xe0000000;
303 {
304 int i;
305
306 for (i = 0; i < 7; i++) {
307 env->CP0_WatchLo[i] = 0;
308 env->CP0_WatchHi[i] = 0x80000000;
309 }
310 env->CP0_WatchLo[7] = 0;
311 env->CP0_WatchHi[7] = 0;
312 }
313 /* Count register increments in debug mode, EJTAG version 1 */
314 env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
315
316 cpu_mips_store_count(env, 1);
317
318 if (ase_mt_available(env)) {
319 int i;
320
321 /* Only TC0 on VPE 0 starts as active. */
322 for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
323 env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE;
324 env->tcs[i].CP0_TCHalt = 1;
325 }
326 env->active_tc.CP0_TCHalt = 1;
327 cs->halted = 1;
328
329 if (cs->cpu_index == 0) {
330 /* VPE0 starts up enabled. */
331 env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
332 env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
333
334 /* TC0 starts up unhalted. */
335 cs->halted = 0;
336 env->active_tc.CP0_TCHalt = 0;
337 env->tcs[0].CP0_TCHalt = 0;
338 /* With thread 0 active. */
339 env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
340 env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
341 }
342 }
343
344 /*
345 * Configure default legacy segmentation control. We use this regardless of
346 * whether segmentation control is presented to the guest.
347 */
348 /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */
349 env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM);
350 /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */
351 env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16;
352 /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */
353 env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
354 (2 << CP0SC_C);
355 /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */
356 env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
357 (3 << CP0SC_C)) << 16;
358 /* USeg (seg4 0x40000000..0x7FFFFFFF) */
359 env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
360 (1 << CP0SC_EU) | (2 << CP0SC_C);
361 /* USeg (seg5 0x00000000..0x3FFFFFFF) */
362 env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
363 (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16;
364 /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */
365 env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM);
366#endif /* !CONFIG_USER_ONLY */
2e211e0a 367 if ((env->insn_flags & ISA_MIPS_R6) &&
c20cf02b
PMD
368 (env->active_fpu.fcr0 & (1 << FCR0_F64))) {
369 /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */
370 env->CP0_Status |= (1 << CP0St_FR);
371 }
372
2e211e0a 373 if (env->insn_flags & ISA_MIPS_R6) {
c20cf02b
PMD
374 /* PTW = 1 */
375 env->CP0_PWSize = 0x40;
376 /* GDI = 12 */
377 /* UDI = 12 */
378 /* MDI = 12 */
379 /* PRI = 12 */
380 /* PTEI = 2 */
381 env->CP0_PWField = 0x0C30C302;
382 } else {
383 /* GDI = 0 */
384 /* UDI = 0 */
385 /* MDI = 0 */
386 /* PRI = 0 */
387 /* PTEI = 2 */
388 env->CP0_PWField = 0x02;
389 }
390
391 if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) {
392 /* microMIPS on reset when Config3.ISA is 3 */
393 env->hflags |= MIPS_HFLAG_M16;
394 }
395
72f31f60 396 msa_reset(env);
c20cf02b
PMD
397
398 compute_hflags(env);
399 restore_fp_status(env);
400 restore_pamask(env);
401 cs->exception_index = EXCP_NONE;
402
403 if (semihosting_get_argc()) {
404 /* UHI interface can be used to obtain argc and argv */
405 env->active_tc.gpr[4] = -1;
406 }
14c03ab9
JH
407
408#ifndef CONFIG_USER_ONLY
409 if (kvm_enabled()) {
410 kvm_mips_reset_vcpu(cpu);
411 }
412#endif
0f71a709
AF
413}
414
cf02a116
AM
415static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info)
416{
89a955e8
AM
417 MIPSCPU *cpu = MIPS_CPU(s);
418 CPUMIPSState *env = &cpu->env;
419
420 if (!(env->insn_flags & ISA_NANOMIPS32)) {
ee3eb3a7 421#if TARGET_BIG_ENDIAN
89a955e8 422 info->print_insn = print_insn_big_mips;
63a946c7 423#else
89a955e8 424 info->print_insn = print_insn_little_mips;
63a946c7 425#endif
89a955e8
AM
426 } else {
427#if defined(CONFIG_NANOMIPS_DIS)
428 info->print_insn = print_insn_nanomips;
429#endif
430 }
63a946c7
PC
431}
432
d225b512 433/*
d0bec217 434 * Since commit 6af0bf9c7c3 this model assumes a CPU clocked at 200MHz.
d225b512
PMD
435 */
436#define CPU_FREQ_HZ_DEFAULT 200000000
d225b512
PMD
437
438static void mips_cp0_period_set(MIPSCPU *cpu)
439{
440 CPUMIPSState *env = &cpu->env;
441
0ac1fb25 442 env->cp0_count_ns = clock_ticks_to_ns(MIPS_CPU(cpu)->clock,
c8aeab3a 443 env->cpu_model->CCRes);
a0713e85 444 assert(env->cp0_count_ns);
d225b512
PMD
445}
446
c1caf1d9
AF
447static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
448{
14a10fc3 449 CPUState *cs = CPU(dev);
df4dc102 450 MIPSCPU *cpu = MIPS_CPU(dev);
7b884bf5 451 CPUMIPSState *env = &cpu->env;
c1caf1d9 452 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
ce5b1bbf
LV
453 Error *local_err = NULL;
454
a0713e85 455 if (!clock_get(cpu->clock)) {
8a6359f9
PMD
456#ifndef CONFIG_USER_ONLY
457 if (!qtest_enabled()) {
458 g_autofree char *cpu_freq_str = freq_to_str(CPU_FREQ_HZ_DEFAULT);
459
460 warn_report("CPU input clock is not connected to any output clock, "
461 "using default frequency of %s.", cpu_freq_str);
462 }
463#endif
a0713e85
PMD
464 /* Initialize the frequency in case the clock remains unconnected. */
465 clock_set_hz(cpu->clock, CPU_FREQ_HZ_DEFAULT);
466 }
d225b512
PMD
467 mips_cp0_period_set(cpu);
468
ce5b1bbf
LV
469 cpu_exec_realizefn(cs, &local_err);
470 if (local_err != NULL) {
471 error_propagate(errp, local_err);
472 return;
473 }
c1caf1d9 474
7b884bf5
PMD
475 env->exception_base = (int32_t)0xBFC00000;
476
c2842017 477#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
7b884bf5
PMD
478 mmu_init(env, env->cpu_model);
479#endif
480 fpu_init(env, env->cpu_model);
481 mvp_init(env);
df4dc102 482
14a10fc3
AF
483 cpu_reset(cs);
484 qemu_init_vcpu(cs);
c1caf1d9
AF
485
486 mcc->parent_realize(dev, errp);
487}
488
5b0c40f7
AF
489static void mips_cpu_initfn(Object *obj)
490{
491 MIPSCPU *cpu = MIPS_CPU(obj);
492 CPUMIPSState *env = &cpu->env;
41da212c 493 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
5b0c40f7 494
7506ed90 495 cpu_set_cpustate_pointers(cpu);
5ee0abed 496 cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0);
41da212c 497 env->cpu_model = mcc->cpu_def;
5b0c40f7
AF
498}
499
41da212c
IM
500static char *mips_cpu_type_name(const char *cpu_model)
501{
a7519f2b 502 return g_strdup_printf(MIPS_CPU_TYPE_NAME("%s"), cpu_model);
41da212c
IM
503}
504
505static ObjectClass *mips_cpu_class_by_name(const char *cpu_model)
506{
507 ObjectClass *oc;
508 char *typename;
509
41da212c
IM
510 typename = mips_cpu_type_name(cpu_model);
511 oc = object_class_by_name(typename);
512 g_free(typename);
513 return oc;
514}
515
8b80bd28
PMD
516#ifndef CONFIG_USER_ONLY
517#include "hw/core/sysemu-cpu-ops.h"
518
519static const struct SysemuCPUOps mips_sysemu_ops = {
08928c6d 520 .get_phys_page_debug = mips_cpu_get_phys_page_debug,
feece4d0 521 .legacy_vmsd = &vmstate_mips_cpu,
8b80bd28
PMD
522};
523#endif
524
78271684
CF
525#ifdef CONFIG_TCG
526#include "hw/core/tcg-cpu-ops.h"
527/*
528 * NB: cannot be const, as some elements are changed for specific
529 * mips hardware (see hw/mips/jazz.c).
530 */
11906557 531static const struct TCGCPUOps mips_tcg_ops = {
78271684
CF
532 .initialize = mips_tcg_init,
533 .synchronize_from_tb = mips_cpu_synchronize_from_tb,
78271684
CF
534
535#if !defined(CONFIG_USER_ONLY)
52d4899b 536 .tlb_fill = mips_cpu_tlb_fill,
6eb66e08 537 .cpu_exec_interrupt = mips_cpu_exec_interrupt,
78271684
CF
538 .do_interrupt = mips_cpu_do_interrupt,
539 .do_transaction_failed = mips_cpu_do_transaction_failed,
540 .do_unaligned_access = mips_cpu_do_unaligned_access,
95ab7c22 541 .io_recompile_replay_branch = mips_io_recompile_replay_branch,
78271684
CF
542#endif /* !CONFIG_USER_ONLY */
543};
544#endif /* CONFIG_TCG */
545
0f71a709
AF
546static void mips_cpu_class_init(ObjectClass *c, void *data)
547{
548 MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
549 CPUClass *cc = CPU_CLASS(c);
c1caf1d9
AF
550 DeviceClass *dc = DEVICE_CLASS(c);
551
bf853881
PMD
552 device_class_set_parent_realize(dc, mips_cpu_realizefn,
553 &mcc->parent_realize);
781c67ca 554 device_class_set_parent_reset(dc, mips_cpu_reset, &mcc->parent_reset);
97a8ea5a 555
41da212c 556 cc->class_by_name = mips_cpu_class_by_name;
8c2e1b00 557 cc->has_work = mips_cpu_has_work;
878096ee 558 cc->dump_state = mips_cpu_dump_state;
f45748f1 559 cc->set_pc = mips_cpu_set_pc;
5b50e790
AF
560 cc->gdb_read_register = mips_cpu_gdb_read_register;
561 cc->gdb_write_register = mips_cpu_gdb_write_register;
931d019f 562#ifndef CONFIG_USER_ONLY
8b80bd28 563 cc->sysemu_ops = &mips_sysemu_ops;
00b941e5 564#endif
63a946c7 565 cc->disas_set_info = mips_cpu_disas_set_info;
a0e372f0 566 cc->gdb_num_core_regs = 73;
2472b6c0 567 cc->gdb_stop_before_watchpoint = true;
78271684
CF
568#ifdef CONFIG_TCG
569 cc->tcg_ops = &mips_tcg_ops;
570#endif /* CONFIG_TCG */
0f71a709
AF
571}
572
573static const TypeInfo mips_cpu_type_info = {
574 .name = TYPE_MIPS_CPU,
575 .parent = TYPE_CPU,
576 .instance_size = sizeof(MIPSCPU),
5b0c40f7 577 .instance_init = mips_cpu_initfn,
41da212c 578 .abstract = true,
0f71a709
AF
579 .class_size = sizeof(MIPSCPUClass),
580 .class_init = mips_cpu_class_init,
581};
582
41da212c
IM
583static void mips_cpu_cpudef_class_init(ObjectClass *oc, void *data)
584{
585 MIPSCPUClass *mcc = MIPS_CPU_CLASS(oc);
586 mcc->cpu_def = data;
587}
588
589static void mips_register_cpudef_type(const struct mips_def_t *def)
590{
591 char *typename = mips_cpu_type_name(def->name);
592 TypeInfo ti = {
593 .name = typename,
594 .parent = TYPE_MIPS_CPU,
595 .class_init = mips_cpu_cpudef_class_init,
596 .class_data = (void *)def,
597 };
598
599 type_register(&ti);
600 g_free(typename);
601}
602
0f71a709
AF
603static void mips_cpu_register_types(void)
604{
41da212c
IM
605 int i;
606
0f71a709 607 type_register_static(&mips_cpu_type_info);
41da212c
IM
608 for (i = 0; i < mips_defs_number; i++) {
609 mips_register_cpudef_type(&mips_defs[i]);
610 }
0f71a709
AF
611}
612
613type_init(mips_cpu_register_types)
7aaab96a 614
a10b453a
PMD
615static void mips_cpu_add_definition(gpointer data, gpointer user_data)
616{
617 ObjectClass *oc = data;
618 CpuDefinitionInfoList **cpu_list = user_data;
a10b453a
PMD
619 CpuDefinitionInfo *info;
620 const char *typename;
621
622 typename = object_class_get_name(oc);
623 info = g_malloc0(sizeof(*info));
624 info->name = g_strndup(typename,
625 strlen(typename) - strlen("-" TYPE_MIPS_CPU));
626 info->q_typename = g_strdup(typename);
627
54aa3de7 628 QAPI_LIST_PREPEND(*cpu_list, info);
a10b453a
PMD
629}
630
631CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
632{
633 CpuDefinitionInfoList *cpu_list = NULL;
634 GSList *list;
635
636 list = object_class_get_list(TYPE_MIPS_CPU, false);
637 g_slist_foreach(list, mips_cpu_add_definition, &cpu_list);
638 g_slist_free(list);
639
640 return cpu_list;
641}
642
7aaab96a
PMD
643/* Could be used by generic CPU object */
644MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
645{
646 DeviceState *cpu;
647
648 cpu = DEVICE(object_new(cpu_type));
649 qdev_connect_clock_in(cpu, "clk-in", cpu_refclk);
650 qdev_realize(cpu, NULL, &error_abort);
651
652 return MIPS_CPU(cpu);
653}
df6adb68
PMD
654
655bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask)
656{
657 return (env->cpu_model->insn_flags & isa_mask) != 0;
658}
ffa657ee
PMD
659
660bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa)
661{
662 const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
663 return (mcc->cpu_def->insn_flags & isa) != 0;
664}
665
666bool cpu_type_supports_cps_smp(const char *cpu_type)
667{
668 const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
669 return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
670}