[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches
From: |
Aurelien Jarno |
Subject: |
Re: [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches |
Date: |
Thu, 19 Jun 2014 23:06:46 +0200 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On Wed, Jun 11, 2014 at 04:19:43PM +0100, Leon Alrae wrote:
> From: Yongbok Kim <address@hidden>
>
> Introduce MIPS32R6 Compact Branch instructions which do not have delay slot -
> they have forbidden slot instead. However, current implementation does not
> support forbidden slot yet.
>
> Signed-off-by: Yongbok Kim <address@hidden>
> Signed-off-by: Leon Alrae <address@hidden>
> ---
> v2:
> * rename "handle_delay_slot" to "gen_branch"
> * Compact branches generate branch straightaway
> * improve BOVC/BNVC, BC1EQZ, BC1NEZ implementation
> ---
> disas/mips.c | 67 +++++++-
> target-mips/cpu.h | 5 +-
> target-mips/translate.c | 481
> +++++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 534 insertions(+), 19 deletions(-)
>
> diff --git a/disas/mips.c b/disas/mips.c
> index 127a7d5..bee39d8 100644
> --- a/disas/mips.c
> +++ b/disas/mips.c
> @@ -1250,6 +1250,34 @@ const struct mips_opcode mips_builtin_opcodes[] =
> {"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0,
> I64R6},
> {"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0,
> I32R6},
> {"dbitswap","d,w", 0x7c000024, 0xffe007ff, WR_d|RD_t, 0,
> I64R6},
> +{"balc", "+p", 0xe8000000, 0xfc000000, UBD|WR_31, 0,
> I32R6},
> +{"bc", "+p", 0xc8000000, 0xfc000000, UBD|WR_31, 0,
> I32R6},
> +{"jic", "t,o", 0xd8000000, 0xffe00000, UBD|RD_t, 0,
> I32R6},
> +{"beqzc", "s,+p", 0xd8000000, 0xfc000000, CBD|RD_s, 0,
> I32R6},
> +{"jialc", "t,o", 0xf8000000, 0xffe00000, UBD|RD_t, 0,
> I32R6},
> +{"bnezc", "s,+p", 0xf8000000, 0xfc000000, CBD|RD_s, 0,
> I32R6},
> +{"beqzalc", "s,t,p", 0x20000000, 0xffe00000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bovc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"beqc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bnezalc", "s,t,p", 0x60000000, 0xffe00000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bnvc", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bnec", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"blezc", "s,t,p", 0x58000000, 0xffe00000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bgezc", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bgec", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bgtzc", "s,t,p", 0x5c000000, 0xffe00000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bltzc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bltc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"blezalc", "s,t,p", 0x18000000, 0xffe00000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bgezalc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bgeuc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bgtzalc", "s,t,p", 0x1c000000, 0xffe00000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bltzalc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bltuc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0,
> I32R6},
> +{"bc1eqz", "T,p", 0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0,
> I32R6},
> +{"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0,
> I32R6},
> +{"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0,
> I32R6},
> +{"bc2nez", "E,p", 0x49a00000, 0xffe00000, CBD|RD_C2, 0,
> I32R6},
> {"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0,
> I4|I32|G3 },
> {"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t,
> 0, I4|I33 },
> {"nop", "", 0x00000000, 0xffffffff, 0,
> INSN2_ALIAS, I1 }, /* sll */
> @@ -3616,6 +3644,24 @@ print_insn_args (const char *d,
> (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
> break;
>
> + case 'o':
> + delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6;
> + if (delta & 0x8000) {
> + delta |= ~0xffff;
> + }
> + (*info->fprintf_func) (info->stream, "%d", delta);
> + break;
> +
> + case 'p':
> + /* Sign extend the displacement with 26 bits. */
> + delta = (l >> OP_SH_DELTA) & OP_MASK_TARGET;
> + if (delta & 0x2000000) {
> + delta |= ~0x3FFFFFF;
> + }
> + info->target = (delta << 2) + pc + INSNLEN;
> + (*info->print_address_func) (info->target, info);
> + break;
> +
> case 't': /* Coprocessor 0 reg name */
> (*info->fprintf_func) (info->stream, "%s",
> mips_cp0_names[(l >> OP_SH_RT) &
> @@ -3767,9 +3813,7 @@ print_insn_args (const char *d,
>
> case 'j': /* Same as i, but sign-extended. */
> case 'o':
> - delta = (opp->membership == I32R6) ?
> - (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6 :
> - (l >> OP_SH_DELTA) & OP_MASK_DELTA;
> + delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
>
> if (delta & 0x8000)
> delta |= ~0xffff;
> @@ -4096,6 +4140,23 @@ print_insn_mips (bfd_vma memaddr,
> && strcmp (op->name, "jalx"))
> continue;
>
> + if (strcmp(op->name, "bovc") == 0
> + || strcmp(op->name, "bnvc") == 0) {
> + if (((word >> OP_SH_RS) & OP_MASK_RS) <
> + ((word >> OP_SH_RT) & OP_MASK_RT)) {
> + continue;
> + }
> + }
> + if (strcmp(op->name, "bgezc") == 0
> + || strcmp(op->name, "bltzc") == 0
> + || strcmp(op->name, "bgezalc") == 0
> + || strcmp(op->name, "bltzalc") == 0) {
> + if (((word >> OP_SH_RS) & OP_MASK_RS) !=
> + ((word >> OP_SH_RT) & OP_MASK_RT)) {
> + continue;
> + }
> + }
> +
> /* Figure out instruction type and branch delay information. */
> if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
> {
> diff --git a/target-mips/cpu.h b/target-mips/cpu.h
> index 85ff529..d1e932e 100644
> --- a/target-mips/cpu.h
> +++ b/target-mips/cpu.h
> @@ -466,10 +466,13 @@ struct CPUMIPSState {
> #define MIPS_HFLAG_BDS16 0x08000 /* branch requires 16-bit delay slot */
> #define MIPS_HFLAG_BDS32 0x10000 /* branch requires 32-bit delay slot */
> #define MIPS_HFLAG_BX 0x20000 /* branch exchanges execution mode */
> -#define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
> +#define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT | \
> + MIPS_HFLAG_CB)
> /* MIPS DSP resources access. */
> #define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */
> #define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources.
> */
> +
> +#define MIPS_HFLAG_CB 0x100000 /* Compact branch */
> 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 270e7d3..1226f97 100644
> --- a/target-mips/translate.c
> +++ b/target-mips/translate.c
> @@ -107,6 +107,31 @@ enum {
> OPC_SWC2 = (0x3A << 26),
> OPC_SDC1 = (0x3D << 26),
> OPC_SDC2 = (0x3E << 26),
> + /* Compact Branches */
> + OPC_BLEZALC = (0x06 << 26),
> + OPC_BGEZALC = (0x06 << 26),
> + OPC_BGEUC = (0x06 << 26),
> + OPC_BGTZALC = (0x07 << 26),
> + OPC_BLTZALC = (0x07 << 26),
> + OPC_BLTUC = (0x07 << 26),
> + OPC_BOVC = (0x08 << 26),
> + OPC_BEQZALC = (0x08 << 26),
> + OPC_BEQC = (0x08 << 26),
> + OPC_BLEZC = (0x16 << 26),
> + OPC_BGEZC = (0x16 << 26),
> + OPC_BGEC = (0x16 << 26),
> + OPC_BGTZC = (0x17 << 26),
> + OPC_BLTZC = (0x17 << 26),
> + OPC_BLTC = (0x17 << 26),
> + OPC_BNVC = (0x18 << 26),
> + OPC_BNEZALC = (0x18 << 26),
> + OPC_BNEC = (0x18 << 26),
> + OPC_BC = (0x32 << 26),
> + OPC_BEQZC = (0x36 << 26),
> + OPC_JIC = (0x36 << 26),
> + OPC_BALC = (0x3A << 26),
> + OPC_BNEZC = (0x3E << 26),
> + OPC_JIALC = (0x3E << 26),
> /* MDMX ASE specific */
> OPC_MDMX = (0x1E << 26),
> /* Cache and prefetch */
> @@ -895,6 +920,8 @@ enum {
> OPC_W_FMT = (FMT_W << 21) | OPC_CP1,
> OPC_L_FMT = (FMT_L << 21) | OPC_CP1,
> OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1,
> + OPC_BC1EQZ = (0x09 << 21) | OPC_CP1,
> + OPC_BC1NEZ = (0x0D << 21) | OPC_CP1,
> };
>
> #define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F)
> @@ -929,6 +956,8 @@ enum {
> OPC_CTC2 = (0x06 << 21) | OPC_CP2,
> OPC_MTHC2 = (0x07 << 21) | OPC_CP2,
> OPC_BC2 = (0x08 << 21) | OPC_CP2,
> + OPC_BC2EQZ = (0x09 << 21) | OPC_CP2,
> + OPC_BC2NEZ = (0x0D << 21) | OPC_CP2,
> };
>
> #define MASK_LMI(op) (MASK_OP_MAJOR(op) | (op & (0x1F << 21)) | (op & 0x1F))
> @@ -1391,6 +1420,20 @@ static inline void gen_op_addr_add (DisasContext *ctx,
> TCGv ret, TCGv arg0, TCGv
> #endif
> }
>
> +/* Addresses computation (translation time) */
> +static target_long addr_add(DisasContext *ctx, target_long base,
> + target_long offset)
> +{
> + target_long sum = base + offset;
> +
> +#if defined(TARGET_MIPS64)
> + if (ctx->hflags & MIPS_HFLAG_AWRAP) {
> + sum = (int32_t)sum;
> + }
> +#endif
> + return sum;
> +}
> +
> static inline void check_cp0_enabled(DisasContext *ctx)
> {
> if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
> @@ -3907,7 +3950,13 @@ 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);
> + if (ctx->hflags & MIPS_HFLAG_CB) {
> + LOG_DISAS("Branch in forbidden slot at PC 0x" TARGET_FMT_lx "\n",
> + ctx->pc);
> + } else {
> + LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
> + ctx->pc);
> + }
> #endif
> generate_exception(ctx, EXCP_RI);
> goto out;
> @@ -7390,6 +7439,45 @@ static void gen_compute_branch1(DisasContext *ctx,
> uint32_t op,
> tcg_temp_free_i32(t0);
> }
>
> +/* R6 CP1 Branches (before delay slot) */
> +static void gen_compute_branch1_r6(DisasContext *ctx, uint32_t op,
> + int32_t ft, int32_t offset)
> +{
> + target_ulong btarget;
> + const char *opn = "cp1 cond branch";
> +
> + TCGv_i64 t0 = tcg_temp_new_i64();
> + gen_load_fpr64(ctx, t0, ft);
> + tcg_gen_andi_i64(t0, t0, 1);
> +
> + btarget = addr_add(ctx, ctx->pc + 4, offset);
> +
> + switch (op) {
> + case OPC_BC1EQZ:
> + tcg_gen_xori_i64(t0, t0, 1);
> + opn = "bc1eqz";
> + ctx->hflags |= MIPS_HFLAG_BC;
> + break;
> + case OPC_BC1NEZ:
> + tcg_gen_mov_i64(t0, t0);
I suggested that, though it's basically useless. This could simply be
removed.
> + opn = "bc1nez";
> + ctx->hflags |= MIPS_HFLAG_BC;
> + break;
> + default:
> + MIPS_INVAL(opn);
> + generate_exception(ctx, EXCP_RI);
> + return;
> + }
> +
> + tcg_gen_trunc_i64_tl(bcond, t0);
> + tcg_temp_free_i64(t0);
> +
> + (void)opn; /* avoid a compiler warning */
> + MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
> + ctx->hflags, btarget);
> + ctx->btarget = btarget;
> +}
> +
> /* Coprocessor 1 (FPU) */
>
> #define FOP(func, fmt) (((fmt) << 21) | (func))
> @@ -9387,7 +9475,7 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
> tcg_temp_free(t0);
> }
>
> -static void handle_delay_slot(DisasContext *ctx, int insn_bytes)
> +static void gen_branch(DisasContext *ctx, int insn_bytes)
> {
> if (ctx->hflags & MIPS_HFLAG_BMASK) {
> int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK;
> @@ -14706,6 +14794,252 @@ static void gen_mipsdsp_accinsn(DisasContext *ctx,
> uint32_t op1, uint32_t op2,
>
> /* End MIPSDSP functions. */
>
> +/* Compact Branches */
> +static void gen_compute_compact_branch(DisasContext *ctx, uint32_t opc,
> + int rs, int rt, int32_t offset)
> +{
> + target_ulong btgt = -1;
> + int blink = 0;
> + int bcond_compute = 0;
> + TCGv t0 = tcg_temp_new();
> + TCGv t1 = tcg_temp_new();
> +
> + if (ctx->hflags & MIPS_HFLAG_BMASK) {
> +#ifdef MIPS_DEBUG_DISAS
> + if (ctx->hflags & MIPS_HFLAG_CB) {
> + LOG_DISAS("Branch in forbidden slot at PC 0x" TARGET_FMT_lx "\n",
> + ctx->pc);
> + } else {
> + LOG_DISAS("Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
> + ctx->pc);
> + }
> +#endif
> + generate_exception(ctx, EXCP_RI);
> + goto out;
> + }
> +
> + /* Load needed operands */
> + switch (opc) {
> + /* compact branch */
> + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */
> + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */
> + gen_load_gpr(t0, rs);
> + gen_load_gpr(t1, rt);
> + bcond_compute = 1;
> + btgt = addr_add(ctx, ctx->pc + 4, offset);
> + if (rs <= rt && rs == 0) {
> + /* OPC_BEQZALC, OPC_BNEZALC */
> + blink = 31;
> + }
> + break;
> + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */
> + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */
> + gen_load_gpr(t0, rs);
> + gen_load_gpr(t1, rt);
> + bcond_compute = 1;
> + btgt = addr_add(ctx, ctx->pc + 4, offset);
> + break;
> + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */
> + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */
> + if (rs == 0 || rs == rt) {
> + /* OPC_BLEZALC, OPC_BGEZALC */
> + /* OPC_BGTZALC, OPC_BLTZALC */
> + blink = 31;
> + }
> + gen_load_gpr(t0, rs);
> + gen_load_gpr(t1, rt);
> + bcond_compute = 1;
> + btgt = addr_add(ctx, ctx->pc + 4, offset);
> + break;
> + case OPC_BC:
> + case OPC_BALC:
> + btgt = addr_add(ctx, ctx->pc + 4, offset);
> + break;
> + case OPC_BEQZC:
> + case OPC_BNEZC:
> + if (rs != 0) {
> + /* OPC_BEQZC, OPC_BNEZC */
> + gen_load_gpr(t0, rs);
> + bcond_compute = 1;
> + btgt = addr_add(ctx, ctx->pc + 4, offset);
> + } else {
> + /* OPC_JIC, OPC_JIALC */
> + TCGv tbase = tcg_temp_new();
> + TCGv toffset = tcg_temp_new();
> +
> + gen_load_gpr(tbase, rt);
> + tcg_gen_movi_tl(toffset, offset);
> + gen_op_addr_add(ctx, btarget, tbase, toffset);
> + tcg_temp_free(tbase);
> + tcg_temp_free(toffset);
> + }
> + break;
> + default:
> + MIPS_INVAL("branch/jump");
> + generate_exception(ctx, EXCP_RI);
> + goto out;
> + }
> +
> + ctx->hflags |= MIPS_HFLAG_CB;
> +
> + if (bcond_compute == 0) {
> + /* No condition to be computed */
> + switch (opc) {
> + /* compact branches */
> + case OPC_JIALC:
> + blink = 31;
> + /* Fallthrough */
> + case OPC_JIC:
> + ctx->hflags |= MIPS_HFLAG_BR;
> + break;
> + case OPC_BALC:
> + blink = 31;
> + /* Fallthrough */
> + case OPC_BC:
> + ctx->hflags |= MIPS_HFLAG_B;
> + /* Always take and link */
> + break;
> + default:
> + MIPS_INVAL("branch/jump");
> + generate_exception(ctx, EXCP_RI);
> + goto out;
> + }
> + } else {
> + ctx->hflags |= MIPS_HFLAG_BC;
> +
> + switch (opc) {
> + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC */
> + if (rs == 0 && rt != 0) {
> + /* OPC_BLEZALC */
> + tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t1, 0);
> + } else if (rs != 0 && rt != 0 && rs == rt) {
> + /* OPC_BGEZALC */
> + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t1, 0);
> + } else {
> + /* OPC_BGEUC */
> + tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1);
> + }
> + break;
> + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC */
> + if (rs == 0 && rt != 0) {
> + /* OPC_BGTZALC */
> + tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t1, 0);
> + } else if (rs != 0 && rt != 0 && rs == rt) {
> + /* OPC_BLTZALC */
> + tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t1, 0);
> + } else {
> + /* OPC_BLTUC */
> + tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1);
> + }
> + break;
> + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC */
> + if (rs == 0 && rt != 0) {
> + /* OPC_BLEZC */
> + tcg_gen_setcondi_tl(TCG_COND_LE, bcond, t1, 0);
> + } else if (rs != 0 && rt != 0 && rs == rt) {
> + /* OPC_BGEZC */
> + tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t1, 0);
> + } else {
> + /* OPC_BGEC */
> + tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1);
> + }
> + break;
> + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC */
> + if (rs == 0 && rt != 0) {
> + /* OPC_BGTZC */
> + tcg_gen_setcondi_tl(TCG_COND_GT, bcond, t1, 0);
> + } else if (rs != 0 && rt != 0 && rs == rt) {
> + /* OPC_BLTZC */
> + tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t1, 0);
> + } else {
> + /* OPC_BLTC */
> + tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1);
> + }
> + break;
> + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC */
> + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */
> + if (rs >= rt) {
> + /* OPC_BOVC, OPC_BNVC */
> + TCGv t2 = tcg_temp_new();
> + TCGv t3 = tcg_temp_new();
> + TCGv t4 = tcg_temp_new();
> + TCGv input_overflow = tcg_temp_new();
> +
> + gen_load_gpr(t0, rs);
> + gen_load_gpr(t1, rt);
> + tcg_gen_ext32s_tl(t2, t0);
> + tcg_gen_setcond_tl(TCG_COND_NE, input_overflow, t2, t0);
> + tcg_gen_ext32s_tl(t3, t1);
> + tcg_gen_setcond_tl(TCG_COND_NE, t4, t3, t1);
> + tcg_gen_or_tl(input_overflow, input_overflow, t4);
> +
> + tcg_gen_add_tl(t4, t2, t3);
> + tcg_gen_ext32s_tl(t4, t4);
> + tcg_gen_xor_tl(t2, t2, t3);
> + tcg_gen_xor_tl(t3, t4, t3);
> + tcg_gen_andc_tl(t2, t3, t2);
> + tcg_gen_setcondi_tl(TCG_COND_LT, t4, t2, 0);
> + if (opc == OPC_BOVC) {
> + /* OPC_BOVC */
> + tcg_gen_or_tl(bcond, t4, input_overflow);
> + } else {
> + /* OPC_BNVC */
> + tcg_gen_or_tl(t4, t4, input_overflow);
> + tcg_gen_xori_tl(bcond, t4, 1);
> + }
> + tcg_temp_free(input_overflow);
> + tcg_temp_free(t4);
> + tcg_temp_free(t3);
> + tcg_temp_free(t2);
> + } else if (rs < rt && rs == 0) {
> + /* OPC_BEQZALC, OPC_BNEZALC */
> + if (opc == OPC_BEQZALC) {
> + /* OPC_BEQZALC */
> + tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t1, 0);
> + } else {
> + /* OPC_BNEZALC */
> + tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t1, 0);
> + }
> + } else {
> + /* OPC_BEQC, OPC_BNEC */
> + if (opc == OPC_BEQC) {
> + /* OPC_BEQC */
> + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> + } else {
> + /* OPC_BNEC */
> + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> + }
> + }
> + break;
> + case OPC_BEQZC:
> + tcg_gen_setcondi_tl(TCG_COND_EQ, bcond, t0, 0);
> + break;
> + case OPC_BNEZC:
> + tcg_gen_setcondi_tl(TCG_COND_NE, bcond, t0, 0);
> + break;
> + default:
> + MIPS_INVAL("conditional branch/jump");
> + generate_exception(ctx, EXCP_RI);
> + goto out;
> + }
> + }
> + MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
> + blink, ctx->hflags, btgt);
> +
> + ctx->btarget = btgt;
> + if (blink > 0) {
> + tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + 4);
> + }
> +
> + /* Compact branches don't have delay slot, thus generating branch here */
> + /* TODO: implement forbidden slot */
> + gen_branch(ctx, 4);
> +
> +out:
> + tcg_temp_free(t0);
> + tcg_temp_free(t1);
> +}
> +
> static void decode_opc_special_r6(CPUMIPSState *env, DisasContext *ctx)
> {
> int rs, rt, rd, sa;
> @@ -16011,7 +16345,16 @@ static void decode_opc (CPUMIPSState *env,
> DisasContext *ctx)
> break;
> }
> break;
> - case OPC_ADDI: /* Arithmetic with immediate opcode */
> + case OPC_BOVC: /* OPC_BEQZALC, OPC_BEQC, OPC_ADDI */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + /* OPC_BOVC, OPC_BEQZALC, OPC_BEQC */
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + } else {
> + /* OPC_ADDI */
> + /* Arithmetic with immediate opcode */
> + gen_arith_imm(ctx, op, rt, rs, imm);
> + }
> + break;
> case OPC_ADDIU:
> gen_arith_imm(ctx, op, rt, rs, imm);
> break;
> @@ -16029,9 +16372,58 @@ static void decode_opc (CPUMIPSState *env,
> DisasContext *ctx)
> offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
> gen_compute_branch(ctx, op, 4, rs, rt, offset);
> break;
> - case OPC_BEQL ... OPC_BGTZL: /* Branch */
> + /* Branch */
> + case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + if (rt == 0) {
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> + /* OPC_BLEZC, OPC_BGEZC, OPC_BGEC */
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + } else {
> + /* OPC_BLEZL */
> + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> + }
> + break;
> + case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + if (rt == 0) {
> + generate_exception(ctx, EXCP_RI);
> + break;
> + }
> + /* OPC_BGTZC, OPC_BLTZC, OPC_BLTC */
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + } else {
> + /* OPC_BGTZL */
> + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> + }
> + break;
> + case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */
> + if (rt == 0) {
> + /* OPC_BLEZ */
> + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> + } else {
> + check_insn(ctx, ISA_MIPS32R6);
> + /* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + }
> + break;
> + case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */
> + if (rt == 0) {
> + /* OPC_BGTZ */
> + gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> + } else {
> + check_insn(ctx, ISA_MIPS32R6);
> + /* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + }
> + break;
> + case OPC_BEQL:
> + case OPC_BNEL:
> check_insn_opc_removed(ctx, ISA_MIPS32R6);
> - case OPC_BEQ ... OPC_BGTZ:
> + case OPC_BEQ:
> + case OPC_BNE:
> gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
> break;
> case OPC_LWL: /* Load and stores */
> @@ -16094,7 +16486,24 @@ static void decode_opc (CPUMIPSState *env,
> DisasContext *ctx)
> gen_cp1(ctx, op1, rt, rd);
> break;
> #endif
> - case OPC_BC1ANY2:
> + case OPC_BC1EQZ: /* OPC_BC1ANY2 */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + /* OPC_BC1EQZ */
> + gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
> + rt, imm << 2);
> + } else {
> + /* OPC_BC1ANY2 */
> + check_cop1x(ctx);
> + check_insn(ctx, ASE_MIPS3D);
> + gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
> + (rt >> 2) & 0x7, imm << 2);
> + }
> + break;
> + case OPC_BC1NEZ:
> + check_insn(ctx, ISA_MIPS32R6);
> + gen_compute_branch1_r6(ctx, MASK_CP1(ctx->opcode),
> + rt, imm << 2);
> + break;
> case OPC_BC1ANY4:
> check_insn_opc_removed(ctx, ISA_MIPS32R6);
> check_cop1x(ctx);
> @@ -16124,13 +16533,35 @@ static void decode_opc (CPUMIPSState *env,
> DisasContext *ctx)
> }
> break;
>
> - /* COP2. */
> - case OPC_LWC2:
> - case OPC_LDC2:
> - case OPC_SWC2:
> - case OPC_SDC2:
> - /* COP2: Not implemented. */
> - generate_exception_err(ctx, EXCP_CpU, 2);
> + /* Compact branches [R6] and COP2 [non-R6] */
> + case OPC_BC: /* OPC_LWC2 */
> + case OPC_BALC: /* OPC_SWC2 */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + /* OPC_BC, OPC_BALC */
> + gen_compute_compact_branch(ctx, op, 0, 0,
> + SIMM((ctx->opcode & 0x3FFFFFF) << 2, 0,
> 28));
> + } else {
> + /* OPC_LWC2, OPC_SWC2 */
> + /* COP2: Not implemented. */
> + generate_exception_err(ctx, EXCP_CpU, 2);
> + }
> + break;
> + case OPC_BEQZC: /* OPC_JIC, OPC_LDC2 */
> + case OPC_BNEZC: /* OPC_JIALC, OPC_SDC2 */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + if (rs != 0) {
> + /* OPC_BEQZC, OPC_BNEZC */
> + gen_compute_compact_branch(ctx, op, rs, 0,
> + SIMM((ctx->opcode & 0x1FFFFF) << 2, 0,
> 23));
> + } else {
> + /* OPC_JIC, OPC_JIALC */
> + gen_compute_compact_branch(ctx, op, 0, rt, imm);
> + }
> + } else {
> + /* OPC_LWC2, OPC_SWC2 */
> + /* COP2: Not implemented. */
> + generate_exception_err(ctx, EXCP_CpU, 2);
> + }
> break;
> case OPC_CP2:
> check_insn(ctx, INSN_LOONGSON2F);
> @@ -16204,12 +16635,31 @@ static void decode_opc (CPUMIPSState *env,
> DisasContext *ctx)
> check_mips_64(ctx);
> gen_st_cond(ctx, op, rt, rs, imm);
> break;
> - case OPC_DADDI:
> + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC, OPC_DADDI */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + /* OPC_BNVC, OPC_BNEZALC, OPC_BNEC */
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + } else {
> + /* OPC_DADDI */
> + check_insn(ctx, ISA_MIPS3);
> + check_mips_64(ctx);
> + gen_arith_imm(ctx, op, rt, rs, imm);
> + }
> + break;
> case OPC_DADDIU:
> check_insn(ctx, ISA_MIPS3);
> check_mips_64(ctx);
> gen_arith_imm(ctx, op, rt, rs, imm);
> break;
> +#else
> + case OPC_BNVC: /* OPC_BNEZALC, OPC_BNEC */
> + if (ctx->insn_flags & ISA_MIPS32R6) {
> + gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
> + } else {
> + MIPS_INVAL("major opcode");
> + generate_exception(ctx, EXCP_RI);
> + }
> + break;
> #endif
> case OPC_JALX:
> check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);
> @@ -16314,8 +16764,9 @@ gen_intermediate_code_internal(MIPSCPU *cpu,
> TranslationBlock *tb,
> ctx.bstate = BS_STOP;
> break;
> }
> +
> if (is_delay) {
> - handle_delay_slot(&ctx, insn_bytes);
> + gen_branch(&ctx, insn_bytes);
> }
> ctx.pc += insn_bytes;
>
> --
> 1.7.5.4
>
>
--
Aurelien Jarno GPG: 4096R/1DDD8C9B
address@hidden http://www.aurel32.net
- [Qemu-devel] [PATCH v2 08/22] target-mips: move PREF, CACHE, LLD and SCD instructions, (continued)
- [Qemu-devel] [PATCH v2 08/22] target-mips: move PREF, CACHE, LLD and SCD instructions, Leon Alrae, 2014/06/11
- [Qemu-devel] [PATCH v2 10/22] target-mips: move CLO, DCLO, CLZ, DCLZ, SDBBP and free special2 in R6, Leon Alrae, 2014/06/11
- [Qemu-devel] [PATCH v2 05/22] target-mips: extract decode_opc_special* from decode_opc, Leon Alrae, 2014/06/11
- [Qemu-devel] [PATCH v2 11/22] target-mips: Status.UX/SX/KX enable 32-bit address wrapping, Leon Alrae, 2014/06/11
- [Qemu-devel] [PATCH v2 09/22] target-mips: redefine Integer Multiply and Divide instructions, Leon Alrae, 2014/06/11
- [Qemu-devel] [PATCH v2 13/22] target-mips: add Compact Branches, Leon Alrae, 2014/06/11
- [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions, Leon Alrae, 2014/06/11
- Re: [Qemu-devel] [PATCH v2 12/22] target-mips: add ALIGN, DALIGN, BITSWAP and DBITSWAP instructions, Aurelien Jarno, 2014/06/19
- [Qemu-devel] [PATCH v2 14/22] target-mips: add Addressing and PC-relative instructions, Leon Alrae, 2014/06/11