4 * Copyright (c) 2012 SUSE LINUX Products GmbH
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.
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.
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>
21 #include "qemu/osdep.h"
24 #include "exec/exec-all.h"
26 /* Called for updates to CP0_Status. */
27 void sync_c0_status(CPUMIPSState
*env
, CPUMIPSState
*cpu
, int tc
)
29 int32_t tcstatus
, *tcst
;
30 uint32_t v
= cpu
->CP0_Status
;
31 uint32_t cu
, mx
, asid
, ksu
;
32 uint32_t mask
= ((1 << CP0TCSt_TCU3
)
38 | (0xff << CP0TCSt_TASID
));
40 cu
= (v
>> CP0St_CU0
) & 0xf;
41 mx
= (v
>> CP0St_MX
) & 0x1;
42 ksu
= (v
>> CP0St_KSU
) & 0x3;
43 asid
= env
->CP0_EntryHi
& env
->CP0_EntryHi_ASID_mask
;
45 tcstatus
= cu
<< CP0TCSt_TCU0
;
46 tcstatus
|= mx
<< CP0TCSt_TMX
;
47 tcstatus
|= ksu
<< CP0TCSt_TKSU
;
50 if (tc
== cpu
->current_tc
) {
51 tcst
= &cpu
->active_tc
.CP0_TCStatus
;
53 tcst
= &cpu
->tcs
[tc
].CP0_TCStatus
;
61 void cpu_mips_store_status(CPUMIPSState
*env
, target_ulong val
)
63 uint32_t mask
= env
->CP0_Status_rw_bitmask
;
64 target_ulong old
= env
->CP0_Status
;
66 if (env
->insn_flags
& ISA_MIPS_R6
) {
67 bool has_supervisor
= extract32(mask
, CP0St_KSU
, 2) == 0x3;
68 #if defined(TARGET_MIPS64)
69 uint32_t ksux
= (1 << CP0St_KX
) & val
;
70 ksux
|= (ksux
>> 1) & val
; /* KX = 0 forces SX to be 0 */
71 ksux
|= (ksux
>> 1) & val
; /* SX = 0 forces UX to be 0 */
72 val
= (val
& ~(7 << CP0St_UX
)) | ksux
;
74 if (has_supervisor
&& extract32(val
, CP0St_KSU
, 2) == 0x3) {
75 mask
&= ~(3 << CP0St_KSU
);
77 mask
&= ~(((1 << CP0St_SR
) | (1 << CP0St_NMI
)) & val
);
80 env
->CP0_Status
= (old
& ~mask
) | (val
& mask
);
81 #if defined(TARGET_MIPS64)
82 if ((env
->CP0_Status
^ old
) & (old
& (7 << CP0St_UX
))) {
83 /* Access to at least one of the 64-bit segments has been disabled */
84 tlb_flush(env_cpu(env
));
87 if (ase_mt_available(env
)) {
88 sync_c0_status(env
, env
, env
->current_tc
);
94 void cpu_mips_store_cause(CPUMIPSState
*env
, target_ulong val
)
96 uint32_t mask
= 0x00C00300;
97 uint32_t old
= env
->CP0_Cause
;
100 if (env
->insn_flags
& ISA_MIPS_R2
) {
101 mask
|= 1 << CP0Ca_DC
;
103 if (env
->insn_flags
& ISA_MIPS_R6
) {
104 mask
&= ~((1 << CP0Ca_WP
) & val
);
107 env
->CP0_Cause
= (env
->CP0_Cause
& ~mask
) | (val
& mask
);
109 if ((old
^ env
->CP0_Cause
) & (1 << CP0Ca_DC
)) {
110 if (env
->CP0_Cause
& (1 << CP0Ca_DC
)) {
111 cpu_mips_stop_count(env
);
113 cpu_mips_start_count(env
);
117 /* Set/reset software interrupts */
118 for (i
= 0 ; i
< 2 ; i
++) {
119 if ((old
^ env
->CP0_Cause
) & (1 << (CP0Ca_IP
+ i
))) {
120 cpu_mips_soft_irq(env
, i
, env
->CP0_Cause
& (1 << (CP0Ca_IP
+ i
)));