aboutsummaryrefslogtreecommitdiff
path: root/target/mips/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/mips/op_helper.c')
-rw-r--r--target/mips/op_helper.c64
1 files changed, 57 insertions, 7 deletions
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index e5f3ea4042..526f8e4969 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -67,6 +67,7 @@ static inline type do_##name(CPUMIPSState *env, target_ulong addr, \
case 1: return (type) cpu_##insn##_super_ra(env, addr, retaddr); \
default: \
case 2: return (type) cpu_##insn##_user_ra(env, addr, retaddr); \
+ case 3: return (type) cpu_##insn##_error_ra(env, addr, retaddr); \
} \
}
#endif
@@ -94,6 +95,9 @@ static inline void do_##name(CPUMIPSState *env, target_ulong addr, \
case 1: cpu_##insn##_super_ra(env, addr, val, retaddr); break; \
default: \
case 2: cpu_##insn##_user_ra(env, addr, val, retaddr); break; \
+ case 3: \
+ cpu_##insn##_error_ra(env, addr, val, retaddr); \
+ break; \
} \
}
#endif
@@ -1318,6 +1322,30 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
restore_pamask(env);
}
+void helper_mtc0_segctl0(CPUMIPSState *env, target_ulong arg1)
+{
+ CPUState *cs = CPU(mips_env_get_cpu(env));
+
+ env->CP0_SegCtl0 = arg1 & CP0SC0_MASK;
+ tlb_flush(cs);
+}
+
+void helper_mtc0_segctl1(CPUMIPSState *env, target_ulong arg1)
+{
+ CPUState *cs = CPU(mips_env_get_cpu(env));
+
+ env->CP0_SegCtl1 = arg1 & CP0SC1_MASK;
+ tlb_flush(cs);
+}
+
+void helper_mtc0_segctl2(CPUMIPSState *env, target_ulong arg1)
+{
+ CPUState *cs = CPU(mips_env_get_cpu(env));
+
+ env->CP0_SegCtl2 = arg1 & CP0SC2_MASK;
+ tlb_flush(cs);
+}
+
void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
{
if (env->insn_flags & ISA_MIPS32R6) {
@@ -1416,7 +1444,7 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
/* If the ASID changes, flush qemu's TLB. */
if ((old & env->CP0_EntryHi_ASID_mask) !=
(val & env->CP0_EntryHi_ASID_mask)) {
- cpu_mips_tlb_flush(env);
+ tlb_flush(CPU(mips_env_get_cpu(env)));
}
}
@@ -1450,7 +1478,10 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
old, old & env->CP0_Cause & CP0Ca_IP_mask,
val, val & env->CP0_Cause & CP0Ca_IP_mask,
env->CP0_Cause);
- switch (env->hflags & MIPS_HFLAG_KSU) {
+ switch (cpu_mmu_index(env, false)) {
+ case 3:
+ qemu_log(", ERL\n");
+ break;
case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
case MIPS_HFLAG_KM: qemu_log("\n"); break;
@@ -1515,14 +1546,22 @@ target_ulong helper_mftc0_ebase(CPUMIPSState *env)
void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
{
- env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
+ target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
+ if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
+ mask |= ~0x3FFFFFFF;
+ }
+ env->CP0_EBase = (env->CP0_EBase & ~mask) | (arg1 & mask);
}
void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1)
{
int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc);
- other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
+ target_ulong mask = 0x3FFFF000 | env->CP0_EBaseWG_rw_bitmask;
+ if (arg1 & env->CP0_EBaseWG_rw_bitmask) {
+ mask |= ~0x3FFFFFFF;
+ }
+ other->CP0_EBase = (other->CP0_EBase & ~mask) | (arg1 & mask);
}
target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx)
@@ -2029,7 +2068,7 @@ void r4k_helper_tlbwi(CPUMIPSState *env)
int idx;
target_ulong VPN;
uint16_t ASID;
- bool G, V0, D0, V1, D1;
+ bool EHINV, G, V0, D0, V1, D1, XI0, XI1, RI0, RI1;
idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
tlb = &env->tlb->mmu.r4k.tlb[idx];
@@ -2038,17 +2077,25 @@ void r4k_helper_tlbwi(CPUMIPSState *env)
VPN &= env->SEGMask;
#endif
ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
+ EHINV = (env->CP0_EntryHi & (1 << CP0EnHi_EHINV)) != 0;
G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
V0 = (env->CP0_EntryLo0 & 2) != 0;
D0 = (env->CP0_EntryLo0 & 4) != 0;
+ XI0 = (env->CP0_EntryLo0 >> CP0EnLo_XI) &1;
+ RI0 = (env->CP0_EntryLo0 >> CP0EnLo_RI) &1;
V1 = (env->CP0_EntryLo1 & 2) != 0;
D1 = (env->CP0_EntryLo1 & 4) != 0;
+ XI1 = (env->CP0_EntryLo1 >> CP0EnLo_XI) &1;
+ RI1 = (env->CP0_EntryLo1 >> CP0EnLo_RI) &1;
/* Discard cached TLB entries, unless tlbwi is just upgrading access
permissions on the current entry. */
if (tlb->VPN != VPN || tlb->ASID != ASID || tlb->G != G ||
+ (!tlb->EHINV && EHINV) ||
(tlb->V0 && !V0) || (tlb->D0 && !D0) ||
- (tlb->V1 && !V1) || (tlb->D1 && !D1)) {
+ (!tlb->XI0 && XI0) || (!tlb->RI0 && RI0) ||
+ (tlb->V1 && !V1) || (tlb->D1 && !D1) ||
+ (!tlb->XI1 && XI1) || (!tlb->RI1 && RI1)) {
r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
}
@@ -2228,7 +2275,10 @@ static void debug_post_eret(CPUMIPSState *env)
qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
if (env->hflags & MIPS_HFLAG_DM)
qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
- switch (env->hflags & MIPS_HFLAG_KSU) {
+ switch (cpu_mmu_index(env, false)) {
+ case 3:
+ qemu_log(", ERL\n");
+ break;
case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
case MIPS_HFLAG_KM: qemu_log("\n"); break;