target/mips/mips-defs: Use ISA_MIPS32R6 definition to check Release 6
[qemu/ar7.git] / target / mips / cp0_helper.c
blob36a92857bfb299f5a338077d460d4913d498ccf2
1 /*
2 * Helpers for emulation of CP0-related MIPS instructions.
4 * Copyright (C) 2004-2005 Jocelyn Mayer
5 * Copyright (C) 2020 Wave Computing, Inc.
6 * Copyright (C) 2020 Aleksandar Markovic <amarkovic@wavecomp.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 #include "qemu/osdep.h"
24 #include "qemu/log.h"
25 #include "qemu/main-loop.h"
26 #include "cpu.h"
27 #include "internal.h"
28 #include "qemu/host-utils.h"
29 #include "exec/helper-proto.h"
30 #include "exec/exec-all.h"
33 /* SMP helpers. */
34 static bool mips_vpe_is_wfi(MIPSCPU *c)
36 CPUState *cpu = CPU(c);
37 CPUMIPSState *env = &c->env;
40 * If the VPE is halted but otherwise active, it means it's waiting for
41 * an interrupt.\
43 return cpu->halted && mips_vpe_active(env);
46 static bool mips_vp_is_wfi(MIPSCPU *c)
48 CPUState *cpu = CPU(c);
49 CPUMIPSState *env = &c->env;
51 return cpu->halted && mips_vp_active(env);
54 static inline void mips_vpe_wake(MIPSCPU *c)
57 * Don't set ->halted = 0 directly, let it be done via cpu_has_work
58 * because there might be other conditions that state that c should
59 * be sleeping.
61 qemu_mutex_lock_iothread();
62 cpu_interrupt(CPU(c), CPU_INTERRUPT_WAKE);
63 qemu_mutex_unlock_iothread();
66 static inline void mips_vpe_sleep(MIPSCPU *cpu)
68 CPUState *cs = CPU(cpu);
71 * The VPE was shut off, really go to bed.
72 * Reset any old _WAKE requests.
74 cs->halted = 1;
75 cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
78 static inline void mips_tc_wake(MIPSCPU *cpu, int tc)
80 CPUMIPSState *c = &cpu->env;
82 /* FIXME: TC reschedule. */
83 if (mips_vpe_active(c) && !mips_vpe_is_wfi(cpu)) {
84 mips_vpe_wake(cpu);
88 static inline void mips_tc_sleep(MIPSCPU *cpu, int tc)
90 CPUMIPSState *c = &cpu->env;
92 /* FIXME: TC reschedule. */
93 if (!mips_vpe_active(c)) {
94 mips_vpe_sleep(cpu);
98 /**
99 * mips_cpu_map_tc:
100 * @env: CPU from which mapping is performed.
101 * @tc: Should point to an int with the value of the global TC index.
103 * This function will transform @tc into a local index within the
104 * returned #CPUMIPSState.
108 * FIXME: This code assumes that all VPEs have the same number of TCs,
109 * which depends on runtime setup. Can probably be fixed by
110 * walking the list of CPUMIPSStates.
112 static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc)
114 MIPSCPU *cpu;
115 CPUState *cs;
116 CPUState *other_cs;
117 int vpe_idx;
118 int tc_idx = *tc;
120 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))) {
121 /* Not allowed to address other CPUs. */
122 *tc = env->current_tc;
123 return env;
126 cs = env_cpu(env);
127 vpe_idx = tc_idx / cs->nr_threads;
128 *tc = tc_idx % cs->nr_threads;
129 other_cs = qemu_get_cpu(vpe_idx);
130 if (other_cs == NULL) {
131 return env;
133 cpu = MIPS_CPU(other_cs);
134 return &cpu->env;
138 * The per VPE CP0_Status register shares some fields with the per TC
139 * CP0_TCStatus registers. These fields are wired to the same registers,
140 * so changes to either of them should be reflected on both registers.
142 * Also, EntryHi shares the bottom 8 bit ASID with TCStauts.
144 * These helper call synchronizes the regs for a given cpu.
148 * Called for updates to CP0_Status. Defined in "cpu.h" for gdbstub.c.
149 * static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu,
150 * int tc);
153 /* Called for updates to CP0_TCStatus. */
154 static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc,
155 target_ulong v)
157 uint32_t status;
158 uint32_t tcu, tmx, tasid, tksu;
159 uint32_t mask = ((1U << CP0St_CU3)
160 | (1 << CP0St_CU2)
161 | (1 << CP0St_CU1)
162 | (1 << CP0St_CU0)
163 | (1 << CP0St_MX)
164 | (3 << CP0St_KSU));
166 tcu = (v >> CP0TCSt_TCU0) & 0xf;
167 tmx = (v >> CP0TCSt_TMX) & 0x1;
168 tasid = v & cpu->CP0_EntryHi_ASID_mask;
169 tksu = (v >> CP0TCSt_TKSU) & 0x3;
171 status = tcu << CP0St_CU0;
172 status |= tmx << CP0St_MX;
173 status |= tksu << CP0St_KSU;
175 cpu->CP0_Status &= ~mask;
176 cpu->CP0_Status |= status;
178 /* Sync the TASID with EntryHi. */
179 cpu->CP0_EntryHi &= ~cpu->CP0_EntryHi_ASID_mask;
180 cpu->CP0_EntryHi |= tasid;
182 compute_hflags(cpu);
185 /* Called for updates to CP0_EntryHi. */
186 static void sync_c0_entryhi(CPUMIPSState *cpu, int tc)
188 int32_t *tcst;
189 uint32_t asid, v = cpu->CP0_EntryHi;
191 asid = v & cpu->CP0_EntryHi_ASID_mask;
193 if (tc == cpu->current_tc) {
194 tcst = &cpu->active_tc.CP0_TCStatus;
195 } else {
196 tcst = &cpu->tcs[tc].CP0_TCStatus;
199 *tcst &= ~cpu->CP0_EntryHi_ASID_mask;
200 *tcst |= asid;
203 /* XXX: do not use a global */
204 uint32_t cpu_mips_get_random(CPUMIPSState *env)
206 static uint32_t seed = 1;
207 static uint32_t prev_idx;
208 uint32_t idx;
209 uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
211 if (nb_rand_tlb == 1) {
212 return env->tlb->nb_tlb - 1;
215 /* Don't return same value twice, so get another value */
216 do {
218 * Use a simple algorithm of Linear Congruential Generator
219 * from ISO/IEC 9899 standard.
221 seed = 1103515245 * seed + 12345;
222 idx = (seed >> 16) % nb_rand_tlb + env->CP0_Wired;
223 } while (idx == prev_idx);
224 prev_idx = idx;
225 return idx;
228 /* CP0 helpers */
229 target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env)
231 return env->mvp->CP0_MVPControl;
234 target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env)
236 return env->mvp->CP0_MVPConf0;
239 target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env)
241 return env->mvp->CP0_MVPConf1;
244 target_ulong helper_mfc0_random(CPUMIPSState *env)
246 return (int32_t)cpu_mips_get_random(env);
249 target_ulong helper_mfc0_tcstatus(CPUMIPSState *env)
251 return env->active_tc.CP0_TCStatus;
254 target_ulong helper_mftc0_tcstatus(CPUMIPSState *env)
256 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
257 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
259 if (other_tc == other->current_tc) {
260 return other->active_tc.CP0_TCStatus;
261 } else {
262 return other->tcs[other_tc].CP0_TCStatus;
266 target_ulong helper_mfc0_tcbind(CPUMIPSState *env)
268 return env->active_tc.CP0_TCBind;
271 target_ulong helper_mftc0_tcbind(CPUMIPSState *env)
273 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
274 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
276 if (other_tc == other->current_tc) {
277 return other->active_tc.CP0_TCBind;
278 } else {
279 return other->tcs[other_tc].CP0_TCBind;
283 target_ulong helper_mfc0_tcrestart(CPUMIPSState *env)
285 return env->active_tc.PC;
288 target_ulong helper_mftc0_tcrestart(CPUMIPSState *env)
290 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
291 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
293 if (other_tc == other->current_tc) {
294 return other->active_tc.PC;
295 } else {
296 return other->tcs[other_tc].PC;
300 target_ulong helper_mfc0_tchalt(CPUMIPSState *env)
302 return env->active_tc.CP0_TCHalt;
305 target_ulong helper_mftc0_tchalt(CPUMIPSState *env)
307 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
308 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
310 if (other_tc == other->current_tc) {
311 return other->active_tc.CP0_TCHalt;
312 } else {
313 return other->tcs[other_tc].CP0_TCHalt;
317 target_ulong helper_mfc0_tccontext(CPUMIPSState *env)
319 return env->active_tc.CP0_TCContext;
322 target_ulong helper_mftc0_tccontext(CPUMIPSState *env)
324 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
325 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
327 if (other_tc == other->current_tc) {
328 return other->active_tc.CP0_TCContext;
329 } else {
330 return other->tcs[other_tc].CP0_TCContext;
334 target_ulong helper_mfc0_tcschedule(CPUMIPSState *env)
336 return env->active_tc.CP0_TCSchedule;
339 target_ulong helper_mftc0_tcschedule(CPUMIPSState *env)
341 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
342 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
344 if (other_tc == other->current_tc) {
345 return other->active_tc.CP0_TCSchedule;
346 } else {
347 return other->tcs[other_tc].CP0_TCSchedule;
351 target_ulong helper_mfc0_tcschefback(CPUMIPSState *env)
353 return env->active_tc.CP0_TCScheFBack;
356 target_ulong helper_mftc0_tcschefback(CPUMIPSState *env)
358 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
359 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
361 if (other_tc == other->current_tc) {
362 return other->active_tc.CP0_TCScheFBack;
363 } else {
364 return other->tcs[other_tc].CP0_TCScheFBack;
368 target_ulong helper_mfc0_count(CPUMIPSState *env)
370 return (int32_t)cpu_mips_get_count(env);
373 target_ulong helper_mfc0_saar(CPUMIPSState *env)
375 if ((env->CP0_SAARI & 0x3f) < 2) {
376 return (int32_t) env->CP0_SAAR[env->CP0_SAARI & 0x3f];
378 return 0;
381 target_ulong helper_mfhc0_saar(CPUMIPSState *env)
383 if ((env->CP0_SAARI & 0x3f) < 2) {
384 return env->CP0_SAAR[env->CP0_SAARI & 0x3f] >> 32;
386 return 0;
389 target_ulong helper_mftc0_entryhi(CPUMIPSState *env)
391 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
392 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
394 return other->CP0_EntryHi;
397 target_ulong helper_mftc0_cause(CPUMIPSState *env)
399 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
400 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
402 return other->CP0_Cause;
405 target_ulong helper_mftc0_status(CPUMIPSState *env)
407 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
408 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
410 return other->CP0_Status;
413 target_ulong helper_mfc0_lladdr(CPUMIPSState *env)
415 return (int32_t)(env->CP0_LLAddr >> env->CP0_LLAddr_shift);
418 target_ulong helper_mfc0_maar(CPUMIPSState *env)
420 return (int32_t) env->CP0_MAAR[env->CP0_MAARI];
423 target_ulong helper_mfhc0_maar(CPUMIPSState *env)
425 return env->CP0_MAAR[env->CP0_MAARI] >> 32;
428 target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel)
430 return (int32_t)env->CP0_WatchLo[sel];
433 target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel)
435 return (int32_t) env->CP0_WatchHi[sel];
438 target_ulong helper_mfhc0_watchhi(CPUMIPSState *env, uint32_t sel)
440 return env->CP0_WatchHi[sel] >> 32;
443 target_ulong helper_mfc0_debug(CPUMIPSState *env)
445 target_ulong t0 = env->CP0_Debug;
446 if (env->hflags & MIPS_HFLAG_DM) {
447 t0 |= 1 << CP0DB_DM;
450 return t0;
453 target_ulong helper_mftc0_debug(CPUMIPSState *env)
455 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
456 int32_t tcstatus;
457 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
459 if (other_tc == other->current_tc) {
460 tcstatus = other->active_tc.CP0_Debug_tcstatus;
461 } else {
462 tcstatus = other->tcs[other_tc].CP0_Debug_tcstatus;
465 /* XXX: Might be wrong, check with EJTAG spec. */
466 return (other->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
467 (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
470 #if defined(TARGET_MIPS64)
471 target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env)
473 return env->active_tc.PC;
476 target_ulong helper_dmfc0_tchalt(CPUMIPSState *env)
478 return env->active_tc.CP0_TCHalt;
481 target_ulong helper_dmfc0_tccontext(CPUMIPSState *env)
483 return env->active_tc.CP0_TCContext;
486 target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env)
488 return env->active_tc.CP0_TCSchedule;
491 target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env)
493 return env->active_tc.CP0_TCScheFBack;
496 target_ulong helper_dmfc0_lladdr(CPUMIPSState *env)
498 return env->CP0_LLAddr >> env->CP0_LLAddr_shift;
501 target_ulong helper_dmfc0_maar(CPUMIPSState *env)
503 return env->CP0_MAAR[env->CP0_MAARI];
506 target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
508 return env->CP0_WatchLo[sel];
511 target_ulong helper_dmfc0_watchhi(CPUMIPSState *env, uint32_t sel)
513 return env->CP0_WatchHi[sel];
516 target_ulong helper_dmfc0_saar(CPUMIPSState *env)
518 if ((env->CP0_SAARI & 0x3f) < 2) {
519 return env->CP0_SAAR[env->CP0_SAARI & 0x3f];
521 return 0;
523 #endif /* TARGET_MIPS64 */
525 void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
527 uint32_t index_p = env->CP0_Index & 0x80000000;
528 uint32_t tlb_index = arg1 & 0x7fffffff;
529 if (tlb_index < env->tlb->nb_tlb) {
530 if (env->insn_flags & ISA_MIPS32R6) {
531 index_p |= arg1 & 0x80000000;
533 env->CP0_Index = index_p | tlb_index;
537 void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
539 uint32_t mask = 0;
540 uint32_t newval;
542 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
543 mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
544 (1 << CP0MVPCo_EVP);
546 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) {
547 mask |= (1 << CP0MVPCo_STLB);
549 newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
551 /* TODO: Enable/disable shared TLB, enable/disable VPEs. */
553 env->mvp->CP0_MVPControl = newval;
556 void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
558 uint32_t mask;
559 uint32_t newval;
561 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
562 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
563 newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
566 * Yield scheduler intercept not implemented.
567 * Gating storage scheduler intercept not implemented.
570 /* TODO: Enable/disable TCs. */
572 env->CP0_VPEControl = newval;
575 void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1)
577 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
578 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
579 uint32_t mask;
580 uint32_t newval;
582 mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
583 (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
584 newval = (other->CP0_VPEControl & ~mask) | (arg1 & mask);
586 /* TODO: Enable/disable TCs. */
588 other->CP0_VPEControl = newval;
591 target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env)
593 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
594 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
595 /* FIXME: Mask away return zero on read bits. */
596 return other->CP0_VPEControl;
599 target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env)
601 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
602 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
604 return other->CP0_VPEConf0;
607 void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
609 uint32_t mask = 0;
610 uint32_t newval;
612 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
613 if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA)) {
614 mask |= (0xff << CP0VPEC0_XTC);
616 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
618 newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
620 /* TODO: TC exclusive handling due to ERL/EXL. */
622 env->CP0_VPEConf0 = newval;
625 void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1)
627 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
628 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
629 uint32_t mask = 0;
630 uint32_t newval;
632 mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
633 newval = (other->CP0_VPEConf0 & ~mask) | (arg1 & mask);
635 /* TODO: TC exclusive handling due to ERL/EXL. */
636 other->CP0_VPEConf0 = newval;
639 void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1)
641 uint32_t mask = 0;
642 uint32_t newval;
644 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
645 mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
646 (0xff << CP0VPEC1_NCP1);
647 newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
649 /* UDI not implemented. */
650 /* CP2 not implemented. */
652 /* TODO: Handle FPU (CP1) binding. */
654 env->CP0_VPEConf1 = newval;
657 void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1)
659 /* Yield qualifier inputs not implemented. */
660 env->CP0_YQMask = 0x00000000;
663 void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1)
665 env->CP0_VPEOpt = arg1 & 0x0000ffff;
668 #define MTC0_ENTRYLO_MASK(env) ((env->PAMask >> 6) & 0x3FFFFFFF)
670 void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1)
672 /* 1k pages not implemented */
673 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
674 env->CP0_EntryLo0 = (arg1 & MTC0_ENTRYLO_MASK(env))
675 | (rxi << (CP0EnLo_XI - 30));
678 #if defined(TARGET_MIPS64)
679 #define DMTC0_ENTRYLO_MASK(env) (env->PAMask >> 6)
681 void helper_dmtc0_entrylo0(CPUMIPSState *env, uint64_t arg1)
683 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
684 env->CP0_EntryLo0 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
686 #endif
688 void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
690 uint32_t mask = env->CP0_TCStatus_rw_bitmask;
691 uint32_t newval;
693 newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
695 env->active_tc.CP0_TCStatus = newval;
696 sync_c0_tcstatus(env, env->current_tc, newval);
699 void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1)
701 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
702 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
704 if (other_tc == other->current_tc) {
705 other->active_tc.CP0_TCStatus = arg1;
706 } else {
707 other->tcs[other_tc].CP0_TCStatus = arg1;
709 sync_c0_tcstatus(other, other_tc, arg1);
712 void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1)
714 uint32_t mask = (1 << CP0TCBd_TBE);
715 uint32_t newval;
717 if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) {
718 mask |= (1 << CP0TCBd_CurVPE);
720 newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
721 env->active_tc.CP0_TCBind = newval;
724 void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1)
726 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
727 uint32_t mask = (1 << CP0TCBd_TBE);
728 uint32_t newval;
729 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
731 if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) {
732 mask |= (1 << CP0TCBd_CurVPE);
734 if (other_tc == other->current_tc) {
735 newval = (other->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
736 other->active_tc.CP0_TCBind = newval;
737 } else {
738 newval = (other->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
739 other->tcs[other_tc].CP0_TCBind = newval;
743 void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
745 env->active_tc.PC = arg1;
746 env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
747 env->CP0_LLAddr = 0;
748 env->lladdr = 0;
749 /* MIPS16 not implemented. */
752 void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1)
754 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
755 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
757 if (other_tc == other->current_tc) {
758 other->active_tc.PC = arg1;
759 other->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
760 other->CP0_LLAddr = 0;
761 other->lladdr = 0;
762 /* MIPS16 not implemented. */
763 } else {
764 other->tcs[other_tc].PC = arg1;
765 other->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
766 other->CP0_LLAddr = 0;
767 other->lladdr = 0;
768 /* MIPS16 not implemented. */
772 void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1)
774 MIPSCPU *cpu = env_archcpu(env);
776 env->active_tc.CP0_TCHalt = arg1 & 0x1;
778 /* TODO: Halt TC / Restart (if allocated+active) TC. */
779 if (env->active_tc.CP0_TCHalt & 1) {
780 mips_tc_sleep(cpu, env->current_tc);
781 } else {
782 mips_tc_wake(cpu, env->current_tc);
786 void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1)
788 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
789 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
790 MIPSCPU *other_cpu = env_archcpu(other);
792 /* TODO: Halt TC / Restart (if allocated+active) TC. */
794 if (other_tc == other->current_tc) {
795 other->active_tc.CP0_TCHalt = arg1;
796 } else {
797 other->tcs[other_tc].CP0_TCHalt = arg1;
800 if (arg1 & 1) {
801 mips_tc_sleep(other_cpu, other_tc);
802 } else {
803 mips_tc_wake(other_cpu, other_tc);
807 void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1)
809 env->active_tc.CP0_TCContext = arg1;
812 void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1)
814 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
815 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
817 if (other_tc == other->current_tc) {
818 other->active_tc.CP0_TCContext = arg1;
819 } else {
820 other->tcs[other_tc].CP0_TCContext = arg1;
824 void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
826 env->active_tc.CP0_TCSchedule = arg1;
829 void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1)
831 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
832 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
834 if (other_tc == other->current_tc) {
835 other->active_tc.CP0_TCSchedule = arg1;
836 } else {
837 other->tcs[other_tc].CP0_TCSchedule = arg1;
841 void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
843 env->active_tc.CP0_TCScheFBack = arg1;
846 void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1)
848 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
849 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
851 if (other_tc == other->current_tc) {
852 other->active_tc.CP0_TCScheFBack = arg1;
853 } else {
854 other->tcs[other_tc].CP0_TCScheFBack = arg1;
858 void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1)
860 /* 1k pages not implemented */
861 target_ulong rxi = arg1 & (env->CP0_PageGrain & (3u << CP0PG_XIE));
862 env->CP0_EntryLo1 = (arg1 & MTC0_ENTRYLO_MASK(env))
863 | (rxi << (CP0EnLo_XI - 30));
866 #if defined(TARGET_MIPS64)
867 void helper_dmtc0_entrylo1(CPUMIPSState *env, uint64_t arg1)
869 uint64_t rxi = arg1 & ((env->CP0_PageGrain & (3ull << CP0PG_XIE)) << 32);
870 env->CP0_EntryLo1 = (arg1 & DMTC0_ENTRYLO_MASK(env)) | rxi;
872 #endif
874 void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
876 env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
879 void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1)
881 int32_t old;
882 old = env->CP0_MemoryMapID;
883 env->CP0_MemoryMapID = (int32_t) arg1;
884 /* If the MemoryMapID changes, flush qemu's TLB. */
885 if (old != env->CP0_MemoryMapID) {
886 cpu_mips_tlb_flush(env);
890 void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask)
892 uint32_t mask;
893 int maskbits;
895 /* Don't care MASKX as we don't support 1KB page */
896 mask = extract32((uint32_t)arg1, CP0PM_MASK, 16);
897 maskbits = cto32(mask);
899 /* Ensure no more set bit after first zero */
900 if ((mask >> maskbits) != 0) {
901 goto invalid;
903 /* We don't support VTLB entry smaller than target page */
904 if ((maskbits + TARGET_PAGE_BITS_MIN) < TARGET_PAGE_BITS) {
905 goto invalid;
907 env->CP0_PageMask = mask << CP0PM_MASK;
909 return;
911 invalid:
912 /* When invalid, set to default target page size. */
913 mask = (~TARGET_PAGE_MASK >> TARGET_PAGE_BITS_MIN);
914 env->CP0_PageMask = mask << CP0PM_MASK;
917 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
919 update_pagemask(env, arg1, &env->CP0_PageMask);
922 void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
924 /* SmartMIPS not implemented */
925 /* 1k pages not implemented */
926 env->CP0_PageGrain = (arg1 & env->CP0_PageGrain_rw_bitmask) |
927 (env->CP0_PageGrain & ~env->CP0_PageGrain_rw_bitmask);
928 compute_hflags(env);
929 restore_pamask(env);
932 void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
934 CPUState *cs = env_cpu(env);
936 env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
937 tlb_flush(cs);
940 void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
942 CPUState *cs = env_cpu(env);
944 env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
945 tlb_flush(cs);
948 void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
950 CPUState *cs = env_cpu(env);
952 env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
953 tlb_flush(cs);
956 void helper_mtc0_pwfield(CPUMIPSState *env, target_ulong arg1)
958 #if defined(TARGET_MIPS64)
959 uint64_t mask = 0x3F3FFFFFFFULL;
960 uint32_t old_ptei = (env->CP0_PWField >> CP0PF_PTEI) & 0x3FULL;
961 uint32_t new_ptei = (arg1 >> CP0PF_PTEI) & 0x3FULL;
963 if ((env->insn_flags & ISA_MIPS32R6)) {
964 if (((arg1 >> CP0PF_BDI) & 0x3FULL) < 12) {
965 mask &= ~(0x3FULL << CP0PF_BDI);
967 if (((arg1 >> CP0PF_GDI) & 0x3FULL) < 12) {
968 mask &= ~(0x3FULL << CP0PF_GDI);
970 if (((arg1 >> CP0PF_UDI) & 0x3FULL) < 12) {
971 mask &= ~(0x3FULL << CP0PF_UDI);
973 if (((arg1 >> CP0PF_MDI) & 0x3FULL) < 12) {
974 mask &= ~(0x3FULL << CP0PF_MDI);
976 if (((arg1 >> CP0PF_PTI) & 0x3FULL) < 12) {
977 mask &= ~(0x3FULL << CP0PF_PTI);
980 env->CP0_PWField = arg1 & mask;
982 if ((new_ptei >= 32) ||
983 ((env->insn_flags & ISA_MIPS32R6) &&
984 (new_ptei == 0 || new_ptei == 1))) {
985 env->CP0_PWField = (env->CP0_PWField & ~0x3FULL) |
986 (old_ptei << CP0PF_PTEI);
988 #else
989 uint32_t mask = 0x3FFFFFFF;
990 uint32_t old_ptew = (env->CP0_PWField >> CP0PF_PTEW) & 0x3F;
991 uint32_t new_ptew = (arg1 >> CP0PF_PTEW) & 0x3F;
993 if ((env->insn_flags & ISA_MIPS32R6)) {
994 if (((arg1 >> CP0PF_GDW) & 0x3F) < 12) {
995 mask &= ~(0x3F << CP0PF_GDW);
997 if (((arg1 >> CP0PF_UDW) & 0x3F) < 12) {
998 mask &= ~(0x3F << CP0PF_UDW);
1000 if (((arg1 >> CP0PF_MDW) & 0x3F) < 12) {
1001 mask &= ~(0x3F << CP0PF_MDW);
1003 if (((arg1 >> CP0PF_PTW) & 0x3F) < 12) {
1004 mask &= ~(0x3F << CP0PF_PTW);
1007 env->CP0_PWField = arg1 & mask;
1009 if ((new_ptew >= 32) ||
1010 ((env->insn_flags & ISA_MIPS32R6) &&
1011 (new_ptew == 0 || new_ptew == 1))) {
1012 env->CP0_PWField = (env->CP0_PWField & ~0x3F) |
1013 (old_ptew << CP0PF_PTEW);
1015 #endif
1018 void helper_mtc0_pwsize(CPUMIPSState *env, target_ulong arg1)
1020 #if defined(TARGET_MIPS64)
1021 env->CP0_PWSize = arg1 & 0x3F7FFFFFFFULL;
1022 #else
1023 env->CP0_PWSize = arg1 & 0x3FFFFFFF;
1024 #endif
1027 void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
1029 if (env->insn_flags & ISA_MIPS32R6) {
1030 if (arg1 < env->tlb->nb_tlb) {
1031 env->CP0_Wired = arg1;
1033 } else {
1034 env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1038 void helper_mtc0_pwctl(CPUMIPSState *env, target_ulong arg1)
1040 #if defined(TARGET_MIPS64)
1041 /* PWEn = 0. Hardware page table walking is not implemented. */
1042 env->CP0_PWCtl = (env->CP0_PWCtl & 0x000000C0) | (arg1 & 0x5C00003F);
1043 #else
1044 env->CP0_PWCtl = (arg1 & 0x800000FF);
1045 #endif
1048 void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
1050 env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1053 void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1)
1055 env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1058 void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1)
1060 env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1063 void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1)
1065 env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1068 void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1)
1070 env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1073 void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1)
1075 uint32_t mask = 0x0000000F;
1077 if ((env->CP0_Config1 & (1 << CP0C1_PC)) &&
1078 (env->insn_flags & ISA_MIPS32R6)) {
1079 mask |= (1 << 4);
1081 if (env->insn_flags & ISA_MIPS32R6) {
1082 mask |= (1 << 5);
1084 if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
1085 mask |= (1 << 29);
1087 if (arg1 & (1 << 29)) {
1088 env->hflags |= MIPS_HFLAG_HWRENA_ULR;
1089 } else {
1090 env->hflags &= ~MIPS_HFLAG_HWRENA_ULR;
1094 env->CP0_HWREna = arg1 & mask;
1097 void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
1099 cpu_mips_store_count(env, arg1);
1102 void helper_mtc0_saari(CPUMIPSState *env, target_ulong arg1)
1104 uint32_t target = arg1 & 0x3f;
1105 if (target <= 1) {
1106 env->CP0_SAARI = target;
1110 void helper_mtc0_saar(CPUMIPSState *env, target_ulong arg1)
1112 uint32_t target = env->CP0_SAARI & 0x3f;
1113 if (target < 2) {
1114 env->CP0_SAAR[target] = arg1 & 0x00000ffffffff03fULL;
1115 switch (target) {
1116 case 0:
1117 if (env->itu) {
1118 itc_reconfigure(env->itu);
1120 break;
1125 void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1)
1127 uint32_t target = env->CP0_SAARI & 0x3f;
1128 if (target < 2) {
1129 env->CP0_SAAR[target] =
1130 (((uint64_t) arg1 << 32) & 0x00000fff00000000ULL) |
1131 (env->CP0_SAAR[target] & 0x00000000ffffffffULL);
1132 switch (target) {
1133 case 0:
1134 if (env->itu) {
1135 itc_reconfigure(env->itu);
1137 break;
1142 void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1144 target_ulong old, val, mask;
1145 mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
1146 if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
1147 mask |= 1 << CP0EnHi_EHINV;
1150 /* 1k pages not implemented */
1151 #if defined(TARGET_MIPS64)
1152 if (env->insn_flags & ISA_MIPS32R6) {
1153 int entryhi_r = extract64(arg1, 62, 2);
1154 int config0_at = extract32(env->CP0_Config0, 13, 2);
1155 bool no_supervisor = (env->CP0_Status_rw_bitmask & 0x8) == 0;
1156 if ((entryhi_r == 2) ||
1157 (entryhi_r == 1 && (no_supervisor || config0_at == 1))) {
1158 /* skip EntryHi.R field if new value is reserved */
1159 mask &= ~(0x3ull << 62);
1162 mask &= env->SEGMask;
1163 #endif
1164 old = env->CP0_EntryHi;
1165 val = (arg1 & mask) | (old & ~mask);
1166 env->CP0_EntryHi = val;
1167 if (ase_mt_available(env)) {
1168 sync_c0_entryhi(env, env->current_tc);
1170 /* If the ASID changes, flush qemu's TLB. */
1171 if ((old & env->CP0_EntryHi_ASID_mask) !=
1172 (val & env->CP0_EntryHi_ASID_mask)) {
1173 tlb_flush(env_cpu(env));
1177 void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1)
1179 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1180 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1182 other->CP0_EntryHi = arg1;
1183 sync_c0_entryhi(other, other_tc);
1186 void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1)
1188 cpu_mips_store_compare(env, arg1);
1191 void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
1193 uint32_t val, old;
1195 old = env->CP0_Status;
1196 cpu_mips_store_status(env, arg1);
1197 val = env->CP0_Status;
1199 if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1200 qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1201 old, old & env->CP0_Cause & CP0Ca_IP_mask,
1202 val, val & env->CP0_Cause & CP0Ca_IP_mask,
1203 env->CP0_Cause);
1204 switch (cpu_mmu_index(env, false)) {
1205 case 3:
1206 qemu_log(", ERL\n");
1207 break;
1208 case MIPS_HFLAG_UM:
1209 qemu_log(", UM\n");
1210 break;
1211 case MIPS_HFLAG_SM:
1212 qemu_log(", SM\n");
1213 break;
1214 case MIPS_HFLAG_KM:
1215 qemu_log("\n");
1216 break;
1217 default:
1218 cpu_abort(env_cpu(env), "Invalid MMU mode!\n");
1219 break;
1224 void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
1226 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1227 uint32_t mask = env->CP0_Status_rw_bitmask & ~0xf1000018;
1228 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1230 other->CP0_Status = (other->CP0_Status & ~mask) | (arg1 & mask);
1231 sync_c0_status(env, other, other_tc);
1234 void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
1236 env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
1239 void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1)
1241 uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1242 env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1245 void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1)
1247 cpu_mips_store_cause(env, arg1);
1250 void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1)
1252 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1253 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1255 cpu_mips_store_cause(other, arg1);
1258 target_ulong helper_mftc0_epc(CPUMIPSState *env)
1260 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1261 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1263 return other->CP0_EPC;
1266 target_ulong helper_mftc0_ebase(CPUMIPSState *env)
1268 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1269 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1271 return other->CP0_EBase;
1274 void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
1276 target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1277 if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1278 mask |= ~0x3FFFFFFF;
1280 env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
1283 void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
1285 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1286 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1287 target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
1288 if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
1289 mask |= ~0x3FFFFFFF;
1291 other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
1294 target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
1296 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1297 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1299 switch (idx) {
1300 case 0: return other->CP0_Config0;
1301 case 1: return other->CP0_Config1;
1302 case 2: return other->CP0_Config2;
1303 case 3: return other->CP0_Config3;
1304 /* 4 and 5 are reserved. */
1305 case 6: return other->CP0_Config6;
1306 case 7: return other->CP0_Config7;
1307 default:
1308 break;
1310 return 0;
1313 void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1)
1315 env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1318 void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1)
1320 /* tertiary/secondary caches not implemented */
1321 env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1324 void helper_mtc0_config3(CPUMIPSState *env, target_ulong arg1)
1326 if (env->insn_flags & ASE_MICROMIPS) {
1327 env->CP0_Config3 = (env->CP0_Config3 & ~(1 << CP0C3_ISA_ON_EXC)) |
1328 (arg1 & (1 << CP0C3_ISA_ON_EXC));
1332 void helper_mtc0_config4(CPUMIPSState *env, target_ulong arg1)
1334 env->CP0_Config4 = (env->CP0_Config4 & (~env->CP0_Config4_rw_bitmask)) |
1335 (arg1 & env->CP0_Config4_rw_bitmask);
1338 void helper_mtc0_config5(CPUMIPSState *env, target_ulong arg1)
1340 env->CP0_Config5 = (env->CP0_Config5 & (~env->CP0_Config5_rw_bitmask)) |
1341 (arg1 & env->CP0_Config5_rw_bitmask);
1342 env->CP0_EntryHi_ASID_mask = (env->CP0_Config5 & (1 << CP0C5_MI)) ?
1343 0x0 : (env->CP0_Config4 & (1 << CP0C4_AE)) ? 0x3ff : 0xff;
1344 compute_hflags(env);
1347 void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1)
1349 target_long mask = env->CP0_LLAddr_rw_bitmask;
1350 arg1 = arg1 << env->CP0_LLAddr_shift;
1351 env->CP0_LLAddr = (env->CP0_LLAddr & ~mask) | (arg1 & mask);
1354 #define MTC0_MAAR_MASK(env) \
1355 ((0x1ULL << 63) | ((env->PAMask >> 4) & ~0xFFFull) | 0x3)
1357 void helper_mtc0_maar(CPUMIPSState *env, target_ulong arg1)
1359 env->CP0_MAAR[env->CP0_MAARI] = arg1 & MTC0_MAAR_MASK(env);
1362 void helper_mthc0_maar(CPUMIPSState *env, target_ulong arg1)
1364 env->CP0_MAAR[env->CP0_MAARI] =
1365 (((uint64_t) arg1 << 32) & MTC0_MAAR_MASK(env)) |
1366 (env->CP0_MAAR[env->CP0_MAARI] & 0x00000000ffffffffULL);
1369 void helper_mtc0_maari(CPUMIPSState *env, target_ulong arg1)
1371 int index = arg1 & 0x3f;
1372 if (index == 0x3f) {
1374 * Software may write all ones to INDEX to determine the
1375 * maximum value supported.
1377 env->CP0_MAARI = MIPS_MAAR_MAX - 1;
1378 } else if (index < MIPS_MAAR_MAX) {
1379 env->CP0_MAARI = index;
1382 * Other than the all ones, if the value written is not supported,
1383 * then INDEX is unchanged from its previous value.
1387 void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1390 * Watch exceptions for instructions, data loads, data stores
1391 * not implemented.
1393 env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1396 void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1398 uint64_t mask = 0x40000FF8 | (env->CP0_EntryHi_ASID_mask << CP0WH_ASID);
1399 if ((env->CP0_Config5 >> CP0C5_MI) & 1) {
1400 mask |= 0xFFFFFFFF00000000ULL; /* MMID */
1402 env->CP0_WatchHi[sel] = arg1 & mask;
1403 env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1406 void helper_mthc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1408 env->CP0_WatchHi[sel] = ((uint64_t) (arg1) << 32) |
1409 (env->CP0_WatchHi[sel] & 0x00000000ffffffffULL);
1412 void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1)
1414 target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1415 env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1418 void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1)
1420 env->CP0_Framemask = arg1; /* XXX */
1423 void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1)
1425 env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1426 if (arg1 & (1 << CP0DB_DM)) {
1427 env->hflags |= MIPS_HFLAG_DM;
1428 } else {
1429 env->hflags &= ~MIPS_HFLAG_DM;
1433 void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1)
1435 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1436 uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1437 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1439 /* XXX: Might be wrong, check with EJTAG spec. */
1440 if (other_tc == other->current_tc) {
1441 other->active_tc.CP0_Debug_tcstatus = val;
1442 } else {
1443 other->tcs[other_tc].CP0_Debug_tcstatus = val;
1445 other->CP0_Debug = (other->CP0_Debug &
1446 ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1447 (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1450 void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
1452 env->CP0_Performance0 = arg1 & 0x000007ff;
1455 void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
1457 int32_t wst = arg1 & (1 << CP0EC_WST);
1458 int32_t spr = arg1 & (1 << CP0EC_SPR);
1459 int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
1461 env->CP0_ErrCtl = wst | spr | itc;
1463 if (itc && !wst && !spr) {
1464 env->hflags |= MIPS_HFLAG_ITC_CACHE;
1465 } else {
1466 env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
1470 void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
1472 if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
1474 * If CACHE instruction is configured for ITC tags then make all
1475 * CP0.TagLo bits writable. The actual write to ITC Configuration
1476 * Tag will take care of the read-only bits.
1478 env->CP0_TagLo = arg1;
1479 } else {
1480 env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1484 void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
1486 env->CP0_DataLo = arg1; /* XXX */
1489 void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1)
1491 env->CP0_TagHi = arg1; /* XXX */
1494 void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1)
1496 env->CP0_DataHi = arg1; /* XXX */
1499 /* MIPS MT functions */
1500 target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel)
1502 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1503 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1505 if (other_tc == other->current_tc) {
1506 return other->active_tc.gpr[sel];
1507 } else {
1508 return other->tcs[other_tc].gpr[sel];
1512 target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel)
1514 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1515 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1517 if (other_tc == other->current_tc) {
1518 return other->active_tc.LO[sel];
1519 } else {
1520 return other->tcs[other_tc].LO[sel];
1524 target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel)
1526 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1527 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1529 if (other_tc == other->current_tc) {
1530 return other->active_tc.HI[sel];
1531 } else {
1532 return other->tcs[other_tc].HI[sel];
1536 target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel)
1538 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1539 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1541 if (other_tc == other->current_tc) {
1542 return other->active_tc.ACX[sel];
1543 } else {
1544 return other->tcs[other_tc].ACX[sel];
1548 target_ulong helper_mftdsp(CPUMIPSState *env)
1550 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1551 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1553 if (other_tc == other->current_tc) {
1554 return other->active_tc.DSPControl;
1555 } else {
1556 return other->tcs[other_tc].DSPControl;
1560 void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1562 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1563 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1565 if (other_tc == other->current_tc) {
1566 other->active_tc.gpr[sel] = arg1;
1567 } else {
1568 other->tcs[other_tc].gpr[sel] = arg1;
1572 void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1574 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1575 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1577 if (other_tc == other->current_tc) {
1578 other->active_tc.LO[sel] = arg1;
1579 } else {
1580 other->tcs[other_tc].LO[sel] = arg1;
1584 void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1586 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1587 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1589 if (other_tc == other->current_tc) {
1590 other->active_tc.HI[sel] = arg1;
1591 } else {
1592 other->tcs[other_tc].HI[sel] = arg1;
1596 void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel)
1598 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1599 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1601 if (other_tc == other->current_tc) {
1602 other->active_tc.ACX[sel] = arg1;
1603 } else {
1604 other->tcs[other_tc].ACX[sel] = arg1;
1608 void helper_mttdsp(CPUMIPSState *env, target_ulong arg1)
1610 int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1611 CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
1613 if (other_tc == other->current_tc) {
1614 other->active_tc.DSPControl = arg1;
1615 } else {
1616 other->tcs[other_tc].DSPControl = arg1;
1620 /* MIPS MT functions */
1621 target_ulong helper_dmt(void)
1623 /* TODO */
1624 return 0;
1627 target_ulong helper_emt(void)
1629 /* TODO */
1630 return 0;
1633 target_ulong helper_dvpe(CPUMIPSState *env)
1635 CPUState *other_cs = first_cpu;
1636 target_ulong prev = env->mvp->CP0_MVPControl;
1638 CPU_FOREACH(other_cs) {
1639 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1640 /* Turn off all VPEs except the one executing the dvpe. */
1641 if (&other_cpu->env != env) {
1642 other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
1643 mips_vpe_sleep(other_cpu);
1646 return prev;
1649 target_ulong helper_evpe(CPUMIPSState *env)
1651 CPUState *other_cs = first_cpu;
1652 target_ulong prev = env->mvp->CP0_MVPControl;
1654 CPU_FOREACH(other_cs) {
1655 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1657 if (&other_cpu->env != env
1658 /* If the VPE is WFI, don't disturb its sleep. */
1659 && !mips_vpe_is_wfi(other_cpu)) {
1660 /* Enable the VPE. */
1661 other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
1662 mips_vpe_wake(other_cpu); /* And wake it up. */
1665 return prev;
1668 /* R6 Multi-threading */
1669 target_ulong helper_dvp(CPUMIPSState *env)
1671 CPUState *other_cs = first_cpu;
1672 target_ulong prev = env->CP0_VPControl;
1674 if (!((env->CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
1675 CPU_FOREACH(other_cs) {
1676 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1677 /* Turn off all VPs except the one executing the dvp. */
1678 if (&other_cpu->env != env) {
1679 mips_vpe_sleep(other_cpu);
1682 env->CP0_VPControl |= (1 << CP0VPCtl_DIS);
1684 return prev;
1687 target_ulong helper_evp(CPUMIPSState *env)
1689 CPUState *other_cs = first_cpu;
1690 target_ulong prev = env->CP0_VPControl;
1692 if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
1693 CPU_FOREACH(other_cs) {
1694 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
1695 if ((&other_cpu->env != env) && !mips_vp_is_wfi(other_cpu)) {
1697 * If the VP is WFI, don't disturb its sleep.
1698 * Otherwise, wake it up.
1700 mips_vpe_wake(other_cpu);
1703 env->CP0_VPControl &= ~(1 << CP0VPCtl_DIS);
1705 return prev;