target-s390: Convert CKSM

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2012-08-24 11:38:12 -07:00
parent 6e2704e74d
commit 374724f91a
4 changed files with 51 additions and 28 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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);
}
/* store result */
env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
((uint32_t)cksm + (cksm >> 32));
/* Indicate whether or not we've processed everything. */
env->cc_op = (len == src_len ? 0 : 3);
/* Return both cksm and processed length. */
env->retxl = cksm;
return len;
}
void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest,

View file

@ -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;