diff options
author | Richard Henderson <rth@twiddle.net> | 2012-08-29 12:57:55 -0700 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2013-01-05 12:18:44 -0800 |
commit | 2cf5e350c4f7ec08aab5d70193310c721b8179e9 (patch) | |
tree | f92bfccf082bfb415d0008526bd8b52d70b42526 | |
parent | 4f3adfb2a63416c434fdafdfa406604f2a18392b (diff) |
target-s390: Implement BRANCH ON INDEX
Signed-off-by: Richard Henderson <rth@twiddle.net>
-rw-r--r-- | target-s390x/insn-data.def | 10 | ||||
-rw-r--r-- | target-s390x/translate.c | 52 |
2 files changed, 62 insertions, 0 deletions
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index cd773d0168..8b89ce6217 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -90,6 +90,16 @@ /* BRANCH RELATIVE ON COUNT */ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* BRANCH ON INDEX */ + D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) + D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) + D(0xeb44, BXHG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 0) + D(0xeb45, BXLEG, RSY_a, Z, 0, a2, 0, 0, bx64, 0, 1) +/* BRANCH RELATIVE ON INDEX */ + D(0x8400, BRXH, RSI, Z, 0, 0, 0, 0, bx32, 0, 0) + D(0x8500, BRXLE, RSI, Z, 0, 0, 0, 0, bx32, 0, 1) + D(0xec44, BRXHG, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 0) + D(0xec45, BRXHLE, RIE_e, Z, 0, 0, 0, 0, bx64, 0, 1) /* CHECKSUM */ C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 3d92a56a50..6553e486c3 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1355,6 +1355,58 @@ static ExitStatus op_bct64(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bx32(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + TCGv_i64 t; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_add_i64(t, regs[r1], regs[r3]); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_temp_new_i32(); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_gen_trunc_i64_i32(c.u.s32.b, regs[r3 | 1]); + store_reg32_i64(r1, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, is_imm, imm, o->in2); +} + +static ExitStatus op_bx64(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + bool is_imm = have_field(s->fields, i2); + int imm = is_imm ? get_field(s->fields, i2) : 0; + DisasCompare c; + + c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT); + c.is_64 = true; + + if (r1 == (r3 | 1)) { + c.u.s64.b = load_reg(r3 | 1); + c.g2 = false; + } else { + c.u.s64.b = regs[r3 | 1]; + c.g2 = true; + } + + tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]); + c.u.s64.a = regs[r1]; + c.g1 = true; + + return help_branch(s, &c, is_imm, imm, o->in2); +} + static ExitStatus op_ceb(DisasContext *s, DisasOps *o) { gen_helper_ceb(cc_op, cpu_env, o->in1, o->in2); |