diff options
-rw-r--r-- | target-mips/cpu.h | 3 | ||||
-rw-r--r-- | target-mips/translate.c | 109 |
2 files changed, 76 insertions, 36 deletions
diff --git a/target-mips/cpu.h b/target-mips/cpu.h index ce9a7a28f0..6367d8c52d 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -488,7 +488,7 @@ struct CPUMIPSState { * the delay slot, record what type of branch it is so that we can * resume translation properly. It might be possible to reduce * this from three bits to two. */ -#define MIPS_HFLAG_BMASK_BASE 0x03800 +#define MIPS_HFLAG_BMASK_BASE 0x803800 #define MIPS_HFLAG_B 0x00800 /* Unconditional branch */ #define MIPS_HFLAG_BC 0x01000 /* Conditional branch */ #define MIPS_HFLAG_BL 0x01800 /* Likely branch */ @@ -507,6 +507,7 @@ struct CPUMIPSState { /* Extra flag about HWREna register. */ #define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ #define MIPS_HFLAG_SBRI 0x400000 /* R6 SDBBP causes RI excpt. in user mode */ +#define MIPS_HFLAG_FBNSLOT 0x800000 /* Forbidden slot */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ diff --git a/target-mips/translate.c b/target-mips/translate.c index c7a8bbc0d3..a383a5ce4a 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -4136,7 +4136,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" + TARGET_FMT_lx "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); goto out; @@ -7638,12 +7639,22 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, case OPC_ERET: opn = "eret"; check_insn(ctx, ISA_MIPS2); + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + goto die; + } gen_helper_eret(cpu_env); ctx->bstate = BS_EXCP; break; case OPC_DERET: opn = "deret"; check_insn(ctx, ISA_MIPS32); + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + goto die; + } if (!(ctx->hflags & MIPS_HFLAG_DM)) { MIPS_INVAL(opn); generate_exception(ctx, EXCP_RI); @@ -7655,6 +7666,11 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, case OPC_WAIT: opn = "wait"; check_insn(ctx, ISA_MIPS3 | ISA_MIPS32); + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + goto die; + } /* If we get an exception, we want to restart at next instruction */ ctx->pc += 4; save_cpu_state(ctx, 1); @@ -7681,6 +7697,12 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, const char *opn = "cp1 cond branch"; TCGv_i32 t0 = tcg_temp_new_i32(); + if ((ctx->insn_flags & ISA_MIPS32R6) && (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + generate_exception(ctx, EXCP_RI); + goto out; + } + if (cc != 0) check_insn(ctx, ISA_MIPS4 | ISA_MIPS32); @@ -7797,7 +7819,8 @@ static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx + "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); goto out; @@ -10251,6 +10274,10 @@ static void gen_branch(DisasContext *ctx, int insn_bytes) save_cpu_state(ctx, 0); /* FIXME: Need to clear can_do_io. */ switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) { + case MIPS_HFLAG_FBNSLOT: + MIPS_DEBUG("forbidden slot"); + gen_goto_tb(ctx, 0, ctx->pc + insn_bytes); + break; case MIPS_HFLAG_B: /* unconditional branch */ MIPS_DEBUG("unconditional branch"); @@ -15533,7 +15560,8 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, if (ctx->hflags & MIPS_HFLAG_BMASK) { #ifdef MIPS_DEBUG_DISAS - LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n", ctx->pc); + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx + "\n", ctx->pc); #endif generate_exception(ctx, EXCP_RI); goto out; @@ -15626,56 +15654,56 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, gen_branch(ctx, 4); } else { /* Conditional compact branch */ - int l1 = gen_new_label(); + int fs = gen_new_label(); save_cpu_state(ctx, 0); switch (opc) { case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */ if (rs == 0 && rt != 0) { /* OPC_BLEZALC */ - tcg_gen_brcondi_tl(TCG_COND_LE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); } else if (rs != 0 && rt != 0 && rs == rt) { /* OPC_BGEZALC */ - tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); } else { /* OPC_BGEUC */ - tcg_gen_brcond_tl(TCG_COND_GEU, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GEU), t0, t1, fs); } break; case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */ if (rs == 0 && rt != 0) { /* OPC_BGTZALC */ - tcg_gen_brcondi_tl(TCG_COND_GT, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); } else if (rs != 0 && rt != 0 && rs == rt) { /* OPC_BLTZALC */ - tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); } else { /* OPC_BLTUC */ - tcg_gen_brcond_tl(TCG_COND_LTU, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LTU), t0, t1, fs); } break; case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */ if (rs == 0 && rt != 0) { /* OPC_BLEZC */ - tcg_gen_brcondi_tl(TCG_COND_LE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LE), t1, 0, fs); } else if (rs != 0 && rt != 0 && rs == rt) { /* OPC_BGEZC */ - tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GE), t1, 0, fs); } else { /* OPC_BGEC */ - tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GE), t0, t1, fs); } break; case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */ if (rs == 0 && rt != 0) { /* OPC_BGTZC */ - tcg_gen_brcondi_tl(TCG_COND_GT, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_GT), t1, 0, fs); } else if (rs != 0 && rt != 0 && rs == rt) { /* OPC_BLTZC */ - tcg_gen_brcondi_tl(TCG_COND_LT, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_LT), t1, 0, fs); } else { /* OPC_BLTC */ - tcg_gen_brcond_tl(TCG_COND_LT, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); } break; case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */ @@ -15704,10 +15732,10 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, tcg_gen_or_tl(t4, t4, input_overflow); if (opc == OPC_BOVC) { /* OPC_BOVC */ - tcg_gen_brcondi_tl(TCG_COND_NE, t4, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t4, 0, fs); } else { /* OPC_BNVC */ - tcg_gen_brcondi_tl(TCG_COND_EQ, t4, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t4, 0, fs); } tcg_temp_free(input_overflow); tcg_temp_free(t4); @@ -15717,27 +15745,27 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, /* OPC_BEQZALC, OPC_BNEZALC */ if (opc == OPC_BEQZALC) { /* OPC_BEQZALC */ - tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t1, 0, fs); } else { /* OPC_BNEZALC */ - tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t1, 0, fs); } } else { /* OPC_BEQC, OPC_BNEC */ if (opc == OPC_BEQC) { /* OPC_BEQC */ - tcg_gen_brcond_tl(TCG_COND_EQ, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_EQ), t0, t1, fs); } else { /* OPC_BNEC */ - tcg_gen_brcond_tl(TCG_COND_NE, t0, t1, l1); + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_NE), t0, t1, fs); } } break; case OPC_BEQZC: - tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_EQ), t0, 0, fs); break; case OPC_BNEZC: - tcg_gen_brcondi_tl(TCG_COND_NE, t0, 0, l1); + tcg_gen_brcondi_tl(tcg_invert_cond(TCG_COND_NE), t0, 0, fs); break; default: MIPS_INVAL("Compact conditional branch/jump"); @@ -15746,12 +15774,11 @@ static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc, } /* Generating branch here as compact branches don't have delay slot */ - /* TODO: implement forbidden slot */ - gen_goto_tb(ctx, 1, ctx->pc + 4); - gen_set_label(l1); - gen_goto_tb(ctx, 0, ctx->btarget); + gen_goto_tb(ctx, 1, ctx->btarget); + gen_set_label(fs); + + ctx->hflags |= MIPS_HFLAG_FBNSLOT; MIPS_DEBUG("Compact conditional branch"); - ctx->bstate = BS_BRANCH; } out: @@ -15969,6 +15996,16 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx) op1 = MASK_SPECIAL(ctx->opcode); switch (op1) { case OPC_SLL: /* Shift with immediate */ + if (sa == 5 && rd == 0 && + rs == 0 && rt == 0) { /* PAUSE */ + if ((ctx->insn_flags & ISA_MIPS32R6) && + (ctx->hflags & MIPS_HFLAG_BMASK)) { + MIPS_DEBUG("CTI in delay / forbidden slot"); + generate_exception(ctx, EXCP_RI); + break; + } + } + /* Fallthrough */ case OPC_SRA: gen_shift_imm(ctx, op1, rd, rt, sa); break; @@ -17567,7 +17604,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, int num_insns; int max_insns; int insn_bytes; - int is_delay; + int is_slot; if (search_pc) qemu_log("search pc %d\n", search_pc); @@ -17632,7 +17669,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) gen_io_start(); - is_delay = ctx.hflags & MIPS_HFLAG_BMASK; + is_slot = ctx.hflags & MIPS_HFLAG_BMASK; if (!(ctx.hflags & MIPS_HFLAG_M16)) { ctx.opcode = cpu_ldl_code(env, ctx.pc); insn_bytes = 4; @@ -17650,12 +17687,14 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, } if (ctx.hflags & MIPS_HFLAG_BMASK) { - if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32))) { - is_delay = 1; - /* force to generate branch as no delay slot is required */ + if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32 | + MIPS_HFLAG_FBNSLOT))) { + /* force to generate branch as there is neither delay nor + forbidden slot */ + is_slot = 1; } } - if (is_delay) { + if (is_slot) { gen_branch(&ctx, insn_bytes); } ctx.pc += insn_bytes; |