]> git.proxmox.com Git - mirror_qemu.git/blame - target/mips/cpu.c
target/mips: Optimize CPU/FPU regnames[] arrays
[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
830b87ea 38const char regnames[32][4] = {
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
e9927723
PMD
45#if !defined(CONFIG_USER_ONLY)
46
47/* Called for updates to CP0_Status. */
48void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
49{
50 int32_t tcstatus, *tcst;
51 uint32_t v = cpu->CP0_Status;
52 uint32_t cu, mx, asid, ksu;
53 uint32_t mask = ((1 << CP0TCSt_TCU3)
54 | (1 << CP0TCSt_TCU2)
55 | (1 << CP0TCSt_TCU1)
56 | (1 << CP0TCSt_TCU0)
57 | (1 << CP0TCSt_TMX)
58 | (3 << CP0TCSt_TKSU)
59 | (0xff << CP0TCSt_TASID));
60
61 cu = (v >> CP0St_CU0) & 0xf;
62 mx = (v >> CP0St_MX) & 0x1;
63 ksu = (v >> CP0St_KSU) & 0x3;
64 asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
65
66 tcstatus = cu << CP0TCSt_TCU0;
67 tcstatus |= mx << CP0TCSt_TMX;
68 tcstatus |= ksu << CP0TCSt_TKSU;
69 tcstatus |= asid;
70
71 if (tc == cpu->current_tc) {
72 tcst = &cpu->active_tc.CP0_TCStatus;
73 } else {
74 tcst = &cpu->tcs[tc].CP0_TCStatus;
75 }
76
77 *tcst &= ~mask;
78 *tcst |= tcstatus;
79 compute_hflags(cpu);
80}
81
82void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
83{
84 uint32_t mask = env->CP0_Status_rw_bitmask;
85 target_ulong old = env->CP0_Status;
86
87 if (env->insn_flags & ISA_MIPS_R6) {
88 bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
89#if defined(TARGET_MIPS64)
90 uint32_t ksux = (1 << CP0St_KX) & val;
91 ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */
92 ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */
93 val = (val & ~(7 << CP0St_UX)) | ksux;
94#endif
95 if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) {
96 mask &= ~(3 << CP0St_KSU);
97 }
98 mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val);
99 }
100
101 env->CP0_Status = (old & ~mask) | (val & mask);
102#if defined(TARGET_MIPS64)
103 if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
104 /* Access to at least one of the 64-bit segments has been disabled */
105 tlb_flush(env_cpu(env));
106 }
107#endif
108 if (ase_mt_available(env)) {
109 sync_c0_status(env, env, env->current_tc);
110 } else {
111 compute_hflags(env);
112 }
113}
114
115void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val)
116{
117 uint32_t mask = 0x00C00300;
118 uint32_t old = env->CP0_Cause;
119 int i;
120
121 if (env->insn_flags & ISA_MIPS_R2) {
122 mask |= 1 << CP0Ca_DC;
123 }
124 if (env->insn_flags & ISA_MIPS_R6) {
125 mask &= ~((1 << CP0Ca_WP) & val);
126 }
127
128 env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask);
129
130 if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
131 if (env->CP0_Cause & (1 << CP0Ca_DC)) {
132 cpu_mips_stop_count(env);
133 } else {
134 cpu_mips_start_count(env);
135 }
136 }
137
138 /* Set/reset software interrupts */
139 for (i = 0 ; i < 2 ; i++) {
140 if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
141 cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
142 }
143 }
144}
145
146#endif /* !CONFIG_USER_ONLY */
147
148static const char * const excp_names[EXCP_LAST + 1] = {
149 [EXCP_RESET] = "reset",
150 [EXCP_SRESET] = "soft reset",
151 [EXCP_DSS] = "debug single step",
152 [EXCP_DINT] = "debug interrupt",
153 [EXCP_NMI] = "non-maskable interrupt",
154 [EXCP_MCHECK] = "machine check",
155 [EXCP_EXT_INTERRUPT] = "interrupt",
156 [EXCP_DFWATCH] = "deferred watchpoint",
157 [EXCP_DIB] = "debug instruction breakpoint",
158 [EXCP_IWATCH] = "instruction fetch watchpoint",
159 [EXCP_AdEL] = "address error load",
160 [EXCP_AdES] = "address error store",
161 [EXCP_TLBF] = "TLB refill",
162 [EXCP_IBE] = "instruction bus error",
163 [EXCP_DBp] = "debug breakpoint",
164 [EXCP_SYSCALL] = "syscall",
165 [EXCP_BREAK] = "break",
166 [EXCP_CpU] = "coprocessor unusable",
167 [EXCP_RI] = "reserved instruction",
168 [EXCP_OVERFLOW] = "arithmetic overflow",
169 [EXCP_TRAP] = "trap",
170 [EXCP_FPE] = "floating point",
171 [EXCP_DDBS] = "debug data break store",
172 [EXCP_DWATCH] = "data watchpoint",
173 [EXCP_LTLBL] = "TLB modify",
174 [EXCP_TLBL] = "TLB load",
175 [EXCP_TLBS] = "TLB store",
176 [EXCP_DBE] = "data bus error",
177 [EXCP_DDBL] = "debug data break load",
178 [EXCP_THREAD] = "thread",
179 [EXCP_MDMX] = "MDMX",
180 [EXCP_C2E] = "precise coprocessor 2",
181 [EXCP_CACHE] = "cache error",
182 [EXCP_TLBXI] = "TLB execute-inhibit",
183 [EXCP_TLBRI] = "TLB read-inhibit",
184 [EXCP_MSADIS] = "MSA disabled",
185 [EXCP_MSAFPE] = "MSA floating point",
186};
187
188const char *mips_exception_name(int32_t exception)
189{
190 if (exception < 0 || exception > EXCP_LAST) {
191 return "unknown";
192 }
193 return excp_names[exception];
194}
195
196void cpu_set_exception_base(int vp_index, target_ulong address)
197{
198 MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
199 vp->env.exception_base = address;
200}
201
202target_ulong exception_resume_pc(CPUMIPSState *env)
203{
204 target_ulong bad_pc;
205 target_ulong isa_mode;
206
207 isa_mode = !!(env->hflags & MIPS_HFLAG_M16);
208 bad_pc = env->active_tc.PC | isa_mode;
209 if (env->hflags & MIPS_HFLAG_BMASK) {
210 /*
211 * If the exception was raised from a delay slot, come back to
212 * the jump.
213 */
214 bad_pc -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
215 }
216
217 return bad_pc;
218}
219
220bool mips_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
221{
222 if (interrupt_request & CPU_INTERRUPT_HARD) {
223 MIPSCPU *cpu = MIPS_CPU(cs);
224 CPUMIPSState *env = &cpu->env;
225
226 if (cpu_mips_hw_interrupts_enabled(env) &&
227 cpu_mips_hw_interrupts_pending(env)) {
228 /* Raise it */
229 cs->exception_index = EXCP_EXT_INTERRUPT;
230 env->error_code = 0;
231 mips_cpu_do_interrupt(cs);
232 return true;
233 }
234 }
235 return false;
236}
237
238void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env,
239 uint32_t exception,
240 int error_code,
241 uintptr_t pc)
242{
243 CPUState *cs = env_cpu(env);
244
245 qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n",
246 __func__, exception, mips_exception_name(exception),
247 error_code);
248 cs->exception_index = exception;
249 env->error_code = error_code;
250
251 cpu_loop_exit_restore(cs, pc);
252}
253
f45748f1
AF
254static void mips_cpu_set_pc(CPUState *cs, vaddr value)
255{
256 MIPSCPU *cpu = MIPS_CPU(cs);
257 CPUMIPSState *env = &cpu->env;
258
259 env->active_tc.PC = value & ~(target_ulong)1;
260 if (value & 1) {
261 env->hflags |= MIPS_HFLAG_M16;
262 } else {
263 env->hflags &= ~(MIPS_HFLAG_M16);
264 }
265}
266
ec62595b 267#ifdef CONFIG_TCG
04a37d4c
RH
268static void mips_cpu_synchronize_from_tb(CPUState *cs,
269 const TranslationBlock *tb)
bdf7ae5b
AF
270{
271 MIPSCPU *cpu = MIPS_CPU(cs);
272 CPUMIPSState *env = &cpu->env;
273
274 env->active_tc.PC = tb->pc;
275 env->hflags &= ~MIPS_HFLAG_BMASK;
276 env->hflags |= tb->flags & MIPS_HFLAG_BMASK;
277}
95ab7c22
RH
278
279# ifndef CONFIG_USER_ONLY
280static bool mips_io_recompile_replay_branch(CPUState *cs,
281 const TranslationBlock *tb)
282{
283 MIPSCPU *cpu = MIPS_CPU(cs);
284 CPUMIPSState *env = &cpu->env;
285
286 if ((env->hflags & MIPS_HFLAG_BMASK) != 0
287 && env->active_tc.PC != tb->pc) {
288 env->active_tc.PC -= (env->hflags & MIPS_HFLAG_B16 ? 2 : 4);
289 env->hflags &= ~MIPS_HFLAG_BMASK;
290 return true;
291 }
292 return false;
293}
294# endif /* !CONFIG_USER_ONLY */
ec62595b 295#endif /* CONFIG_TCG */
bdf7ae5b 296
8c2e1b00
AF
297static bool mips_cpu_has_work(CPUState *cs)
298{
299 MIPSCPU *cpu = MIPS_CPU(cs);
300 CPUMIPSState *env = &cpu->env;
301 bool has_work = false;
302
cf02a116
AM
303 /*
304 * Prior to MIPS Release 6 it is implementation dependent if non-enabled
305 * interrupts wake-up the CPU, however most of the implementations only
306 * check for interrupts that can be taken.
307 */
8c2e1b00
AF
308 if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
309 cpu_mips_hw_interrupts_pending(env)) {
7540a43a 310 if (cpu_mips_hw_interrupts_enabled(env) ||
2e211e0a 311 (env->insn_flags & ISA_MIPS_R6)) {
71ca034a
LA
312 has_work = true;
313 }
8c2e1b00
AF
314 }
315
316 /* MIPS-MT has the ability to halt the CPU. */
17c2c320 317 if (ase_mt_available(env)) {
cf02a116
AM
318 /*
319 * The QEMU model will issue an _WAKE request whenever the CPUs
320 * should be woken up.
321 */
8c2e1b00
AF
322 if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
323 has_work = true;
324 }
325
326 if (!mips_vpe_active(env)) {
327 has_work = false;
328 }
329 }
01bc435b
YK
330 /* MIPS Release 6 has the ability to halt the CPU. */
331 if (env->CP0_Config5 & (1 << CP0C5_VP)) {
332 if (cs->interrupt_request & CPU_INTERRUPT_WAKE) {
333 has_work = true;
334 }
335 if (!mips_vp_active(env)) {
336 has_work = false;
337 }
338 }
8c2e1b00
AF
339 return has_work;
340}
341
0dc351ca 342#include "cpu-defs.c.inc"
c20cf02b 343
9bcd41d4 344static void mips_cpu_reset(DeviceState *dev)
c20cf02b 345{
9bcd41d4
PMD
346 CPUState *cs = CPU(dev);
347 MIPSCPU *cpu = MIPS_CPU(cs);
348 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cpu);
349 CPUMIPSState *env = &cpu->env;
350
351 mcc->parent_reset(dev);
352
353 memset(env, 0, offsetof(CPUMIPSState, end_reset_fields));
c20cf02b
PMD
354
355 /* Reset registers to their default values */
356 env->CP0_PRid = env->cpu_model->CP0_PRid;
357 env->CP0_Config0 = env->cpu_model->CP0_Config0;
358#ifdef TARGET_WORDS_BIGENDIAN
359 env->CP0_Config0 |= (1 << CP0C0_BE);
360#endif
361 env->CP0_Config1 = env->cpu_model->CP0_Config1;
362 env->CP0_Config2 = env->cpu_model->CP0_Config2;
363 env->CP0_Config3 = env->cpu_model->CP0_Config3;
364 env->CP0_Config4 = env->cpu_model->CP0_Config4;
365 env->CP0_Config4_rw_bitmask = env->cpu_model->CP0_Config4_rw_bitmask;
366 env->CP0_Config5 = env->cpu_model->CP0_Config5;
367 env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
368 env->CP0_Config6 = env->cpu_model->CP0_Config6;
369 env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
370 env->CP0_Config7 = env->cpu_model->CP0_Config7;
371 env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
372 env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
373 << env->cpu_model->CP0_LLAddr_shift;
374 env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
375 env->SYNCI_Step = env->cpu_model->SYNCI_Step;
376 env->CCRes = env->cpu_model->CCRes;
377 env->CP0_Status_rw_bitmask = env->cpu_model->CP0_Status_rw_bitmask;
378 env->CP0_TCStatus_rw_bitmask = env->cpu_model->CP0_TCStatus_rw_bitmask;
379 env->CP0_SRSCtl = env->cpu_model->CP0_SRSCtl;
380 env->current_tc = 0;
381 env->SEGBITS = env->cpu_model->SEGBITS;
382 env->SEGMask = (target_ulong)((1ULL << env->cpu_model->SEGBITS) - 1);
383#if defined(TARGET_MIPS64)
384 if (env->cpu_model->insn_flags & ISA_MIPS3) {
385 env->SEGMask |= 3ULL << 62;
386 }
387#endif
388 env->PABITS = env->cpu_model->PABITS;
389 env->CP0_SRSConf0_rw_bitmask = env->cpu_model->CP0_SRSConf0_rw_bitmask;
390 env->CP0_SRSConf0 = env->cpu_model->CP0_SRSConf0;
391 env->CP0_SRSConf1_rw_bitmask = env->cpu_model->CP0_SRSConf1_rw_bitmask;
392 env->CP0_SRSConf1 = env->cpu_model->CP0_SRSConf1;
393 env->CP0_SRSConf2_rw_bitmask = env->cpu_model->CP0_SRSConf2_rw_bitmask;
394 env->CP0_SRSConf2 = env->cpu_model->CP0_SRSConf2;
395 env->CP0_SRSConf3_rw_bitmask = env->cpu_model->CP0_SRSConf3_rw_bitmask;
396 env->CP0_SRSConf3 = env->cpu_model->CP0_SRSConf3;
397 env->CP0_SRSConf4_rw_bitmask = env->cpu_model->CP0_SRSConf4_rw_bitmask;
398 env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
399 env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
400 env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
401 env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
402 env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
403 env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
404 env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
405 env->msair = env->cpu_model->MSAIR;
406 env->insn_flags = env->cpu_model->insn_flags;
407
408#if defined(CONFIG_USER_ONLY)
409 env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU);
410# ifdef TARGET_MIPS64
411 /* Enable 64-bit register mode. */
412 env->CP0_Status |= (1 << CP0St_PX);
413# endif
414# ifdef TARGET_ABI_MIPSN64
415 /* Enable 64-bit address mode. */
416 env->CP0_Status |= (1 << CP0St_UX);
417# endif
418 /*
419 * Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR
420 * hardware registers.
421 */
422 env->CP0_HWREna |= 0x0000000F;
423 if (env->CP0_Config1 & (1 << CP0C1_FP)) {
424 env->CP0_Status |= (1 << CP0St_CU1);
425 }
426 if (env->CP0_Config3 & (1 << CP0C3_DSPP)) {
427 env->CP0_Status |= (1 << CP0St_MX);
428 }
429# if defined(TARGET_MIPS64)
430 /* For MIPS64, init FR bit to 1 if FPU unit is there and bit is writable. */
431 if ((env->CP0_Config1 & (1 << CP0C1_FP)) &&
432 (env->CP0_Status_rw_bitmask & (1 << CP0St_FR))) {
433 env->CP0_Status |= (1 << CP0St_FR);
434 }
435# endif
436#else /* !CONFIG_USER_ONLY */
437 if (env->hflags & MIPS_HFLAG_BMASK) {
438 /*
439 * If the exception was raised from a delay slot,
440 * come back to the jump.
441 */
442 env->CP0_ErrorEPC = (env->active_tc.PC
443 - (env->hflags & MIPS_HFLAG_B16 ? 2 : 4));
444 } else {
445 env->CP0_ErrorEPC = env->active_tc.PC;
446 }
447 env->active_tc.PC = env->exception_base;
448 env->CP0_Random = env->tlb->nb_tlb - 1;
449 env->tlb->tlb_in_use = env->tlb->nb_tlb;
450 env->CP0_Wired = 0;
451 env->CP0_GlobalNumber = (cs->cpu_index & 0xFF) << CP0GN_VPId;
452 env->CP0_EBase = (cs->cpu_index & 0x3FF);
453 if (mips_um_ksegs_enabled()) {
454 env->CP0_EBase |= 0x40000000;
455 } else {
456 env->CP0_EBase |= (int32_t)0x80000000;
457 }
458 if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) {
459 env->CP0_CMGCRBase = 0x1fbf8000 >> 4;
460 }
461 env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
462 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
463 env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
464 /*
465 * Vectored interrupts not implemented, timer on int 7,
466 * no performance counters.
467 */
468 env->CP0_IntCtl = 0xe0000000;
469 {
470 int i;
471
472 for (i = 0; i < 7; i++) {
473 env->CP0_WatchLo[i] = 0;
474 env->CP0_WatchHi[i] = 0x80000000;
475 }
476 env->CP0_WatchLo[7] = 0;
477 env->CP0_WatchHi[7] = 0;
478 }
479 /* Count register increments in debug mode, EJTAG version 1 */
480 env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
481
482 cpu_mips_store_count(env, 1);
483
484 if (ase_mt_available(env)) {
485 int i;
486
487 /* Only TC0 on VPE 0 starts as active. */
488 for (i = 0; i < ARRAY_SIZE(env->tcs); i++) {
489 env->tcs[i].CP0_TCBind = cs->cpu_index << CP0TCBd_CurVPE;
490 env->tcs[i].CP0_TCHalt = 1;
491 }
492 env->active_tc.CP0_TCHalt = 1;
493 cs->halted = 1;
494
495 if (cs->cpu_index == 0) {
496 /* VPE0 starts up enabled. */
497 env->mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
498 env->CP0_VPEConf0 |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
499
500 /* TC0 starts up unhalted. */
501 cs->halted = 0;
502 env->active_tc.CP0_TCHalt = 0;
503 env->tcs[0].CP0_TCHalt = 0;
504 /* With thread 0 active. */
505 env->active_tc.CP0_TCStatus = (1 << CP0TCSt_A);
506 env->tcs[0].CP0_TCStatus = (1 << CP0TCSt_A);
507 }
508 }
509
510 /*
511 * Configure default legacy segmentation control. We use this regardless of
512 * whether segmentation control is presented to the guest.
513 */
514 /* KSeg3 (seg0 0xE0000000..0xFFFFFFFF) */
515 env->CP0_SegCtl0 = (CP0SC_AM_MK << CP0SC_AM);
516 /* KSeg2 (seg1 0xC0000000..0xDFFFFFFF) */
517 env->CP0_SegCtl0 |= ((CP0SC_AM_MSK << CP0SC_AM)) << 16;
518 /* KSeg1 (seg2 0xA0000000..0x9FFFFFFF) */
519 env->CP0_SegCtl1 = (0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
520 (2 << CP0SC_C);
521 /* KSeg0 (seg3 0x80000000..0x9FFFFFFF) */
522 env->CP0_SegCtl1 |= ((0 << CP0SC_PA) | (CP0SC_AM_UK << CP0SC_AM) |
523 (3 << CP0SC_C)) << 16;
524 /* USeg (seg4 0x40000000..0x7FFFFFFF) */
525 env->CP0_SegCtl2 = (2 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
526 (1 << CP0SC_EU) | (2 << CP0SC_C);
527 /* USeg (seg5 0x00000000..0x3FFFFFFF) */
528 env->CP0_SegCtl2 |= ((0 << CP0SC_PA) | (CP0SC_AM_MUSK << CP0SC_AM) |
529 (1 << CP0SC_EU) | (2 << CP0SC_C)) << 16;
530 /* XKPhys (note, SegCtl2.XR = 0, so XAM won't be used) */
531 env->CP0_SegCtl1 |= (CP0SC_AM_UK << CP0SC1_XAM);
532#endif /* !CONFIG_USER_ONLY */
2e211e0a 533 if ((env->insn_flags & ISA_MIPS_R6) &&
c20cf02b
PMD
534 (env->active_fpu.fcr0 & (1 << FCR0_F64))) {
535 /* Status.FR = 0 mode in 64-bit FPU not allowed in R6 */
536 env->CP0_Status |= (1 << CP0St_FR);
537 }
538
2e211e0a 539 if (env->insn_flags & ISA_MIPS_R6) {
c20cf02b
PMD
540 /* PTW = 1 */
541 env->CP0_PWSize = 0x40;
542 /* GDI = 12 */
543 /* UDI = 12 */
544 /* MDI = 12 */
545 /* PRI = 12 */
546 /* PTEI = 2 */
547 env->CP0_PWField = 0x0C30C302;
548 } else {
549 /* GDI = 0 */
550 /* UDI = 0 */
551 /* MDI = 0 */
552 /* PRI = 0 */
553 /* PTEI = 2 */
554 env->CP0_PWField = 0x02;
555 }
556
557 if (env->CP0_Config3 & (1 << CP0C3_ISA) & (1 << (CP0C3_ISA + 1))) {
558 /* microMIPS on reset when Config3.ISA is 3 */
559 env->hflags |= MIPS_HFLAG_M16;
560 }
561
72f31f60 562 msa_reset(env);
c20cf02b
PMD
563
564 compute_hflags(env);
565 restore_fp_status(env);
566 restore_pamask(env);
567 cs->exception_index = EXCP_NONE;
568
569 if (semihosting_get_argc()) {
570 /* UHI interface can be used to obtain argc and argv */
571 env->active_tc.gpr[4] = -1;
572 }
14c03ab9
JH
573
574#ifndef CONFIG_USER_ONLY
575 if (kvm_enabled()) {
576 kvm_mips_reset_vcpu(cpu);
577 }
578#endif
0f71a709
AF
579}
580
cf02a116
AM
581static void mips_cpu_disas_set_info(CPUState *s, disassemble_info *info)
582{
89a955e8
AM
583 MIPSCPU *cpu = MIPS_CPU(s);
584 CPUMIPSState *env = &cpu->env;
585
586 if (!(env->insn_flags & ISA_NANOMIPS32)) {
63a946c7 587#ifdef TARGET_WORDS_BIGENDIAN
89a955e8 588 info->print_insn = print_insn_big_mips;
63a946c7 589#else
89a955e8 590 info->print_insn = print_insn_little_mips;
63a946c7 591#endif
89a955e8
AM
592 } else {
593#if defined(CONFIG_NANOMIPS_DIS)
594 info->print_insn = print_insn_nanomips;
595#endif
596 }
63a946c7
PC
597}
598
d225b512 599/*
d0bec217 600 * Since commit 6af0bf9c7c3 this model assumes a CPU clocked at 200MHz.
d225b512
PMD
601 */
602#define CPU_FREQ_HZ_DEFAULT 200000000
603#define CP0_COUNT_RATE_DEFAULT 2
d225b512
PMD
604
605static void mips_cp0_period_set(MIPSCPU *cpu)
606{
607 CPUMIPSState *env = &cpu->env;
608
0ac1fb25
PM
609 env->cp0_count_ns = clock_ticks_to_ns(MIPS_CPU(cpu)->clock,
610 cpu->cp0_count_rate);
a0713e85 611 assert(env->cp0_count_ns);
d225b512
PMD
612}
613
c1caf1d9
AF
614static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
615{
14a10fc3 616 CPUState *cs = CPU(dev);
df4dc102 617 MIPSCPU *cpu = MIPS_CPU(dev);
7b884bf5 618 CPUMIPSState *env = &cpu->env;
c1caf1d9 619 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(dev);
ce5b1bbf
LV
620 Error *local_err = NULL;
621
a0713e85 622 if (!clock_get(cpu->clock)) {
8a6359f9
PMD
623#ifndef CONFIG_USER_ONLY
624 if (!qtest_enabled()) {
625 g_autofree char *cpu_freq_str = freq_to_str(CPU_FREQ_HZ_DEFAULT);
626
627 warn_report("CPU input clock is not connected to any output clock, "
628 "using default frequency of %s.", cpu_freq_str);
629 }
630#endif
a0713e85
PMD
631 /* Initialize the frequency in case the clock remains unconnected. */
632 clock_set_hz(cpu->clock, CPU_FREQ_HZ_DEFAULT);
633 }
d225b512
PMD
634 mips_cp0_period_set(cpu);
635
ce5b1bbf
LV
636 cpu_exec_realizefn(cs, &local_err);
637 if (local_err != NULL) {
638 error_propagate(errp, local_err);
639 return;
640 }
c1caf1d9 641
7b884bf5
PMD
642 env->exception_base = (int32_t)0xBFC00000;
643
644#ifndef CONFIG_USER_ONLY
645 mmu_init(env, env->cpu_model);
646#endif
647 fpu_init(env, env->cpu_model);
648 mvp_init(env);
df4dc102 649
14a10fc3
AF
650 cpu_reset(cs);
651 qemu_init_vcpu(cs);
c1caf1d9
AF
652
653 mcc->parent_realize(dev, errp);
654}
655
5b0c40f7
AF
656static void mips_cpu_initfn(Object *obj)
657{
658 MIPSCPU *cpu = MIPS_CPU(obj);
659 CPUMIPSState *env = &cpu->env;
41da212c 660 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(obj);
5b0c40f7 661
7506ed90 662 cpu_set_cpustate_pointers(cpu);
5ee0abed 663 cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0);
41da212c 664 env->cpu_model = mcc->cpu_def;
5b0c40f7
AF
665}
666
41da212c
IM
667static char *mips_cpu_type_name(const char *cpu_model)
668{
a7519f2b 669 return g_strdup_printf(MIPS_CPU_TYPE_NAME("%s"), cpu_model);
41da212c
IM
670}
671
672static ObjectClass *mips_cpu_class_by_name(const char *cpu_model)
673{
674 ObjectClass *oc;
675 char *typename;
676
41da212c
IM
677 typename = mips_cpu_type_name(cpu_model);
678 oc = object_class_by_name(typename);
679 g_free(typename);
680 return oc;
681}
682
d0bec217
PMD
683static Property mips_cpu_properties[] = {
684 /* CP0 timer running at half the clock of the CPU */
685 DEFINE_PROP_UINT32("cp0-count-rate", MIPSCPU, cp0_count_rate,
686 CP0_COUNT_RATE_DEFAULT),
687 DEFINE_PROP_END_OF_LIST()
688};
689
78271684
CF
690#ifdef CONFIG_TCG
691#include "hw/core/tcg-cpu-ops.h"
692/*
693 * NB: cannot be const, as some elements are changed for specific
694 * mips hardware (see hw/mips/jazz.c).
695 */
696static struct TCGCPUOps mips_tcg_ops = {
697 .initialize = mips_tcg_init,
698 .synchronize_from_tb = mips_cpu_synchronize_from_tb,
699 .cpu_exec_interrupt = mips_cpu_exec_interrupt,
700 .tlb_fill = mips_cpu_tlb_fill,
701
702#if !defined(CONFIG_USER_ONLY)
703 .do_interrupt = mips_cpu_do_interrupt,
704 .do_transaction_failed = mips_cpu_do_transaction_failed,
705 .do_unaligned_access = mips_cpu_do_unaligned_access,
95ab7c22 706 .io_recompile_replay_branch = mips_io_recompile_replay_branch,
78271684
CF
707#endif /* !CONFIG_USER_ONLY */
708};
709#endif /* CONFIG_TCG */
710
0f71a709
AF
711static void mips_cpu_class_init(ObjectClass *c, void *data)
712{
713 MIPSCPUClass *mcc = MIPS_CPU_CLASS(c);
714 CPUClass *cc = CPU_CLASS(c);
c1caf1d9
AF
715 DeviceClass *dc = DEVICE_CLASS(c);
716
bf853881
PMD
717 device_class_set_parent_realize(dc, mips_cpu_realizefn,
718 &mcc->parent_realize);
781c67ca 719 device_class_set_parent_reset(dc, mips_cpu_reset, &mcc->parent_reset);
d0bec217 720 device_class_set_props(dc, mips_cpu_properties);
97a8ea5a 721
41da212c 722 cc->class_by_name = mips_cpu_class_by_name;
8c2e1b00 723 cc->has_work = mips_cpu_has_work;
878096ee 724 cc->dump_state = mips_cpu_dump_state;
f45748f1 725 cc->set_pc = mips_cpu_set_pc;
5b50e790
AF
726 cc->gdb_read_register = mips_cpu_gdb_read_register;
727 cc->gdb_write_register = mips_cpu_gdb_write_register;
931d019f 728#ifndef CONFIG_USER_ONLY
00b941e5 729 cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
04cd7962 730 cc->vmsd = &vmstate_mips_cpu;
00b941e5 731#endif
63a946c7 732 cc->disas_set_info = mips_cpu_disas_set_info;
a0e372f0 733 cc->gdb_num_core_regs = 73;
2472b6c0 734 cc->gdb_stop_before_watchpoint = true;
78271684
CF
735#ifdef CONFIG_TCG
736 cc->tcg_ops = &mips_tcg_ops;
737#endif /* CONFIG_TCG */
0f71a709
AF
738}
739
740static const TypeInfo mips_cpu_type_info = {
741 .name = TYPE_MIPS_CPU,
742 .parent = TYPE_CPU,
743 .instance_size = sizeof(MIPSCPU),
5b0c40f7 744 .instance_init = mips_cpu_initfn,
41da212c 745 .abstract = true,
0f71a709
AF
746 .class_size = sizeof(MIPSCPUClass),
747 .class_init = mips_cpu_class_init,
748};
749
41da212c
IM
750static void mips_cpu_cpudef_class_init(ObjectClass *oc, void *data)
751{
752 MIPSCPUClass *mcc = MIPS_CPU_CLASS(oc);
753 mcc->cpu_def = data;
754}
755
756static void mips_register_cpudef_type(const struct mips_def_t *def)
757{
758 char *typename = mips_cpu_type_name(def->name);
759 TypeInfo ti = {
760 .name = typename,
761 .parent = TYPE_MIPS_CPU,
762 .class_init = mips_cpu_cpudef_class_init,
763 .class_data = (void *)def,
764 };
765
766 type_register(&ti);
767 g_free(typename);
768}
769
0f71a709
AF
770static void mips_cpu_register_types(void)
771{
41da212c
IM
772 int i;
773
0f71a709 774 type_register_static(&mips_cpu_type_info);
41da212c
IM
775 for (i = 0; i < mips_defs_number; i++) {
776 mips_register_cpudef_type(&mips_defs[i]);
777 }
0f71a709
AF
778}
779
780type_init(mips_cpu_register_types)
7aaab96a 781
a10b453a
PMD
782static void mips_cpu_add_definition(gpointer data, gpointer user_data)
783{
784 ObjectClass *oc = data;
785 CpuDefinitionInfoList **cpu_list = user_data;
a10b453a
PMD
786 CpuDefinitionInfo *info;
787 const char *typename;
788
789 typename = object_class_get_name(oc);
790 info = g_malloc0(sizeof(*info));
791 info->name = g_strndup(typename,
792 strlen(typename) - strlen("-" TYPE_MIPS_CPU));
793 info->q_typename = g_strdup(typename);
794
54aa3de7 795 QAPI_LIST_PREPEND(*cpu_list, info);
a10b453a
PMD
796}
797
798CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
799{
800 CpuDefinitionInfoList *cpu_list = NULL;
801 GSList *list;
802
803 list = object_class_get_list(TYPE_MIPS_CPU, false);
804 g_slist_foreach(list, mips_cpu_add_definition, &cpu_list);
805 g_slist_free(list);
806
807 return cpu_list;
808}
809
7aaab96a
PMD
810/* Could be used by generic CPU object */
811MIPSCPU *mips_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk)
812{
813 DeviceState *cpu;
814
815 cpu = DEVICE(object_new(cpu_type));
816 qdev_connect_clock_in(cpu, "clk-in", cpu_refclk);
817 qdev_realize(cpu, NULL, &error_abort);
818
819 return MIPS_CPU(cpu);
820}
df6adb68
PMD
821
822bool cpu_supports_isa(const CPUMIPSState *env, uint64_t isa_mask)
823{
824 return (env->cpu_model->insn_flags & isa_mask) != 0;
825}
ffa657ee
PMD
826
827bool cpu_type_supports_isa(const char *cpu_type, uint64_t isa)
828{
829 const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
830 return (mcc->cpu_def->insn_flags & isa) != 0;
831}
832
833bool cpu_type_supports_cps_smp(const char *cpu_type)
834{
835 const MIPSCPUClass *mcc = MIPS_CPU_CLASS(object_class_by_name(cpu_type));
836 return (mcc->cpu_def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
837}