> Subject: [PATCH v2 15/33] target/mips: Add emulation of nanoMIPS branch > instructions > > From: Yongbok Kim <yongbok....@mips.com> > > Add emulation of various flavors of nanoMIPS branch instructions. > > Signed-off-by: Yongbok Kim <yongbok....@mips.com> > Signed-off-by: Aleksandar Markovic <amarko...@wavecomp.com> > Signed-off-by: Stefan Markovic <smarko...@wavecomp.com> > --- > target/mips/translate.c | 277 > ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 277 insertions(+) >
After switch-case alignment is fixed: Reviewed-by: Aleksandar Markovic <amarko...@wavecomp.com> > diff --git a/target/mips/translate.c b/target/mips/translate.c > index d48a0cf..e18e279 100644 > --- a/target/mips/translate.c > +++ b/target/mips/translate.c > @@ -16730,6 +16730,168 @@ static void > gen_pool32axf_nanomips_insn(CPUMIPSState *env, > DisasContext *ctx) > } > } > > +/* Immediate Value Compact Branches */ > +static void gen_compute_imm_branch(DisasContext *ctx, uint32_t opc, > + int rt, int32_t imm, int32_t offset) > +{ > + int bcond_compute = 0; > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + > + if (ctx->hflags & MIPS_HFLAG_BMASK) { > +#ifdef MIPS_DEBUG_DISAS > + LOG_DISAS("Branch in delay / forbidden slot at PC 0x" TARGET_FMT_lx > + "\n", ctx->base.pc_next); > +#endif > + generate_exception_end(ctx, EXCP_RI); > + goto out; > + } > + > + gen_load_gpr(t0, rt); > + tcg_gen_movi_tl(t1, imm); > + ctx->btarget = addr_add(ctx, ctx->base.pc_next + 4, offset); > + > + /* Load needed operands and calculate btarget */ > + switch (opc) { > + case NM_BEQIC: > + if (rt == 0 && imm == 0) { > + /* Unconditional branch */ > + } else if (rt == 0 && imm != 0) { > + /* Treat as NOP */ > + goto out; > + } else { > + bcond_compute = 1; > + } > + break; > + case NM_BBEQZC: > + case NM_BBNEZC: > + if (imm >= 32 && !(ctx->hflags & MIPS_HFLAG_64)) { > + generate_exception_end(ctx, EXCP_RI); > + goto out; > + } else if (rt == 0 && opc == NM_BBEQZC) { > + /* Unconditional branch */ > + } else if (rt == 0 && opc == NM_BBNEZC) { > + /* Treat as NOP */ > + goto out; > + } else { > + tcg_gen_shri_tl(t0, t0, imm); > + tcg_gen_andi_tl(t0, t0, 1); > + tcg_gen_movi_tl(t1, 0); > + bcond_compute = 1; > + } > + break; > + case NM_BNEIC: > + if (rt == 0 && imm == 0) { > + /* Treat as NOP */ > + goto out; > + } else if (rt == 0 && imm != 0) { > + /* Unconditional branch */ > + } else { > + bcond_compute = 1; > + } > + break; > + case NM_BGEIC: > + if (rt == 0 && imm == 0) { > + /* Unconditional branch */ > + } else { > + bcond_compute = 1; > + } > + break; > + case NM_BLTIC: > + bcond_compute = 1; > + break; > + case NM_BGEIUC: > + if (rt == 0 && imm == 0) { > + /* Unconditional branch */ > + } else { > + bcond_compute = 1; > + } > + break; > + case NM_BLTIUC: > + bcond_compute = 1; > + break; > + default: > + MIPS_INVAL("Immediate Value Compact branch"); > + generate_exception_end(ctx, EXCP_RI); > + goto out; > + } > + > + if (bcond_compute == 0) { > + /* Uncoditional compact branch */ > + ctx->hflags |= MIPS_HFLAG_B; > + /* Generating branch here as compact branches don't have delay slot > */ > + gen_branch(ctx, 4); > + } else { > + /* Conditional compact branch */ > + TCGLabel *fs = gen_new_label(); > + save_cpu_state(ctx, 0); > + > + switch (opc) { > + case NM_BEQIC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_EQ), t0, t1, fs); > + break; > + case NM_BBEQZC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_EQ), t0, t1, fs); > + break; > + case NM_BNEIC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_NE), t0, t1, fs); > + break; > + case NM_BBNEZC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_NE), t0, t1, fs); > + break; > + case NM_BGEIC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GE), t0, t1, fs); > + break; > + case NM_BLTIC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LT), t0, t1, fs); > + break; > + case NM_BGEIUC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_GEU), t0, t1, fs); > + break; > + case NM_BLTIUC: > + tcg_gen_brcond_tl(tcg_invert_cond(TCG_COND_LTU), t0, t1, fs); > + break; > + } > + > + /* Generating branch here as compact branches don't have delay slot > */ > + gen_goto_tb(ctx, 1, ctx->btarget); > + gen_set_label(fs); > + > + ctx->hflags |= MIPS_HFLAG_FBNSLOT; > + } > + > +out: > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > + > +/* P.BALRSC type nanoMIPS R6 branches: BALRSC and BRSC */ > +static void gen_compute_nanomips_pbalrsc_branch(DisasContext *ctx, int rs, > + int rt) > +{ > + TCGv t0 = tcg_temp_new(); > + TCGv t1 = tcg_temp_new(); > + > + /* load rs */ > + gen_load_gpr(t0, rs); > + > + /* link */ > + if (rt != 0) { > + tcg_gen_movi_tl(cpu_gpr[rt], ctx->base.pc_next + 4); > + } > + > + /* calculate btarget */ > + tcg_gen_shli_tl(t0, t0, 1); > + tcg_gen_movi_tl(t1, ctx->base.pc_next + 4); > + gen_op_addr_add(ctx, btarget, t1, t0); > + > + ctx->hflags |= MIPS_HFLAG_BR; > + /* Generating branch here as compact branches don't have delay slot */ > + gen_branch(ctx, 4); > + > + tcg_temp_free(t0); > + tcg_temp_free(t1); > +} > > static void gen_p_lsx(DisasContext *ctx, int rd, int rs, int rt) > { > @@ -17804,16 +17966,131 @@ static int decode_nanomips_32_48_opc(CPUMIPSState > *env, > DisasContext *ctx) > } > break; > case NM_MOVE_BALC: > + { > + TCGv t0 = tcg_temp_new(); > + int32_t s = sextract32(ctx->opcode, 0, 1) << 21 | > + extract32(ctx->opcode, 1, 20) << 1; > + rd = ((ctx->opcode >> 24) & 1) == 0 ? 4 : 5; > + rt = decode_gpr_gpr4_zero(extract32(ctx->opcode, 25, 1) << 3 | > + extract32(ctx->opcode, 21, 3)); > + gen_load_gpr(t0, rt); > + tcg_gen_mov_tl(cpu_gpr[rd], t0); > + gen_compute_branch(ctx, OPC_BGEZAL, 4, 0, 0, s, 0); > + tcg_temp_free(t0); > + } > break; > case NM_P_BAL: > + { > + int32_t s = sextract32(ctx->opcode, 0, 1) << 25 | > + extract32(ctx->opcode, 1, 24) << 1; > + > + if (((ctx->opcode >> 25) & 1) == 0) { > + /* BC */ > + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, s, 0); > + } else { > + /* BALC */ > + gen_compute_branch(ctx, OPC_BGEZAL, 4, 0, 0, s, 0); > + } > + } > break; > case NM_P_J: > + switch ((ctx->opcode >> 12) & 0x0f) { > + case NM_JALRC: > + case NM_JALRC_HB: > + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 0); > + break; > + case NM_P_BALRSC: > + gen_compute_nanomips_pbalrsc_branch(ctx, rs, rt); > + break; > + default: > + generate_exception_end(ctx, EXCP_RI); > + break; > + } > break; > case NM_P_BR1: > + { > + int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | > + extract32(ctx->opcode, 1, 13) << 1; > + switch ((ctx->opcode >> 14) & 0x03) { > + case NM_BEQC: > + gen_compute_branch(ctx, OPC_BEQ, 4, rs, rt, s, 0); > + break; > + case NM_P_BR3A: > + { > + int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | > + extract32(ctx->opcode, 1, 13) << 1; > + check_cp1_enabled(ctx); > + switch ((ctx->opcode >> 16) & 0x1f) { > + case NM_BC1EQZC: > + gen_compute_branch1_r6(ctx, OPC_BC1EQZ, rt, s, 0); > + break; > + case NM_BC1NEZC: > + gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rt, s, 0); > + break; > + default: > + generate_exception_end(ctx, EXCP_RI); > + break; > + } > + } > + break; > + case NM_BGEC: > + if (rs == rt) { > + gen_compute_compact_branch(ctx, OPC_BC, rs, rt, s); > + } else { > + gen_compute_compact_branch(ctx, OPC_BGEC, rs, rt, s); > + } > + break; > + case NM_BGEUC: > + if (rs == rt || rt == 0) { > + gen_compute_compact_branch(ctx, OPC_BC, 0, 0, s); > + } else if (rs == 0) { > + gen_compute_compact_branch(ctx, OPC_BEQZC, rt, 0, s); > + } else { > + gen_compute_compact_branch(ctx, OPC_BGEUC, rs, rt, s); > + } > + break; > + } > + } > break; > case NM_P_BR2: > + { > + int32_t s = sextract32(ctx->opcode, 0, 1) << 14 | > + extract32(ctx->opcode, 1, 13) << 1; > + switch ((ctx->opcode >> 14) & 0x03) { > + case NM_BNEC: > + gen_compute_branch(ctx, OPC_BNE, 4, rs, rt, s, 0); > + break; > + case NM_BLTC: > + if (rs != 0 && rt != 0 && rs == rt) { > + /* NOP */ > + ctx->hflags |= MIPS_HFLAG_FBNSLOT; > + } else { > + gen_compute_compact_branch(ctx, OPC_BLTC, rs, rt, s); > + } > + break; > + case NM_BLTUC: > + if (rs == 0 || rs == rt) { > + /* NOP */ > + ctx->hflags |= MIPS_HFLAG_FBNSLOT; > + } else { > + gen_compute_compact_branch(ctx, OPC_BLTUC, rs, rt, s); > + } > + break; > + default: > + generate_exception_end(ctx, EXCP_RI); > + break; > + } > + } > break; > case NM_P_BRI: > + { > + int32_t s = sextract32(ctx->opcode, 0, 1) << 11 | > + extract32(ctx->opcode, 1, 10) << 1; > + uint32_t u = extract32(ctx->opcode, 11, 7); > + > + gen_compute_imm_branch(ctx, extract32(ctx->opcode, 18, 3), > + rt, u, s); > + } > break; > default: > generate_exception_end(ctx, EXCP_RI); > -- > 2.7.4 > >