Skip to content

Commit

Permalink
target/hppa: Convert direct and indirect branches
Browse files Browse the repository at this point in the history
Tested-by: Helge Deller <deller@gmx.de>
Tested-by: Sven Schnelle <svens@stackframe.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
  • Loading branch information
rth7680 committed Feb 12, 2019
1 parent 3087859 commit 8340f53
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 102 deletions.
34 changes: 33 additions & 1 deletion target/hppa/insns.decode
Expand Up @@ -24,7 +24,9 @@
%assemble_sr3 13:1 14:2
%assemble_sr3x 13:1 14:2 !function=expand_sr3x

%assemble_12 0:s1 2:1 3:10 !function=expand_shl2
%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

Expand Down Expand Up @@ -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
131 changes: 30 additions & 101 deletions target/hppa/translate.c
Expand Up @@ -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);
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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();
Expand All @@ -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
Expand Down Expand Up @@ -3659,92 +3629,61 @@ 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) {
tcg_gen_mov_i64(cpu_iasq_f, cpu_iasq_b);
}
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)
{
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit 8340f53

Please sign in to comment.