Commit 8340f534 authored by Richard Henderson's avatar Richard Henderson
Browse files

target/hppa: Convert direct and indirect branches

parent 30878590
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
%assemble_sr3x  13:1 14:2 !function=expand_sr3x

%assemble_12    0:s1 2:1 3:10        !function=expand_shl2
%assemble_17    0:s1 16:5 2:1 3:10   !function=expand_shl2
%assemble_22    0:s1 16:10 2:1 3:10  !function=expand_shl2

%sm_imm         16:10 !function=expand_sm_imm

@@ -210,3 +212,33 @@ depw_sar 110101 t:5 r:5 c:3 00 nz:1 00000 clen:5
depw_imm        110101 t:5 r:5   c:3 01 nz:1 cpos:5 clen:5
depwi_sar       110101 t:5 ..... c:3 10 nz:1 00000  clen:5      i=%im5_16
depwi_imm       110101 t:5 ..... c:3 11 nz:1 cpos:5 clen:5      i=%im5_16

####
# Branch External
####

&BE             b l n disp sp
@be             ...... b:5 ..... ... ........... n:1 .  \
                &BE disp=%assemble_17 sp=%assemble_sr3

be              111000 ..... ..... ... ........... . .  @be l=0
be              111001 ..... ..... ... ........... . .  @be l=31

####
# Branch
####

&BL             l n disp
@bl             ...... l:5 ..... ... ........... n:1 .  &BL disp=%assemble_17

# B,L and B,L,PUSH
bl              111010 ..... ..... 000 ........... .   .        @bl
bl              111010 ..... ..... 100 ........... .   .        @bl
# B,L (long displacement)
bl              111010 ..... ..... 101 ........... n:1 .        &BL l=2 \
                disp=%assemble_22
b_gate          111010 ..... ..... 001 ........... .   .        @bl
blr             111010 l:5   x:5   010 00000000000 n:1 0
bv              111010 b:5   x:5   110 00000000000 n:1 0
bve             111010 b:5   00000 110 10000000000 n:1 -        l=0
bve             111010 b:5   00000 111 10000000000 n:1 -        l=2
+30 −101
Original line number Diff line number Diff line
@@ -895,15 +895,6 @@ static target_sreg assemble_16a(uint32_t insn)
    return x << 2;
}

static target_sreg assemble_17(uint32_t insn)
{
    target_ureg x = -(target_ureg)(insn & 1);
    x = (x <<  5) | extract32(insn, 16, 5);
    x = (x <<  1) | extract32(insn, 2, 1);
    x = (x << 10) | extract32(insn, 3, 10);
    return x << 2;
}

static target_sreg assemble_21(uint32_t insn)
{
    target_ureg x = -(target_ureg)(insn & 1);
@@ -914,15 +905,6 @@ static target_sreg assemble_21(uint32_t insn)
    return x << 11;
}

static target_sreg assemble_22(uint32_t insn)
{
    target_ureg x = -(target_ureg)(insn & 1);
    x = (x << 10) | extract32(insn, 16, 10);
    x = (x <<  1) | extract32(insn, 2, 1);
    x = (x << 10) | extract32(insn, 3, 10);
    return x << 2;
}

