Patchwork [090/147] target-s390: Convert CKSM

login
register
mail settings
Submitter Richard Henderson
Date Sept. 28, 2012, 12:24 a.m.
Message ID <1348791856-26564-1-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/187612/
State New
Headers show

Comments

Richard Henderson - Sept. 28, 2012, 12:24 a.m.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-s390x/helper.h      |  2 +-
 target-s390x/insn-data.def |  3 +++
 target-s390x/mem_helper.c  | 43 +++++++++++++++++++++++++------------------
 target-s390x/translate.c   | 31 ++++++++++++++++++++++---------
 4 files changed, 51 insertions(+), 28 deletions(-)

Patch

diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 5ae723e..9bcf79f 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_PURE|TCG_CALL_CONST, 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_2(sfpc, TCG_CALL_CONST, void, env, i64)
 
 DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST,
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index 13b1771..74f1032 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 db48d63..1b06297 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -753,42 +753,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 4990e57..06b0322 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;