1*5679479bSPhilippe Mathieu-Daudé /* 2*5679479bSPhilippe Mathieu-Daudé * QEMU MIPS CPU 3*5679479bSPhilippe Mathieu-Daudé * 4*5679479bSPhilippe Mathieu-Daudé * Copyright (c) 2012 SUSE LINUX Products GmbH 5*5679479bSPhilippe Mathieu-Daudé * 6*5679479bSPhilippe Mathieu-Daudé * This library is free software; you can redistribute it and/or 7*5679479bSPhilippe Mathieu-Daudé * modify it under the terms of the GNU Lesser General Public 8*5679479bSPhilippe Mathieu-Daudé * License as published by the Free Software Foundation; either 9*5679479bSPhilippe Mathieu-Daudé * version 2.1 of the License, or (at your option) any later version. 10*5679479bSPhilippe Mathieu-Daudé * 11*5679479bSPhilippe Mathieu-Daudé * This library is distributed in the hope that it will be useful, 12*5679479bSPhilippe Mathieu-Daudé * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*5679479bSPhilippe Mathieu-Daudé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*5679479bSPhilippe Mathieu-Daudé * Lesser General Public License for more details. 15*5679479bSPhilippe Mathieu-Daudé * 16*5679479bSPhilippe Mathieu-Daudé * You should have received a copy of the GNU Lesser General Public 17*5679479bSPhilippe Mathieu-Daudé * License along with this library; if not, see 18*5679479bSPhilippe Mathieu-Daudé * <http://www.gnu.org/licenses/lgpl-2.1.html> 19*5679479bSPhilippe Mathieu-Daudé */ 20*5679479bSPhilippe Mathieu-Daudé 21*5679479bSPhilippe Mathieu-Daudé #include "qemu/osdep.h" 22*5679479bSPhilippe Mathieu-Daudé #include "cpu.h" 23*5679479bSPhilippe Mathieu-Daudé #include "internal.h" 24*5679479bSPhilippe Mathieu-Daudé #include "exec/exec-all.h" 25*5679479bSPhilippe Mathieu-Daudé 26*5679479bSPhilippe Mathieu-Daudé /* Called for updates to CP0_Status. */ 27*5679479bSPhilippe Mathieu-Daudé void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) 28*5679479bSPhilippe Mathieu-Daudé { 29*5679479bSPhilippe Mathieu-Daudé int32_t tcstatus, *tcst; 30*5679479bSPhilippe Mathieu-Daudé uint32_t v = cpu->CP0_Status; 31*5679479bSPhilippe Mathieu-Daudé uint32_t cu, mx, asid, ksu; 32*5679479bSPhilippe Mathieu-Daudé uint32_t mask = ((1 << CP0TCSt_TCU3) 33*5679479bSPhilippe Mathieu-Daudé | (1 << CP0TCSt_TCU2) 34*5679479bSPhilippe Mathieu-Daudé | (1 << CP0TCSt_TCU1) 35*5679479bSPhilippe Mathieu-Daudé | (1 << CP0TCSt_TCU0) 36*5679479bSPhilippe Mathieu-Daudé | (1 << CP0TCSt_TMX) 37*5679479bSPhilippe Mathieu-Daudé | (3 << CP0TCSt_TKSU) 38*5679479bSPhilippe Mathieu-Daudé | (0xff << CP0TCSt_TASID)); 39*5679479bSPhilippe Mathieu-Daudé 40*5679479bSPhilippe Mathieu-Daudé cu = (v >> CP0St_CU0) & 0xf; 41*5679479bSPhilippe Mathieu-Daudé mx = (v >> CP0St_MX) & 0x1; 42*5679479bSPhilippe Mathieu-Daudé ksu = (v >> CP0St_KSU) & 0x3; 43*5679479bSPhilippe Mathieu-Daudé asid = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask; 44*5679479bSPhilippe Mathieu-Daudé 45*5679479bSPhilippe Mathieu-Daudé tcstatus = cu << CP0TCSt_TCU0; 46*5679479bSPhilippe Mathieu-Daudé tcstatus |= mx << CP0TCSt_TMX; 47*5679479bSPhilippe Mathieu-Daudé tcstatus |= ksu << CP0TCSt_TKSU; 48*5679479bSPhilippe Mathieu-Daudé tcstatus |= asid; 49*5679479bSPhilippe Mathieu-Daudé 50*5679479bSPhilippe Mathieu-Daudé if (tc == cpu->current_tc) { 51*5679479bSPhilippe Mathieu-Daudé tcst = &cpu->active_tc.CP0_TCStatus; 52*5679479bSPhilippe Mathieu-Daudé } else { 53*5679479bSPhilippe Mathieu-Daudé tcst = &cpu->tcs[tc].CP0_TCStatus; 54*5679479bSPhilippe Mathieu-Daudé } 55*5679479bSPhilippe Mathieu-Daudé 56*5679479bSPhilippe Mathieu-Daudé *tcst &= ~mask; 57*5679479bSPhilippe Mathieu-Daudé *tcst |= tcstatus; 58*5679479bSPhilippe Mathieu-Daudé compute_hflags(cpu); 59*5679479bSPhilippe Mathieu-Daudé } 60*5679479bSPhilippe Mathieu-Daudé 61*5679479bSPhilippe Mathieu-Daudé void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) 62*5679479bSPhilippe Mathieu-Daudé { 63*5679479bSPhilippe Mathieu-Daudé uint32_t mask = env->CP0_Status_rw_bitmask; 64*5679479bSPhilippe Mathieu-Daudé target_ulong old = env->CP0_Status; 65*5679479bSPhilippe Mathieu-Daudé 66*5679479bSPhilippe Mathieu-Daudé if (env->insn_flags & ISA_MIPS_R6) { 67*5679479bSPhilippe Mathieu-Daudé bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; 68*5679479bSPhilippe Mathieu-Daudé #if defined(TARGET_MIPS64) 69*5679479bSPhilippe Mathieu-Daudé uint32_t ksux = (1 << CP0St_KX) & val; 70*5679479bSPhilippe Mathieu-Daudé ksux |= (ksux >> 1) & val; /* KX = 0 forces SX to be 0 */ 71*5679479bSPhilippe Mathieu-Daudé ksux |= (ksux >> 1) & val; /* SX = 0 forces UX to be 0 */ 72*5679479bSPhilippe Mathieu-Daudé val = (val & ~(7 << CP0St_UX)) | ksux; 73*5679479bSPhilippe Mathieu-Daudé #endif 74*5679479bSPhilippe Mathieu-Daudé if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) { 75*5679479bSPhilippe Mathieu-Daudé mask &= ~(3 << CP0St_KSU); 76*5679479bSPhilippe Mathieu-Daudé } 77*5679479bSPhilippe Mathieu-Daudé mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); 78*5679479bSPhilippe Mathieu-Daudé } 79*5679479bSPhilippe Mathieu-Daudé 80*5679479bSPhilippe Mathieu-Daudé env->CP0_Status = (old & ~mask) | (val & mask); 81*5679479bSPhilippe Mathieu-Daudé #if defined(TARGET_MIPS64) 82*5679479bSPhilippe Mathieu-Daudé if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) { 83*5679479bSPhilippe Mathieu-Daudé /* Access to at least one of the 64-bit segments has been disabled */ 84*5679479bSPhilippe Mathieu-Daudé tlb_flush(env_cpu(env)); 85*5679479bSPhilippe Mathieu-Daudé } 86*5679479bSPhilippe Mathieu-Daudé #endif 87*5679479bSPhilippe Mathieu-Daudé if (ase_mt_available(env)) { 88*5679479bSPhilippe Mathieu-Daudé sync_c0_status(env, env, env->current_tc); 89*5679479bSPhilippe Mathieu-Daudé } else { 90*5679479bSPhilippe Mathieu-Daudé compute_hflags(env); 91*5679479bSPhilippe Mathieu-Daudé } 92*5679479bSPhilippe Mathieu-Daudé } 93*5679479bSPhilippe Mathieu-Daudé 94*5679479bSPhilippe Mathieu-Daudé void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) 95*5679479bSPhilippe Mathieu-Daudé { 96*5679479bSPhilippe Mathieu-Daudé uint32_t mask = 0x00C00300; 97*5679479bSPhilippe Mathieu-Daudé uint32_t old = env->CP0_Cause; 98*5679479bSPhilippe Mathieu-Daudé int i; 99*5679479bSPhilippe Mathieu-Daudé 100*5679479bSPhilippe Mathieu-Daudé if (env->insn_flags & ISA_MIPS_R2) { 101*5679479bSPhilippe Mathieu-Daudé mask |= 1 << CP0Ca_DC; 102*5679479bSPhilippe Mathieu-Daudé } 103*5679479bSPhilippe Mathieu-Daudé if (env->insn_flags & ISA_MIPS_R6) { 104*5679479bSPhilippe Mathieu-Daudé mask &= ~((1 << CP0Ca_WP) & val); 105*5679479bSPhilippe Mathieu-Daudé } 106*5679479bSPhilippe Mathieu-Daudé 107*5679479bSPhilippe Mathieu-Daudé env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask); 108*5679479bSPhilippe Mathieu-Daudé 109*5679479bSPhilippe Mathieu-Daudé if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { 110*5679479bSPhilippe Mathieu-Daudé if (env->CP0_Cause & (1 << CP0Ca_DC)) { 111*5679479bSPhilippe Mathieu-Daudé cpu_mips_stop_count(env); 112*5679479bSPhilippe Mathieu-Daudé } else { 113*5679479bSPhilippe Mathieu-Daudé cpu_mips_start_count(env); 114*5679479bSPhilippe Mathieu-Daudé } 115*5679479bSPhilippe Mathieu-Daudé } 116*5679479bSPhilippe Mathieu-Daudé 117*5679479bSPhilippe Mathieu-Daudé /* Set/reset software interrupts */ 118*5679479bSPhilippe Mathieu-Daudé for (i = 0 ; i < 2 ; i++) { 119*5679479bSPhilippe Mathieu-Daudé if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { 120*5679479bSPhilippe Mathieu-Daudé cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); 121*5679479bSPhilippe Mathieu-Daudé } 122*5679479bSPhilippe Mathieu-Daudé } 123*5679479bSPhilippe Mathieu-Daudé } 124