summaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/s390x/insn-data.def3
-rw-r--r--target/s390x/mem_helper.c24
-rw-r--r--target/s390x/translate.c79
3 files changed, 81 insertions, 25 deletions
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index 5c6f33ed9c..9c7b434fca 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -102,6 +102,9 @@
D(0x9400, NI, SI, Z, la1, i2_8u, new, 0, ni, nz64, MO_UB)
D(0xeb54, NIY, SIY, LD, la1, i2_8u, new, 0, ni, nz64, MO_UB)
+/* BRANCH AND LINK */
+ C(0x0500, BALR, RR_a, Z, 0, r2_nz, r1, 0, bal, 0)
+ C(0x4500, BAL, RX_a, Z, 0, a2, r1, 0, bal, 0)
/* BRANCH AND SAVE */
C(0x0d00, BASR, RR_a, Z, 0, r2_nz, r1, 0, bas, 0)
C(0x4d00, BAS, RX_a, Z, 0, a2, r1, 0, bas, 0)
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
index e21a47fb4d..bacae4f503 100644
--- a/target/s390x/mem_helper.c
+++ b/target/s390x/mem_helper.c
@@ -1019,15 +1019,15 @@ void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src)
len_src--;
/* now pack every value */
- while (len_dest >= 0) {
+ while (len_dest > 0) {
b = 0;
- if (len_src > 0) {
+ if (len_src >= 0) {
b = cpu_ldub_data_ra(env, src, ra) & 0x0f;
src--;
len_src--;
}
- if (len_src > 0) {
+ if (len_src >= 0) {
b |= cpu_ldub_data_ra(env, src, ra) << 4;
src--;
len_src--;
@@ -1299,12 +1299,26 @@ static inline uint32_t do_helper_trt(CPUS390XState *env, int len,
return 0;
}
+static uint32_t do_helper_trt_fwd(CPUS390XState *env, uint32_t len,
+ uint64_t array, uint64_t trans,
+ uintptr_t ra)
+{
+ return do_helper_trt(env, len, array, trans, 1, ra);
+}
+
uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
uint64_t trans)
{
return do_helper_trt(env, len, array, trans, 1, GETPC());
}
+static uint32_t do_helper_trt_bkwd(CPUS390XState *env, uint32_t len,
+ uint64_t array, uint64_t trans,
+ uintptr_t ra)
+{
+ return do_helper_trt(env, len, array, trans, -1, ra);
+}
+
uint32_t HELPER(trtr)(CPUS390XState *env, uint32_t len, uint64_t array,
uint64_t trans)
{
@@ -1442,7 +1456,7 @@ static uint32_t do_csst(CPUS390XState *env, uint32_t r3, uint64_t a1,
}
/* Sanity check the alignments. */
- if (extract32(a1, 0, 4 << fc) || extract32(a2, 0, 1 << sc)) {
+ if (extract32(a1, 0, fc + 2) || extract32(a2, 0, sc)) {
goto spec_exception;
}
@@ -2193,12 +2207,14 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr)
typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t,
uint64_t, uintptr_t);
static const dx_helper dx[16] = {
+ [0x0] = do_helper_trt_bkwd,
[0x2] = do_helper_mvc,
[0x4] = do_helper_nc,
[0x5] = do_helper_clc,
[0x6] = do_helper_oc,
[0x7] = do_helper_xc,
[0xc] = do_helper_tr,
+ [0xd] = do_helper_trt_fwd,
};
dx_helper helper = dx[opc & 0xf];
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 57c03cbf58..7363aabf3a 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -84,14 +84,21 @@ static uint64_t inline_branch_hit[CC_OP_MAX];
static uint64_t inline_branch_miss[CC_OP_MAX];
#endif
-static uint64_t pc_to_link_info(DisasContext *s, uint64_t pc)
+static void pc_to_link_info(TCGv_i64 out, DisasContext *s, uint64_t pc)
{
- if (!(s->base.tb->flags & FLAG_MASK_64)) {
- if (s->base.tb->flags & FLAG_MASK_32) {
- return pc | 0x80000000;
+ TCGv_i64 tmp;
+
+ if (s->base.tb->flags & FLAG_MASK_32) {
+ if (s->base.tb->flags & FLAG_MASK_64) {
+ tcg_gen_movi_i64(out, pc);
+ return;
}
+ pc |= 0x80000000;
}
- return pc;
+ assert(!(s->base.tb->flags & FLAG_MASK_64));
+ tmp = tcg_const_i64(pc);
+ tcg_gen_deposit_i64(out, out, tmp, 0, 32);
+ tcg_temp_free_i64(tmp);
}
static TCGv_i64 psw_addr;
@@ -835,7 +842,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
cond = TCG_COND_NE;
c->u.s32.b = tcg_const_i32(1);
break;
- case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */
+ case 0x8 | 0x2: /* cc == 0 || cc == 2 => (cc & 1) == 0 */
cond = TCG_COND_EQ;
c->g1 = false;
c->u.s32.a = tcg_temp_new_i32();
@@ -854,7 +861,7 @@ static void disas_jcc(DisasContext *s, DisasCompare *c, uint32_t mask)
cond = TCG_COND_NE;
c->u.s32.b = tcg_const_i32(0);
break;
- case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */
+ case 0x4 | 0x1: /* cc == 1 || cc == 3 => (cc & 1) != 0 */
cond = TCG_COND_NE;
c->g1 = false;
c->u.s32.a = tcg_temp_new_i32();
@@ -1453,7 +1460,40 @@ static DisasJumpType op_ni(DisasContext *s, DisasOps *o)
static DisasJumpType op_bas(DisasContext *s, DisasOps *o)
{
- tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->pc_tmp));
+ pc_to_link_info(o->out, s, s->pc_tmp);
+ if (o->in2) {
+ tcg_gen_mov_i64(psw_addr, o->in2);
+ per_branch(s, false);
+ return DISAS_PC_UPDATED;
+ } else {
+ return DISAS_NEXT;
+ }
+}
+
+static void save_link_info(DisasContext *s, DisasOps *o)
+{
+ TCGv_i64 t;
+
+ if (s->base.tb->flags & (FLAG_MASK_32 | FLAG_MASK_64)) {
+ pc_to_link_info(o->out, s, s->pc_tmp);
+ return;
+ }
+ gen_op_calc_cc(s);
+ tcg_gen_andi_i64(o->out, o->out, 0xffffffff00000000ull);
+ tcg_gen_ori_i64(o->out, o->out, ((s->ilen / 2) << 30) | s->pc_tmp);
+ t = tcg_temp_new_i64();
+ tcg_gen_shri_i64(t, psw_mask, 16);
+ tcg_gen_andi_i64(t, t, 0x0f000000);
+ tcg_gen_or_i64(o->out, o->out, t);
+ tcg_gen_extu_i32_i64(t, cc_op);
+ tcg_gen_shli_i64(t, t, 28);
+ tcg_gen_or_i64(o->out, o->out, t);
+ tcg_temp_free_i64(t);
+}
+
+static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
+{
+ save_link_info(s, o);
if (o->in2) {
tcg_gen_mov_i64(psw_addr, o->in2);
per_branch(s, false);
@@ -1465,7 +1505,7 @@ static DisasJumpType op_bas(DisasContext *s, DisasOps *o)
static DisasJumpType op_basi(DisasContext *s, DisasOps *o)
{
- tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->pc_tmp));
+ pc_to_link_info(o->out, s, s->pc_tmp);
return help_goto_direct(s, s->base.pc_next + 2 * get_field(s->fields, i2));
}
@@ -2018,9 +2058,9 @@ static DisasJumpType op_csst(DisasContext *s, DisasOps *o)
TCGv_i32 t_r3 = tcg_const_i32(r3);
if (tb_cflags(s->base.tb) & CF_PARALLEL) {
- gen_helper_csst_parallel(cc_op, cpu_env, t_r3, o->in1, o->in2);
+ gen_helper_csst_parallel(cc_op, cpu_env, t_r3, o->addr1, o->in2);
} else {
- gen_helper_csst(cc_op, cpu_env, t_r3, o->in1, o->in2);
+ gen_helper_csst(cc_op, cpu_env, t_r3, o->addr1, o->in2);
}
tcg_temp_free_i32(t_r3);
@@ -2404,20 +2444,17 @@ static DisasJumpType op_insi(DisasContext *s, DisasOps *o)
static DisasJumpType op_ipm(DisasContext *s, DisasOps *o)
{
- TCGv_i64 t1;
+ TCGv_i64 t1, t2;
gen_op_calc_cc(s);
- tcg_gen_andi_i64(o->out, o->out, ~0xff000000ull);
-
t1 = tcg_temp_new_i64();
- tcg_gen_shli_i64(t1, psw_mask, 20);
- tcg_gen_shri_i64(t1, t1, 36);
- tcg_gen_or_i64(o->out, o->out, t1);
-
- tcg_gen_extu_i32_i64(t1, cc_op);
- tcg_gen_shli_i64(t1, t1, 28);
- tcg_gen_or_i64(o->out, o->out, t1);
+ tcg_gen_extract_i64(t1, psw_mask, 40, 4);
+ t2 = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(t2, cc_op);
+ tcg_gen_deposit_i64(t1, t1, t2, 4, 60);
+ tcg_gen_deposit_i64(o->out, o->out, t1, 24, 8);
tcg_temp_free_i64(t1);
+ tcg_temp_free_i64(t2);
return DISAS_NEXT;
}