aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target/mips/cpu.h5
-rw-r--r--target/mips/helper.c14
-rw-r--r--target/mips/machine.c6
-rw-r--r--target/mips/op_helper.c12
-rw-r--r--target/mips/translate.c8
-rw-r--r--target/mips/translate_init.c1
6 files changed, 31 insertions, 15 deletions
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 4a4747af25..2b699a0e24 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -399,7 +399,9 @@ struct CPUMIPSState {
#define CP0Ca_EC 2
target_ulong CP0_EPC;
int32_t CP0_PRid;
- int32_t CP0_EBase;
+ target_ulong CP0_EBase;
+ target_ulong CP0_EBaseWG_rw_bitmask;
+#define CP0EBase_WG 11
target_ulong CP0_CMGCRBase;
int32_t CP0_Config0;
#define CP0C0_M 31
@@ -447,6 +449,7 @@ struct CPUMIPSState {
#define CP0C3_MSAP 28
#define CP0C3_BP 27
#define CP0C3_BI 26
+#define CP0C3_SC 25
#define CP0C3_IPLW 21
#define CP0C3_MMAR 18
#define CP0C3_MCU 17
diff --git a/target/mips/helper.c b/target/mips/helper.c
index 11d6a86567..5b765cdef5 100644
--- a/target/mips/helper.c
+++ b/target/mips/helper.c
@@ -831,11 +831,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
goto set_EPC;
case EXCP_CACHE:
cause = 30;
- if (env->CP0_Status & (1 << CP0St_BEV)) {
- offset = 0x100;
- } else {
- offset = 0x20000100;
- }
+ offset = 0x100;
set_EPC:
if (!(env->CP0_Status & (1 << CP0St_EXL))) {
env->CP0_EPC = exception_resume_pc(env);
@@ -861,9 +857,15 @@ void mips_cpu_do_interrupt(CPUState *cs)
env->hflags &= ~MIPS_HFLAG_BMASK;
if (env->CP0_Status & (1 << CP0St_BEV)) {
env->active_tc.PC = env->exception_base + 0x200;
+ } else if (cause == 30 && !(env->CP0_Config3 & (1 << CP0C3_SC) &&
+ env->CP0_Config5 & (1 << CP0C5_CV))) {
+ /* Force KSeg1 for cache errors */
+ env->active_tc.PC = (int32_t)KSEG1_BASE |
+ (env->CP0_EBase & 0x1FFFF000);
} else {
- env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
+ env->active_tc.PC = env->CP0_EBase & ~0xfff;
}
+
env->active_tc.PC += offset;
set_hflags_for_handler(env);
env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
diff --git a/target/mips/machine.c b/target/mips/machine.c
index 38c8fe9328..91e31a7c2f 100644
--- a/target/mips/machine.c
+++ b/target/mips/machine.c
@@ -211,8 +211,8 @@ const VMStateDescription vmstate_tlb = {
const VMStateDescription vmstate_mips_cpu = {
.name = "cpu",
- .version_id = 8,
- .minimum_version_id = 8,
+ .version_id = 9,
+ .minimum_version_id = 9,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
/* Active TC */
@@ -272,7 +272,7 @@ const VMStateDescription vmstate_mips_cpu = {
VMSTATE_INT32(env.CP0_Cause, MIPSCPU),
VMSTATE_UINTTL(env.CP0_EPC, MIPSCPU),
VMSTATE_INT32(env.CP0_PRid, MIPSCPU),
- VMSTATE_INT32(env.CP0_EBase, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_EBase, MIPSCPU),
VMSTATE_INT32(env.CP0_Config0, MIPSCPU),
VMSTATE_INT32(env.CP0_Config1, MIPSCPU),
VMSTATE_INT32(env.CP0_Config2, MIPSCPU),
diff --git a/target/mips/op_helper.c b/target/mips/op_helper.c
index 091afd5ade..3b560d96b4 100644
--- a/target/mips/op_helper.c
+++ b/target/mips/op_helper.c
@@ -1515,14 +1515,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)
diff --git a/target/mips/translate.c b/target/mips/translate.c
index db6e5b599d..76dcc5ec8d 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -5332,7 +5332,8 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
- gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_EBase));
+ tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase));
+ tcg_gen_ext32s_tl(arg, arg);
rn = "EBase";
break;
case 3:
@@ -6643,7 +6644,7 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
- gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_EBase));
+ tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_EBase));
rn = "EBase";
break;
case 3:
@@ -20301,6 +20302,7 @@ void cpu_state_reset(CPUMIPSState *env)
env->CP0_SRSConf4 = env->cpu_model->CP0_SRSConf4;
env->CP0_PageGrain_rw_bitmask = env->cpu_model->CP0_PageGrain_rw_bitmask;
env->CP0_PageGrain = env->cpu_model->CP0_PageGrain;
+ env->CP0_EBaseWG_rw_bitmask = env->cpu_model->CP0_EBaseWG_rw_bitmask;
env->active_fpu.fcr0 = env->cpu_model->CP1_fcr0;
env->active_fpu.fcr31_rw_bitmask = env->cpu_model->CP1_fcr31_rw_bitmask;
env->active_fpu.fcr31 = env->cpu_model->CP1_fcr31;
@@ -20351,7 +20353,7 @@ void cpu_state_reset(CPUMIPSState *env)
if (kvm_enabled()) {
env->CP0_EBase |= 0x40000000;
} else {
- env->CP0_EBase |= 0x80000000;
+ env->CP0_EBase |= (int32_t)0x80000000;
}
if (env->CP0_Config3 & (1 << CP0C3_CMGCR)) {
env->CP0_CMGCRBase = 0x1fbf8000 >> 4;
diff --git a/target/mips/translate_init.c b/target/mips/translate_init.c
index 6ae23e476f..8f8196ed5a 100644
--- a/target/mips/translate_init.c
+++ b/target/mips/translate_init.c
@@ -101,6 +101,7 @@ struct mips_def_t {
int32_t CP0_SRSConf4;
int32_t CP0_PageGrain_rw_bitmask;
int32_t CP0_PageGrain;
+ target_ulong CP0_EBaseWG_rw_bitmask;
int insn_flags;
enum mips_mmu_types mmu_type;
};