On Mon, Aug 20, 2018 at 8:17 PM Aleksandar Markovic
<aleksandar.marko...@rt-rk.com> wrote:
>
> From: Stefan Markovic <smarko...@wavecomp.com>
>
> Add emulation of nanoMIPS 16-bit branch instructions.
>
> Reviewed-by: Richard Henderson <richard.hender...@linaro.org>
> 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 | 158 
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 158 insertions(+)
>
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 261680e..b0bbf4c 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -4564,6 +4564,128 @@ static void gen_compute_branch (DisasContext *ctx, 
> uint32_t opc,
>      tcg_temp_free(t1);
>  }
>
> +
> +/* nanoMIPS Branches */
> +static void gen_compute_branch_nm(DisasContext *ctx, uint32_t opc,
> +                                int insn_bytes,
> +                                int rs, int rt, int32_t offset)
> +{
> +    target_ulong btgt = -1;
> +    int bcond_compute = 0;
> +    TCGv t0 = tcg_temp_new();
> +    TCGv t1 = tcg_temp_new();
> +
> +    /* Load needed operands */
> +    switch (opc) {
> +    case OPC_BEQ:
> +    case OPC_BNE:
> +        /* Compare two registers */
> +        if (rs != rt) {
> +            gen_load_gpr(t0, rs);
> +            gen_load_gpr(t1, rt);
> +            bcond_compute = 1;
> +        }
> +        btgt = ctx->base.pc_next + insn_bytes + offset;
> +        break;
> +    case OPC_BGEZAL:
> +        /* Compare to zero */
> +        if (rs != 0) {
> +            gen_load_gpr(t0, rs);
> +            bcond_compute = 1;
> +        }
> +        btgt = ctx->base.pc_next + insn_bytes + offset;
> +        break;
> +    case OPC_BPOSGE32:
> +        tcg_gen_andi_tl(t0, cpu_dspctrl, 0x3F);
> +        bcond_compute = 1;
> +        btgt = ctx->base.pc_next + insn_bytes + offset;
> +        break;
> +    case OPC_JR:
> +    case OPC_JALR:
> +        /* Jump to register */
> +        if (offset != 0 && offset != 16) {
> +            /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
> +               others are reserved. */
> +            MIPS_INVAL("jump hint");
> +            generate_exception_end(ctx, EXCP_RI);
> +            goto out;
> +        }
> +        gen_load_gpr(btarget, rs);
> +        break;
> +    default:
> +        MIPS_INVAL("branch/jump");
> +        generate_exception_end(ctx, EXCP_RI);
> +        goto out;
> +    }
> +    if (bcond_compute == 0) {
> +        /* No condition to be computed */
> +        switch (opc) {
> +        case OPC_BEQ:     /* rx == rx        */
> +            /* Always take */
> +            ctx->hflags |= MIPS_HFLAG_B;
> +            break;
> +        case OPC_BGEZAL:  /* 0 >= 0          */
> +            /* Always take and link */
> +            tcg_gen_movi_tl(cpu_gpr[31],
> +                            ctx->base.pc_next + insn_bytes);
> +            ctx->hflags |= MIPS_HFLAG_B;
> +            break;
> +        case OPC_BNE:     /* rx != rx        */
> +            tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 8);
> +            /* Skip the instruction in the delay slot */
> +            ctx->base.pc_next += 4;
> +            goto out;
> +        case OPC_JR:
> +            ctx->hflags |= MIPS_HFLAG_BR;
> +            break;
> +        case OPC_JALR:
> +            if (rt > 0) {
> +                tcg_gen_movi_tl(cpu_gpr[rt],
> +                                ctx->base.pc_next + insn_bytes);
> +            }
> +            ctx->hflags |= MIPS_HFLAG_BR;
> +            break;
> +        default:
> +            MIPS_INVAL("branch/jump");
> +            generate_exception_end(ctx, EXCP_RI);
> +            goto out;
> +        }
> +    } else {
> +        switch (opc) {
> +        case OPC_BEQ:
> +            tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1);
> +            goto not_likely;
> +        case OPC_BNE:
> +            tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1);
> +            goto not_likely;
> +        case OPC_BGEZAL:
> +            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
> +            tcg_gen_movi_tl(cpu_gpr[31],
> +                            ctx->base.pc_next + insn_bytes);
> +            goto not_likely;
> +        case OPC_BPOSGE32:
> +            tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 32);

This opcode implementation seems incomplete, per the ISA manual:

If a control transfer instruction (CTI) is executed in the forbidden
slot of a branch or jump, Release 6 implementations are required to
signal a Reserved Instruction Exception. A CTI is considered to be one
of the following instructions: branch, jump, NAL (Release 6), ERET,
ERETNC (Release 5), DERET, WAIT, or PAUSE (Release 2). An instruction
is in the forbidden slot if it is the instruction following the
branch.

> +        not_likely:
> +            ctx->hflags |= MIPS_HFLAG_BC;
> +            break;
> +        default:
> +            MIPS_INVAL("conditional branch/jump");
> +            generate_exception_end(ctx, EXCP_RI);
> +            goto out;
> +        }
> +    }
> +
> +    ctx->btarget = btgt;
> +
> + out:
> +    if (insn_bytes == 2) {
> +        ctx->hflags |= MIPS_HFLAG_B16;
> +    }
> +    tcg_temp_free(t0);
> +    tcg_temp_free(t1);
> +}

Reply via email to