aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-mips/cpu.h7
-rw-r--r--target-mips/helper.h3
-rw-r--r--target-mips/op_helper.c40
-rw-r--r--target-mips/translate.c62
4 files changed, 100 insertions, 12 deletions
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 725aaef4c2..67bbb25adf 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -519,6 +519,10 @@ struct CPUMIPSState {
#define CP0DB_DSS 0
target_ulong CP0_DEPC;
int32_t CP0_Performance0;
+ int32_t CP0_ErrCtl;
+#define CP0EC_WST 29
+#define CP0EC_SPR 28
+#define CP0EC_ITC 26
uint64_t CP0_TagLo;
int32_t CP0_DataLo;
int32_t CP0_TagHi;
@@ -534,7 +538,7 @@ struct CPUMIPSState {
#define EXCP_INST_NOTAVAIL 0x2 /* No valid instruction word for BadInstr */
uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */
-#define MIPS_HFLAG_TMASK 0x75807FF
+#define MIPS_HFLAG_TMASK 0xF5807FF
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */
/* The KSU flags must be the lowest bits in hflags. The flag order
must be the same as defined for CP0 Status. This allows to use
@@ -583,6 +587,7 @@ struct CPUMIPSState {
#define MIPS_HFLAG_MSA 0x1000000
#define MIPS_HFLAG_FRE 0x2000000 /* FRE enabled */
#define MIPS_HFLAG_ELPA 0x4000000
+#define MIPS_HFLAG_ITC_CACHE 0x8000000 /* CACHE instr. operates on ITC tag */
target_ulong btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */
diff --git a/target-mips/helper.h b/target-mips/helper.h
index 1bc8bb20d1..62fe20bbdf 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -151,6 +151,7 @@ DEF_HELPER_2(mtc0_framemask, void, env, tl)
DEF_HELPER_2(mtc0_debug, void, env, tl)
DEF_HELPER_2(mttc0_debug, void, env, tl)
DEF_HELPER_2(mtc0_performance0, void, env, tl)
+DEF_HELPER_2(mtc0_errctl, void, env, tl)
DEF_HELPER_2(mtc0_taglo, void, env, tl)
DEF_HELPER_2(mtc0_datalo, void, env, tl)
DEF_HELPER_2(mtc0_taghi, void, env, tl)
@@ -949,3 +950,5 @@ MSALDST_PROTO(h)
MSALDST_PROTO(w)
MSALDST_PROTO(d)
#undef MSALDST_PROTO
+
+DEF_HELPER_3(cache, void, env, tl, i32)
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 7c5669cc96..dcd44c4e55 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1632,9 +1632,31 @@ void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1)
env->CP0_Performance0 = arg1 & 0x000007ff;
}
+void helper_mtc0_errctl(CPUMIPSState *env, target_ulong arg1)
+{
+ int32_t wst = arg1 & (1 << CP0EC_WST);
+ int32_t spr = arg1 & (1 << CP0EC_SPR);
+ int32_t itc = env->itc_tag ? (arg1 & (1 << CP0EC_ITC)) : 0;
+
+ env->CP0_ErrCtl = wst | spr | itc;
+
+ if (itc && !wst && !spr) {
+ env->hflags |= MIPS_HFLAG_ITC_CACHE;
+ } else {
+ env->hflags &= ~MIPS_HFLAG_ITC_CACHE;
+ }
+}
+
void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1)
{
- env->CP0_TagLo = arg1 & 0xFFFFFCF6;
+ if (env->hflags & MIPS_HFLAG_ITC_CACHE) {
+ /* If CACHE instruction is configured for ITC tags then make all
+ CP0.TagLo bits writable. The actual write to ITC Configuration
+ Tag will take care of the read-only bits. */
+ env->CP0_TagLo = arg1;
+ } else {
+ env->CP0_TagLo = arg1 & 0xFFFFFCF6;
+ }
}
void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1)
@@ -3781,3 +3803,19 @@ MSA_ST_DF(DF_HALF, h, cpu_stw_data)
MSA_ST_DF(DF_WORD, w, cpu_stl_data)
MSA_ST_DF(DF_DOUBLE, d, cpu_stq_data)
#endif
+
+void helper_cache(CPUMIPSState *env, target_ulong addr, uint32_t op)
+{
+#ifndef CONFIG_USER_ONLY
+ target_ulong index = addr & 0x1fffffff;
+ if (op == 9) {
+ /* Index Store Tag */
+ memory_region_dispatch_write(env->itc_tag, index, env->CP0_TagLo,
+ 8, MEMTXATTRS_UNSPECIFIED);
+ } else if (op == 5) {
+ /* Index Load Tag */
+ memory_region_dispatch_read(env->itc_tag, index, &env->CP0_TagLo,
+ 8, MEMTXATTRS_UNSPECIFIED);
+ }
+#endif
+}
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 65f2caff3e..592e4e3cd0 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -5486,8 +5486,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
break;
case 26:
- tcg_gen_movi_tl(arg, 0); /* unimplemented */
- rn = "ECC";
+ switch (sel) {
+ case 0:
+ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl));
+ rn = "ErrCtl";
+ break;
+ default:
+ goto cp0_unimplemented;
+ }
break;
case 27:
switch (sel) {
@@ -6136,8 +6142,15 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
break;
case 26:
- /* ignored */
- rn = "ECC";
+ switch (sel) {
+ case 0:
+ gen_helper_mtc0_errctl(cpu_env, arg);
+ ctx->bstate = BS_STOP;
+ rn = "ErrCtl";
+ break;
+ default:
+ goto cp0_unimplemented;
+ }
break;
case 27:
switch (sel) {
@@ -6762,8 +6775,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
break;
case 26:
- tcg_gen_movi_tl(arg, 0); /* unimplemented */
- rn = "ECC";
+ switch (sel) {
+ case 0:
+ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_ErrCtl));
+ rn = "ErrCtl";
+ break;
+ default:
+ goto cp0_unimplemented;
+ }
break;
case 27:
switch (sel) {
@@ -7404,8 +7423,15 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel)
}
break;
case 26:
- /* ignored */
- rn = "ECC";
+ switch (sel) {
+ case 0:
+ gen_helper_mtc0_errctl(cpu_env, arg);
+ ctx->bstate = BS_STOP;
+ rn = "ErrCtl";
+ break;
+ default:
+ goto cp0_unimplemented;
+ }
break;
case 27:
switch (sel) {
@@ -11190,6 +11216,15 @@ static void gen_addiupc (DisasContext *ctx, int rx, int imm,
tcg_temp_free(t0);
}
+static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base,
+ int16_t offset)
+{
+ TCGv_i32 t0 = tcg_const_i32(op);
+ TCGv t1 = tcg_temp_new();
+ gen_base_offset_addr(ctx, t1, base, offset);
+ gen_helper_cache(cpu_env, t1, t0);
+}
+
#if defined(TARGET_MIPS64)
static void decode_i64_mips16 (DisasContext *ctx,
int ry, int funct, int16_t offset,
@@ -13741,7 +13776,9 @@ static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx)
switch (minor) {
case CACHE:
check_cp0_enabled(ctx);
- /* Treat as no-op. */
+ if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) {
+ gen_cache_operation(ctx, rt, rs, imm);
+ }
break;
case LWC2:
case SWC2:
@@ -17195,7 +17232,9 @@ static void decode_opc_special3_r6(CPUMIPSState *env, DisasContext *ctx)
break;
case R6_OPC_CACHE:
check_cp0_enabled(ctx);
- /* Treat as NOP. */
+ if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) {
+ gen_cache_operation(ctx, rt, rs, imm);
+ }
break;
case R6_OPC_SC:
gen_st_cond(ctx, op1, rt, rs, imm);
@@ -19304,6 +19343,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS32R6);
check_cp0_enabled(ctx);
check_insn(ctx, ISA_MIPS3 | ISA_MIPS32);
+ if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) {
+ gen_cache_operation(ctx, rt, rs, imm);
+ }
/* Treat as NOP. */
break;
case OPC_PREF: