diff --git a/target/mips/translate.c b/target/mips/translate.c index 38887a1271..93fb8f32e7 100644 --- a/target/mips/translate.c +++ b/target/mips/translate.c @@ -427,6 +427,24 @@ enum { OPC_EXTR_W_DSP = 0x38 | OPC_SPECIAL3, OPC_DEXTR_W_DSP = 0x3C | OPC_SPECIAL3, + /* EVA */ + OPC_LWLE = 0x19 | OPC_SPECIAL3, + OPC_LWRE = 0x1A | OPC_SPECIAL3, + OPC_CACHEE = 0x1B | OPC_SPECIAL3, + OPC_SBE = 0x1C | OPC_SPECIAL3, + OPC_SHE = 0x1D | OPC_SPECIAL3, + OPC_SCE = 0x1E | OPC_SPECIAL3, + OPC_SWE = 0x1F | OPC_SPECIAL3, + OPC_SWLE = 0x21 | OPC_SPECIAL3, + OPC_SWRE = 0x22 | OPC_SPECIAL3, + OPC_PREFE = 0x23 | OPC_SPECIAL3, + OPC_LBUE = 0x28 | OPC_SPECIAL3, + OPC_LHUE = 0x29 | OPC_SPECIAL3, + OPC_LBE = 0x2C | OPC_SPECIAL3, + OPC_LHE = 0x2D | OPC_SPECIAL3, + OPC_LLE = 0x2E | OPC_SPECIAL3, + OPC_LWE = 0x2F | OPC_SPECIAL3, + /* R6 */ R6_OPC_PREF = 0x35 | OPC_SPECIAL3, R6_OPC_CACHE = 0x25 | OPC_SPECIAL3, @@ -1431,6 +1449,7 @@ typedef struct DisasContext { bool bp; uint64_t PAMask; bool mvh; + bool eva; int CP0_LLAddr_shift; bool ps; bool vp; @@ -2216,29 +2235,47 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL); gen_store_gpr(t0, rt); break; + case OPC_LWE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LW: tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL | ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); break; + case OPC_LHE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LH: tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESW | ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); break; + case OPC_LHUE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LHU: tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUW | ctx->default_tcg_memop_mask); gen_store_gpr(t0, rt); break; + case OPC_LBE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LB: tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_SB); gen_store_gpr(t0, rt); break; + case OPC_LBUE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LBU: tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_UB); gen_store_gpr(t0, rt); break; + case OPC_LWLE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LWL: t1 = tcg_temp_new(); /* Do a byte access to possibly trigger a page @@ -2262,6 +2299,9 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_gen_ext32s_tl(t0, t0); gen_store_gpr(t0, rt); break; + case OPC_LWRE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LWR: t1 = tcg_temp_new(); /* Do a byte access to possibly trigger a page @@ -2286,6 +2326,9 @@ static void gen_ld(DisasContext *ctx, uint32_t opc, tcg_gen_ext32s_tl(t0, t0); gen_store_gpr(t0, rt); break; + case OPC_LLE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_LL: case R6_OPC_LL: op_ld_ll(t0, t0, mem_idx, ctx); @@ -2318,20 +2361,35 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt, gen_helper_0e2i(sdr, t1, t0, mem_idx); break; #endif + case OPC_SWE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_SW: tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | ctx->default_tcg_memop_mask); break; + case OPC_SHE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_SH: tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | ctx->default_tcg_memop_mask); break; + case OPC_SBE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_SB: tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); break; + case OPC_SWLE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_SWL: gen_helper_0e2i(swl, t1, t0, mem_idx); break; + case OPC_SWRE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_SWR: gen_helper_0e2i(swr, t1, t0, mem_idx); break; @@ -2364,6 +2422,9 @@ static void gen_st_cond (DisasContext *ctx, uint32_t opc, int rt, op_st_scd(t1, t0, rt, mem_idx, ctx); break; #endif + case OPC_SCE: + mem_idx = MIPS_HFLAG_UM; + /* fall through */ case OPC_SC: case R6_OPC_SC: op_st_sc(t1, t0, rt, mem_idx, ctx); @@ -18020,13 +18081,57 @@ static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx) { int rs, rt, rd, sa; uint32_t op1, op2; + int16_t imm; rs = (ctx->opcode >> 21) & 0x1f; rt = (ctx->opcode >> 16) & 0x1f; rd = (ctx->opcode >> 11) & 0x1f; sa = (ctx->opcode >> 6) & 0x1f; + imm = sextract32(ctx->opcode, 7, 9); op1 = MASK_SPECIAL3(ctx->opcode); + + /* + * EVA loads and stores overlap Loongson 2E instructions decoded by + * decode_opc_special3_legacy(), so be careful to allow their decoding when + * EVA is absent. + */ + if (ctx->eva) { + switch (op1) { + case OPC_LWLE ... OPC_LWRE: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* fall through */ + case OPC_LBUE ... OPC_LHUE: + case OPC_LBE ... OPC_LWE: + check_cp0_enabled(ctx); + gen_ld(ctx, op1, rt, rs, imm); + return; + case OPC_SWLE ... OPC_SWRE: + check_insn_opc_removed(ctx, ISA_MIPS32R6); + /* fall through */ + case OPC_SBE ... OPC_SHE: + case OPC_SWE: + check_cp0_enabled(ctx); + gen_st(ctx, op1, rt, rs, imm); + return; + case OPC_SCE: + check_cp0_enabled(ctx); + gen_st_cond(ctx, op1, rt, rs, imm); + return; + case OPC_CACHEE: + check_cp0_enabled(ctx); + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, imm); + } + /* Treat as NOP. */ + return; + case OPC_PREFE: + check_cp0_enabled(ctx); + /* Treat as NOP. */ + return; + } + } + switch (op1) { case OPC_EXT: case OPC_INS: @@ -19925,6 +20030,7 @@ void gen_intermediate_code(CPUState *cs, struct TranslationBlock *tb) ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1; ctx.PAMask = env->PAMask; ctx.mvh = (env->CP0_Config5 >> CP0C5_MVH) & 1; + ctx.eva = (env->CP0_Config5 >> CP0C5_EVA) & 1; ctx.CP0_LLAddr_shift = env->CP0_LLAddr_shift; ctx.cmgcr = (env->CP0_Config3 >> CP0C3_CMGCR) & 1; /* Restore delay slot state from the tb context. */