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;
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config3));
rn = "Config3";
break;
+ case 4:
+ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config4));
+ rn = "Config4";
+ break;
+ case 5:
+ gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config5));
+ rn = "Config5";
+ break;
/* 6,7 are implementation dependent */
case 6:
gen_mfc0_load32(arg, offsetof(CPUMIPSState, CP0_Config6));
/* ignored */
rn = "Config3";
break;
+ case 4:
+ /* currently ignored */
+ rn = "Config4";
+ break;
+ case 5:
+ gen_helper_mtc0_config5(cpu_env, arg);
+ rn = "Config5";
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
/* 6,7 are implementation dependent */
default:
rn = "Invalid config selector";
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);
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);
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);
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;
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");
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;
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 */
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);
/* 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");
}
/* 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:
}
break;
case R6_OPC_SDBBP:
- generate_exception(ctx, EXCP_DBp);
+ if (ctx->hflags & MIPS_HFLAG_SBRI) {
+ generate_exception(ctx, EXCP_RI);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
break;
#if defined(TARGET_MIPS64)
case OPC_DLSA:
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;
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);
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;
}
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;