diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-12-17 16:25:21 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-12-17 16:25:21 +0000 |
commit | 84afc4dd56648ac302c7b5a917e95ca7b1239695 (patch) | |
tree | 7f1905105f79a12f7f83e5bb033f80192ae9070c /target-mips/cpu.h | |
parent | 339aaf5b7f26d1e638641c59a44883b7654bd8ea (diff) | |
parent | d4fa5354a246a1c6cb538a5d8ebcc21206d502fb (diff) |
Merge remote-tracking branch 'remotes/lalrae/tags/mips-20141216' into staging
* remotes/lalrae/tags/mips-20141216: (30 commits)
target-mips: remove excp_names[] from linux-user as it is unused
disas/mips: disable unused mips16_to_32_reg_map[]
disas/mips: remove unused mips_msa_control_names_numeric[32]
target-mips: convert single case switch into if statement
target-mips: Fix DisasContext's ulri member initialization
target-mips: Use local float status pointer across MSA macros
target-mips: Add missing calls to synchronise SoftFloat status
linux-user: Use the 5KEf processor for 64-bit emulation
target-mips: Also apply the CP0.Status mask to MTTC0
target-mips: gdbstub: Clean up FPU register handling
target-mips: Correct 32-bit address space wrapping
target-mips: Tighten ISA level checks
target-mips: Fix CP0.Config3.ISAOnExc write accesses
target-mips: Output CP0.Config2-5 in the register dump
target-mips: Fix the 64-bit case for microMIPS MOVE16 and MOVEP
target-mips: Correct the writes to Status and Cause registers via gdbstub
target-mips: Correct the handling of writes to CP0.Status for MIPSr6
target-mips: Correct MIPS16/microMIPS branch size calculation
target-mips: Restore the order of helpers
target-mips: Remove unused `FLOAT_OP' macro
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-mips/cpu.h')
-rw-r--r-- | target-mips/cpu.h | 124 |
1 files changed, 114 insertions, 10 deletions
diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c01bbdac2d..8875c975e0 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -446,8 +446,8 @@ struct CPUMIPSState { #define CP0C3_MT 2 #define CP0C3_SM 1 #define CP0C3_TL 0 - uint32_t CP0_Config4; - uint32_t CP0_Config4_rw_bitmask; + int32_t CP0_Config4; + int32_t CP0_Config4_rw_bitmask; #define CP0C4_M 31 #define CP0C4_IE 29 #define CP0C4_KScrExist 16 @@ -456,8 +456,8 @@ struct CPUMIPSState { #define CP0C4_FTLBWays 4 #define CP0C4_FTLBSets 0 #define CP0C4_MMUSizeExt 0 - uint32_t CP0_Config5; - uint32_t CP0_Config5_rw_bitmask; + int32_t CP0_Config5; + int32_t CP0_Config5_rw_bitmask; #define CP0C5_M 31 #define CP0C5_K 30 #define CP0C5_CV 29 @@ -777,6 +777,18 @@ target_ulong exception_resume_pc (CPUMIPSState *env); extern unsigned int ieee_rm[]; int ieee_ex_to_mips(int xcpt); +static inline void restore_rounding_mode(CPUMIPSState *env) +{ + set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], + &env->active_fpu.fp_status); +} + +static inline void restore_flush_mode(CPUMIPSState *env) +{ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, + &env->active_fpu.fp_status); +} + static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, target_ulong *cs_base, int *flags) { @@ -831,16 +843,19 @@ static inline void compute_hflags(CPUMIPSState *env) env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; } #if defined(TARGET_MIPS64) - if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || - (env->CP0_Status & (1 << CP0St_PX)) || - (env->CP0_Status & (1 << CP0St_UX))) { + if ((env->insn_flags & ISA_MIPS3) && + (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || + (env->CP0_Status & (1 << CP0St_PX)) || + (env->CP0_Status & (1 << CP0St_UX)))) { env->hflags |= MIPS_HFLAG_64; } - if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && - !(env->CP0_Status & (1 << CP0St_UX))) { + if (!(env->insn_flags & ISA_MIPS3)) { + env->hflags |= MIPS_HFLAG_AWRAP; + } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && + !(env->CP0_Status & (1 << CP0St_UX))) { env->hflags |= MIPS_HFLAG_AWRAP; - } else if (env->insn_flags & ISA_MIPS32R6) { + } else if (env->insn_flags & ISA_MIPS64R6) { /* Address wrapping for Supervisor and Kernel is specified in R6 */ if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) && !(env->CP0_Status & (1 << CP0St_SX))) || @@ -904,4 +919,93 @@ static inline void compute_hflags(CPUMIPSState *env) } } +#ifndef CONFIG_USER_ONLY +/* Called for updates to CP0_Status. */ +static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) +{ + int32_t tcstatus, *tcst; + uint32_t v = cpu->CP0_Status; + uint32_t cu, mx, asid, ksu; + uint32_t mask = ((1 << CP0TCSt_TCU3) + | (1 << CP0TCSt_TCU2) + | (1 << CP0TCSt_TCU1) + | (1 << CP0TCSt_TCU0) + | (1 << CP0TCSt_TMX) + | (3 << CP0TCSt_TKSU) + | (0xff << CP0TCSt_TASID)); + + cu = (v >> CP0St_CU0) & 0xf; + mx = (v >> CP0St_MX) & 0x1; + ksu = (v >> CP0St_KSU) & 0x3; + asid = env->CP0_EntryHi & 0xff; + + tcstatus = cu << CP0TCSt_TCU0; + tcstatus |= mx << CP0TCSt_TMX; + tcstatus |= ksu << CP0TCSt_TKSU; + tcstatus |= asid; + + if (tc == cpu->current_tc) { + tcst = &cpu->active_tc.CP0_TCStatus; + } else { + tcst = &cpu->tcs[tc].CP0_TCStatus; + } + + *tcst &= ~mask; + *tcst |= tcstatus; + compute_hflags(cpu); +} + +static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = env->CP0_Status_rw_bitmask; + + if (env->insn_flags & ISA_MIPS32R6) { + bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3; + + if (has_supervisor && extract32(val, CP0St_KSU, 2) == 0x3) { + mask &= ~(3 << CP0St_KSU); + } + mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val); + } + + env->CP0_Status = (env->CP0_Status & ~mask) | (val & mask); + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + sync_c0_status(env, env, env->current_tc); + } else { + compute_hflags(env); + } +} + +static inline void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val) +{ + uint32_t mask = 0x00C00300; + uint32_t old = env->CP0_Cause; + int i; + + if (env->insn_flags & ISA_MIPS32R2) { + mask |= 1 << CP0Ca_DC; + } + if (env->insn_flags & ISA_MIPS32R6) { + mask &= ~((1 << CP0Ca_WP) & val); + } + + env->CP0_Cause = (env->CP0_Cause & ~mask) | (val & mask); + + if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) { + if (env->CP0_Cause & (1 << CP0Ca_DC)) { + cpu_mips_stop_count(env); + } else { + cpu_mips_start_count(env); + } + } + + /* Set/reset software interrupts */ + for (i = 0 ; i < 2 ; i++) { + if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) { + cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i))); + } + } +} +#endif + #endif /* !defined (__MIPS_CPU_H__) */ |