diff options
-rw-r--r-- | target-s390x/insn-data.def | 2 | ||||
-rw-r--r-- | target-s390x/translate.c | 50 |
2 files changed, 48 insertions, 4 deletions
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e915984828..480f1fdf51 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -271,7 +271,7 @@ C(0xb982, XGR, RRE, Z, r1, r2, r1, 0, xor, nz64) C(0xb9e7, XGRK, RRF_a, DO, r2, r3, r1, 0, xor, nz64) C(0xe382, XG, RXY_a, Z, r1, m2_64, r1, 0, xor, nz64) - C(0xd700, XC, SS_a, Z, la1, a2, 0, 0, xc, 0) + C(0xd700, XC, SS_a, Z, 0, 0, 0, 0, xc, 0) /* EXCLUSIVE OR IMMEDIATE */ D(0xc006, XIHF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2020) D(0xc007, XILF, RIL_a, EI, r1_o, i2_32u, r1, 0, xori, 0, 0x2000) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 34b9cdf127..7f8a5503d9 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3403,10 +3403,54 @@ static ExitStatus op_unpk(DisasContext *s, DisasOps *o) static ExitStatus op_xc(DisasContext *s, DisasOps *o) { - TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + int d1 = get_field(s->fields, d1); + int d2 = get_field(s->fields, d2); + int b1 = get_field(s->fields, b1); + int b2 = get_field(s->fields, b2); + int l = get_field(s->fields, l1); + TCGv_i32 t32; + + o->addr1 = get_address(s, 0, b1, d1); + + /* If the addresses are identical, this is a store/memset of zero. */ + if (b1 == b2 && d1 == d2 && (l + 1) <= 32) { + o->in2 = tcg_const_i64(0); + + l++; + while (l >= 8) { + tcg_gen_qemu_st64(o->in2, o->addr1, get_mem_index(s)); + l -= 8; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 8); + } + } + if (l >= 4) { + tcg_gen_qemu_st32(o->in2, o->addr1, get_mem_index(s)); + l -= 4; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 4); + } + } + if (l >= 2) { + tcg_gen_qemu_st16(o->in2, o->addr1, get_mem_index(s)); + l -= 2; + if (l > 0) { + tcg_gen_addi_i64(o->addr1, o->addr1, 2); + } + } + if (l) { + tcg_gen_qemu_st8(o->in2, o->addr1, get_mem_index(s)); + } + gen_op_movi_cc(s, 0); + return NO_EXIT; + } + + /* But in general we'll defer to a helper. */ + o->in2 = get_address(s, 0, b2, d2); + t32 = tcg_const_i32(l); potential_page_fault(s); - gen_helper_xc(cc_op, cpu_env, l, o->addr1, o->in2); - tcg_temp_free_i32(l); + gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); + tcg_temp_free_i32(t32); set_cc_static(s); return NO_EXIT; } |