diff options
-rw-r--r-- | target-s390x/helper.h | 2 | ||||
-rw-r--r-- | target-s390x/insn-data.def | 3 | ||||
-rw-r--r-- | target-s390x/mem_helper.c | 43 | ||||
-rw-r--r-- | target-s390x/translate.c | 31 |
4 files changed, 51 insertions, 28 deletions
diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 633667827f..c6afcbc6b6 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -75,7 +75,7 @@ DEF_HELPER_3(sqxb, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_4(unpk, void, env, i32, i64, i64) DEF_HELPER_4(tr, void, env, i32, i64, i64) -DEF_HELPER_3(cksm, void, env, i32, i32) +DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 13b1771bc3..74f10323db 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -91,6 +91,9 @@ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* CHECKSUM */ + C(0xb241, CKSM, RRE, Z, r1_o, ra2, new, r1_32, cksm, 0) + /* COMPARE */ C(0x1900, CR, RR_a, Z, r1_o, r2_o, 0, 0, 0, cmps32) C(0x5900, C, RX_a, Z, r1_o, m2_32s, 0, 0, 0, cmps32) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 9c3ade816c..9c7815ad17 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -747,42 +747,49 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } /* checksum */ -void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) +uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, + uint64_t src, uint64_t src_len) { - uint64_t src = get_address_31fix(env, r2); - uint64_t src_len = env->regs[(r2 + 1) & 15]; - uint64_t cksm = (uint32_t)env->regs[r1]; + uint64_t max_len, len; + uint64_t cksm = (uint32_t)r1; - while (src_len >= 4) { - cksm += cpu_ldl_data(env, src); + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. For now, lets cap at 8k. */ + max_len = (src_len > 0x2000 ? 0x2000 : src_len); - /* move to next word */ - src_len -= 4; - src += 4; + /* Process full words as available. */ + for (len = 0; len + 4 <= max_len; len += 4, src += 4) { + cksm += (uint32_t)cpu_ldl_data(env, src); } - switch (src_len) { - case 0: - break; + switch (max_len - len) { case 1: cksm += cpu_ldub_data(env, src) << 24; + len += 1; break; case 2: cksm += cpu_lduw_data(env, src) << 16; + len += 2; break; case 3: cksm += cpu_lduw_data(env, src) << 16; cksm += cpu_ldub_data(env, src + 2) << 8; + len += 3; break; } - /* indicate we've processed everything */ - env->regs[r2] = src + src_len; - env->regs[(r2 + 1) & 15] = 0; + /* Fold the carry from the checksum. Note that we can see carry-out + during folding more than once (but probably not more than twice). */ + while (cksm > 0xffffffffull) { + cksm = (uint32_t)cksm + (cksm >> 32); + } + + /* Indicate whether or not we've processed everything. */ + env->cc_op = (len == src_len ? 0 : 3); - /* store result */ - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | - ((uint32_t)cksm + (cksm >> 32)); + /* Return both cksm and processed length. */ + env->retxl = cksm; + return len; } void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 702b174a10..ea2b1dc561 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1034,15 +1034,6 @@ static void disas_b2(CPUS390XState *env, DisasContext *s, int op, LOG_DISAS("disas_b2: op 0x%x r1 %d r2 %d\n", op, r1, r2); switch (op) { - case 0x41: /* CKSM R1,R2 [RRE] */ - tmp32_1 = tcg_const_i32(r1); - tmp32_2 = tcg_const_i32(r2); - potential_page_fault(s); - gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); - tcg_temp_free_i32(tmp32_1); - tcg_temp_free_i32(tmp32_2); - gen_op_movi_cc(s, 0); - break; case 0x4e: /* SAR R1,R2 [RRE] */ tmp32_1 = load_reg32(r2); tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, aregs[r1])); @@ -2047,6 +2038,23 @@ static ExitStatus op_cxgb(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_cksm(DisasContext *s, DisasOps *o) +{ + int r2 = get_field(s->fields, r2); + TCGv_i64 len = tcg_temp_new_i64(); + + potential_page_fault(s); + gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); + set_cc_static(s); + return_low128(o->out); + + tcg_gen_add_i64(regs[r2], regs[r2], len); + tcg_gen_sub_i64(regs[r2 + 1], regs[r2 + 1], len); + tcg_temp_free_i64(len); + + return NO_EXIT; +} + static ExitStatus op_clc(DisasContext *s, DisasOps *o) { int l = get_field(s->fields, l1); @@ -3847,6 +3855,11 @@ static void in2_x2_o(DisasContext *s, DisasFields *f, DisasOps *o) o->g_in1 = o->g_in2 = true; } +static void in2_ra2(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = get_address(s, 0, get_field(f, r2), 0); +} + static void in2_a2(DisasContext *s, DisasFields *f, DisasOps *o) { int x2 = have_field(f, x2) ? get_field(f, x2) : 0; |