diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 8e983b89..8c980227 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -3559,6 +3559,7 @@ mips_symbols = ( 'helper_biadd', 'helper_bitrev', 'helper_bitswap', + 'helper_cache', 'helper_cfc1', 'helper_cmp_d_eq', 'helper_cmp_d_f', @@ -4122,6 +4123,7 @@ mips_symbols = ( 'helper_mtc0_datalo', 'helper_mtc0_debug', 'helper_mtc0_ebase', + 'helper_mtc0_errctl', 'helper_mtc0_entryhi', 'helper_mtc0_entrylo0', 'helper_mtc0_entrylo1', diff --git a/qemu/mips.h b/qemu/mips.h index 80c7f356..e5cd1993 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -3495,6 +3495,7 @@ #define helper_biadd helper_biadd_mips #define helper_bitrev helper_bitrev_mips #define helper_bitswap helper_bitswap_mips +#define helper_cache helper_cache_mips #define helper_cfc1 helper_cfc1_mips #define helper_cmp_d_eq helper_cmp_d_eq_mips #define helper_cmp_d_f helper_cmp_d_f_mips @@ -4058,6 +4059,7 @@ #define helper_mtc0_datalo helper_mtc0_datalo_mips #define helper_mtc0_debug helper_mtc0_debug_mips #define helper_mtc0_ebase helper_mtc0_ebase_mips +#define helper_mtc0_errctl helper_mtc0_errctl_mips #define helper_mtc0_entryhi helper_mtc0_entryhi_mips #define helper_mtc0_entrylo0 helper_mtc0_entrylo0_mips #define helper_mtc0_entrylo1 helper_mtc0_entrylo1_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 247d68fc..f8a33bd7 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -3495,6 +3495,7 @@ #define helper_biadd helper_biadd_mips64 #define helper_bitrev helper_bitrev_mips64 #define helper_bitswap helper_bitswap_mips64 +#define helper_cache helper_cache_mips64 #define helper_cfc1 helper_cfc1_mips64 #define helper_cmp_d_eq helper_cmp_d_eq_mips64 #define helper_cmp_d_f helper_cmp_d_f_mips64 @@ -4058,6 +4059,7 @@ #define helper_mtc0_datalo helper_mtc0_datalo_mips64 #define helper_mtc0_debug helper_mtc0_debug_mips64 #define helper_mtc0_ebase helper_mtc0_ebase_mips64 +#define helper_mtc0_errctl helper_mtc0_errctl_mips64 #define helper_mtc0_entryhi helper_mtc0_entryhi_mips64 #define helper_mtc0_entrylo0 helper_mtc0_entrylo0_mips64 #define helper_mtc0_entrylo1 helper_mtc0_entrylo1_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 1a7f1666..cd23bab3 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -3495,6 +3495,7 @@ #define helper_biadd helper_biadd_mips64el #define helper_bitrev helper_bitrev_mips64el #define helper_bitswap helper_bitswap_mips64el +#define helper_cache helper_cache_mips64el #define helper_cfc1 helper_cfc1_mips64el #define helper_cmp_d_eq helper_cmp_d_eq_mips64el #define helper_cmp_d_f helper_cmp_d_f_mips64el @@ -4058,6 +4059,7 @@ #define helper_mtc0_datalo helper_mtc0_datalo_mips64el #define helper_mtc0_debug helper_mtc0_debug_mips64el #define helper_mtc0_ebase helper_mtc0_ebase_mips64el +#define helper_mtc0_errctl helper_mtc0_errctl_mips64el #define helper_mtc0_entryhi helper_mtc0_entryhi_mips64el #define helper_mtc0_entrylo0 helper_mtc0_entrylo0_mips64el #define helper_mtc0_entrylo1 helper_mtc0_entrylo1_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 06f96674..51aa4c0b 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -3495,6 +3495,7 @@ #define helper_biadd helper_biadd_mipsel #define helper_bitrev helper_bitrev_mipsel #define helper_bitswap helper_bitswap_mipsel +#define helper_cache helper_cache_mipsel #define helper_cfc1 helper_cfc1_mipsel #define helper_cmp_d_eq helper_cmp_d_eq_mipsel #define helper_cmp_d_f helper_cmp_d_f_mipsel @@ -4058,6 +4059,7 @@ #define helper_mtc0_datalo helper_mtc0_datalo_mipsel #define helper_mtc0_debug helper_mtc0_debug_mipsel #define helper_mtc0_ebase helper_mtc0_ebase_mipsel +#define helper_mtc0_errctl helper_mtc0_errctl_mipsel #define helper_mtc0_entryhi helper_mtc0_entryhi_mipsel #define helper_mtc0_entrylo0 helper_mtc0_entrylo0_mipsel #define helper_mtc0_entrylo1 helper_mtc0_entrylo1_mipsel diff --git a/qemu/target/mips/cpu.h b/qemu/target/mips/cpu.h index eeaa64bb..d83ff35b 100644 --- a/qemu/target/mips/cpu.h +++ b/qemu/target/mips/cpu.h @@ -533,6 +533,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; @@ -548,7 +552,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 @@ -597,6 +601,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) */ @@ -621,6 +626,7 @@ struct CPUMIPSState { //void *irq[8]; //QEMUTimer *timer; /* Internal timer */ target_ulong exception_base; /* ExceptionBase input to the core */ + MemoryRegion *itc_tag; /* ITC Configuration Tags */ // Unicorn engine struct uc_struct *uc; diff --git a/qemu/target/mips/helper.h b/qemu/target/mips/helper.h index 3a6104cb..df350d4c 100644 --- a/qemu/target/mips/helper.h +++ b/qemu/target/mips/helper.h @@ -150,6 +150,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) @@ -950,3 +951,6 @@ MSALDST_PROTO(h) MSALDST_PROTO(w) MSALDST_PROTO(d) #undef MSALDST_PROTO + +DEF_HELPER_3(cache, void, env, tl, i32) + diff --git a/qemu/target/mips/op_helper.c b/qemu/target/mips/op_helper.c index 7b75779c..938ab454 100644 --- a/qemu/target/mips/op_helper.c +++ b/qemu/target/mips/op_helper.c @@ -1666,9 +1666,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) @@ -4146,6 +4168,21 @@ 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 +} #if !defined(CONFIG_USER_ONLY) MSA_LD_DF(DF_BYTE, b, helper_ret_ldub_mmu, oi, GETPC()) diff --git a/qemu/target/mips/translate.c b/qemu/target/mips/translate.c index 4f48f08e..9475fc01 100644 --- a/qemu/target/mips/translate.c +++ b/qemu/target/mips/translate.c @@ -5680,8 +5680,14 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } break; case 26: - tcg_gen_movi_tl(tcg_ctx, arg, 0); /* unimplemented */ - rn = "ECC"; + switch (sel) { + case 0: + gen_mfc0_load32(ctx, arg, offsetof(CPUMIPSState, CP0_ErrCtl)); + rn = "ErrCtl"; + break; + default: + goto cp0_unimplemented; + } break; case 27: switch (sel) { @@ -6345,8 +6351,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(tcg_ctx, tcg_ctx->cpu_env, arg); + ctx->bstate = BS_STOP; + rn = "ErrCtl"; + break; + default: + goto cp0_unimplemented; + } break; case 27: switch (sel) { @@ -6975,8 +6988,14 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) } break; case 26: - tcg_gen_movi_tl(tcg_ctx, arg, 0); /* unimplemented */ - rn = "ECC"; + switch (sel) { + case 0: + gen_mfc0_load32(ctx, arg, offsetof(CPUMIPSState, CP0_ErrCtl)); + rn = "ErrCtl"; + break; + default: + goto cp0_unimplemented; + } break; case 27: switch (sel) { @@ -7628,8 +7647,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(tcg_ctx, tcg_ctx->cpu_env, arg); + ctx->bstate = BS_STOP; + rn = "ErrCtl"; + break; + default: + goto cp0_unimplemented; + } break; case 27: switch (sel) { @@ -11542,6 +11568,16 @@ static void gen_addiupc (DisasContext *ctx, int rx, int imm, tcg_temp_free(tcg_ctx, t0); } +static void gen_cache_operation(DisasContext *ctx, uint32_t op, int base, + int16_t offset) +{ + TCGContext *tcg_ctx = ctx->uc->tcg_ctx; + TCGv_i32 t0 = tcg_const_i32(tcg_ctx, op); + TCGv t1 = tcg_temp_new(tcg_ctx); + gen_base_offset_addr(ctx, t1, base, offset); + gen_helper_cache(tcg_ctx, tcg_ctx->cpu_env, t1, t0); +} + #if defined(TARGET_MIPS64) static void decode_i64_mips16 (DisasContext *ctx, int ry, int funct, int16_t offset, @@ -14122,7 +14158,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: @@ -17646,7 +17684,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); @@ -19793,7 +19833,9 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_pat check_insn_opc_removed(ctx, ISA_MIPS32R6); check_cp0_enabled(ctx); check_insn(ctx, ISA_MIPS3 | ISA_MIPS32); - /* Treat as NOP. */ + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, imm); + } break; case OPC_PREF: check_insn_opc_removed(ctx, ISA_MIPS32R6);