/* The parisc documentation describes only the general interpretation of
   the conditions, without describing their exact implementation.  The
   interpretations do not stand up well when considering ADD,C and SUB,B.
@@ -3546,11 +3528,8 @@ static bool trans_depwi_sar(DisasContext *ctx, arg_depwi_sar *a)
    return do_depw_sar(ctx, a->t, a->c, a->nz, a->clen, load_const(ctx, a->i));
}

static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
static bool trans_be(DisasContext *ctx, arg_be *a)
{
    unsigned n = extract32(insn, 1, 1);
    unsigned b = extract32(insn, 21, 5);
    target_sreg disp = assemble_17(insn);
    TCGv_reg tmp;

#ifdef CONFIG_USER_ONLY
@@ -3562,29 +3541,28 @@ static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
    /* Since we don't implement spaces, just branch.  Do notice the special
       case of "be disp(*,r0)" using a direct branch to disp, so that we can
       goto_tb to the TB containing the syscall.  */
    if (b == 0) {
        return do_dbranch(ctx, disp, is_l ? 31 : 0, n);
    if (a->b == 0) {
        return do_dbranch(ctx, a->disp, a->l, a->n);
    }
#else
    int sp = assemble_sr3(insn);
    nullify_over(ctx);
#endif

    tmp = get_temp(ctx);
    tcg_gen_addi_reg(tmp, load_gpr(ctx, b), disp);
    tcg_gen_addi_reg(tmp, load_gpr(ctx, a->b), a->disp);
    tmp = do_ibranch_priv(ctx, tmp);

#ifdef CONFIG_USER_ONLY
    return do_ibranch(ctx, tmp, is_l ? 31 : 0, n);
    return do_ibranch(ctx, tmp, a->l, a->n);
#else
    TCGv_i64 new_spc = tcg_temp_new_i64();

    load_spr(ctx, new_spc, sp);
    if (is_l) {
    load_spr(ctx, new_spc, a->sp);
    if (a->l) {
        copy_iaoq_entry(cpu_gr[31], ctx->iaoq_n, ctx->iaoq_n_var);
        tcg_gen_mov_i64(cpu_sr[0], cpu_iasq_f);
    }
    if (n && use_nullify_skip(ctx)) {
    if (a->n && use_nullify_skip(ctx)) {
        tcg_gen_mov_reg(cpu_iaoq_f, tmp);
        tcg_gen_addi_reg(cpu_iaoq_b, cpu_iaoq_f, 4);
        tcg_gen_mov_i64(cpu_iasq_f, new_spc);
@@ -3596,7 +3574,7 @@ static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
        }
        tcg_gen_mov_reg(cpu_iaoq_b, tmp);
        tcg_gen_mov_i64(cpu_iasq_b, new_spc);
        nullify_set(ctx, n);
        nullify_set(ctx, a->n);
    }
    tcg_temp_free_i64(new_spc);
    tcg_gen_lookup_and_goto_ptr();
@@ -3605,22 +3583,14 @@ static bool trans_be(DisasContext *ctx, uint32_t insn, bool is_l)
#endif
}

static bool trans_bl(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
static bool trans_bl(DisasContext *ctx, arg_bl *a)
{
    unsigned n = extract32(insn, 1, 1);
    unsigned link = extract32(insn, 21, 5);
    target_sreg disp = assemble_17(insn);

    do_dbranch(ctx, iaoq_dest(ctx, disp), link, n);
    return true;
    return do_dbranch(ctx, iaoq_dest(ctx, a->disp), a->l, a->n);
}

static bool trans_b_gate(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
static bool trans_b_gate(DisasContext *ctx, arg_b_gate *a)
{
    unsigned n = extract32(insn, 1, 1);
    unsigned link = extract32(insn, 21, 5);
    target_sreg disp = assemble_17(insn);
    target_ureg dest = iaoq_dest(ctx, disp);
    target_ureg dest = iaoq_dest(ctx, a->disp);

    /* Make sure the caller hasn't done something weird with the queue.
     * ??? This is not quite the same as the PSW[B] bit, which would be
@@ -3659,65 +3629,44 @@ static bool trans_b_gate(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
    }
#endif

    do_dbranch(ctx, dest, link, n);
    return true;
    return do_dbranch(ctx, dest, a->l, a->n);
}

static bool trans_bl_long(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
static bool trans_blr(DisasContext *ctx, arg_blr *a)
{
    unsigned n = extract32(insn, 1, 1);
    target_sreg disp = assemble_22(insn);

    do_dbranch(ctx, iaoq_dest(ctx, disp), 2, n);
    return true;
}

static bool trans_blr(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
{
    unsigned n = extract32(insn, 1, 1);
    unsigned rx = extract32(insn, 16, 5);
    unsigned link = extract32(insn, 21, 5);
    TCGv_reg tmp = get_temp(ctx);

    tcg_gen_shli_reg(tmp, load_gpr(ctx, rx), 3);
    tcg_gen_shli_reg(tmp, load_gpr(ctx, a->x), 3);
    tcg_gen_addi_reg(tmp, tmp, ctx->iaoq_f + 8);
    /* The computation here never changes privilege level.  */
    do_ibranch(ctx, tmp, link, n);
    return true;
    return do_ibranch(ctx, tmp, a->l, a->n);
}

static bool trans_bv(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
static bool trans_bv(DisasContext *ctx, arg_bv *a)
{
    unsigned n = extract32(insn, 1, 1);
    unsigned rx = extract32(insn, 16, 5);
    unsigned rb = extract32(insn, 21, 5);
    TCGv_reg dest;

    if (rx == 0) {
        dest = load_gpr(ctx, rb);
    if (a->x == 0) {
        dest = load_gpr(ctx, a->b);
    } else {
        dest = get_temp(ctx);
        tcg_gen_shli_reg(dest, load_gpr(ctx, rx), 3);
        tcg_gen_add_reg(dest, dest, load_gpr(ctx, rb));
        tcg_gen_shli_reg(dest, load_gpr(ctx, a->x), 3);
        tcg_gen_add_reg(dest, dest, load_gpr(ctx, a->b));
    }
    dest = do_ibranch_priv(ctx, dest);
    do_ibranch(ctx, dest, 0, n);
    return true;
    return do_ibranch(ctx, dest, 0, a->n);
}

static bool trans_bve(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
static bool trans_bve(DisasContext *ctx, arg_bve *a)
{
    unsigned n = extract32(insn, 1, 1);
    unsigned rb = extract32(insn, 21, 5);
    unsigned link = extract32(insn, 13, 1) ? 2 : 0;
    TCGv_reg dest;

#ifdef CONFIG_USER_ONLY
    dest = do_ibranch_priv(ctx, load_gpr(ctx, rb));
    do_ibranch(ctx, dest, link, n);
    dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));
    return do_ibranch(ctx, dest, a->l, a->n);
#else
    nullify_over(ctx);
    dest = do_ibranch_priv(ctx, load_gpr(ctx, rb));
    dest = do_ibranch_priv(ctx, load_gpr(ctx, a->b));

    copy_iaoq_entry(cpu_iaoq_f, ctx->iaoq_b, cpu_iaoq_b);
    if (ctx->iaoq_b == -1) {
@@ -3725,26 +3674,16 @@ static bool trans_bve(DisasContext *ctx, uint32_t insn, const DisasInsn *di)
    }
    copy_iaoq_entry(cpu_iaoq_b, -1, dest);
    tcg_gen_mov_i64(cpu_iasq_b, space_select(ctx, 0, dest));
    if (link) {
        copy_iaoq_entry(cpu_gr[link], ctx->iaoq_n, ctx->iaoq_n_var);
    if (a->l) {
        copy_iaoq_entry(cpu_gr[a->l], ctx->iaoq_n, ctx->iaoq_n_var);
    }
    nullify_set(ctx, n);
    nullify_set(ctx, a->n);
    tcg_gen_lookup_and_goto_ptr();
    ctx->base.is_jmp = DISAS_NORETURN;
    return nullify_end(ctx);
#endif
    return true;
}

static const DisasInsn table_branch[] = {
    { 0xe8000000u, 0xfc006000u, trans_bl }, /* B,L and B,L,PUSH */
    { 0xe800a000u, 0xfc00e000u, trans_bl_long },
    { 0xe8004000u, 0xfc00fffdu, trans_blr },
    { 0xe800c000u, 0xfc00fffdu, trans_bv },
    { 0xe800d000u, 0xfc00dffcu, trans_bve },
    { 0xe8002000u, 0xfc00e000u, trans_b_gate },
};

static bool trans_fop_wew_0c(DisasContext *ctx, uint32_t insn,
                             const DisasInsn *di)
{
@@ -4422,16 +4361,6 @@ static void translate_one(DisasContext *ctx, uint32_t insn)
        translate_table(ctx, insn, table_fp_fused);
        return;

    case 0x38:
        trans_be(ctx, insn, false);
        return;
    case 0x39:
        trans_be(ctx, insn, true);
        return;
    case 0x3A:
        translate_table(ctx, insn, table_branch);
        return;

    case 0x04: /* spopn */
    case 0x05: /* diag */
    case 0x0F: /* product specific */