diff options
author | Aurelien Jarno <aurelien@aurel32.net> | 2017-06-01 00:01:17 +0200 |
---|---|---|
committer | Richard Henderson <rth@twiddle.net> | 2017-06-06 15:20:43 -0700 |
commit | 5c2b48a8f0d02acfcb577abdbd5f3040d61455d9 (patch) | |
tree | e97876a724b055110ed0c8e533974fa89ea7efd4 /target/s390x/mem_helper.c | |
parent | 84aa07f109f0afaeeec63c159f3a578b955c3de9 (diff) |
target/s390x: implement COMPARE LOGICAL LONG
As CLCL and CLCLE mostly differ by their operands, use a common do_clcl
helper. Another difference is that CLCL is not interruptible.
Reviewed-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Message-Id: <20170531220129.27724-19-aurelien@aurel32.net>
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target/s390x/mem_helper.c')
-rw-r--r-- | target/s390x/mem_helper.c | 82 |
1 files changed, 59 insertions, 23 deletions
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index e30020c8e9..4ed0b65751 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -661,17 +661,14 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, return cc; } -/* compare logical long extended memcompare insn with padding */ -uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, - uint32_t r3) +/* compare logical long helper */ +static inline uint32_t do_clcl(CPUS390XState *env, + uint64_t *src1, uint64_t *src1len, + uint64_t *src3, uint64_t *src3len, + uint8_t pad, uint64_t limit, + uintptr_t ra) { - uintptr_t ra = GETPC(); - uint64_t src1len = get_length(env, r1 + 1); - uint64_t src1 = get_address(env, r1); - uint64_t src3len = get_length(env, r3 + 1); - uint64_t src3 = get_address(env, r3); - uint8_t pad = a2 & 0xff; - uint64_t len = MAX(src1len, src3len); + uint64_t len = MAX(*src1len, *src3len); uint32_t cc = 0; if (!len) { @@ -679,9 +676,9 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } /* Lest we fail to service interrupts in a timely manner, limit the - amount of work we're willing to do. For now, let's cap at 8k. */ - if (len > 0x2000) { - len = 0x2000; + amount of work we're willing to do. */ + if (len > limit) { + len = limit; cc = 3; } @@ -689,11 +686,11 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint8_t v1 = pad; uint8_t v3 = pad; - if (src1len) { - v1 = cpu_ldub_data_ra(env, src1, ra); + if (*src1len) { + v1 = cpu_ldub_data_ra(env, *src1, ra); } - if (src3len) { - v3 = cpu_ldub_data_ra(env, src3, ra); + if (*src3len) { + v3 = cpu_ldub_data_ra(env, *src3, ra); } if (v1 != v3) { @@ -701,16 +698,55 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, break; } - if (src1len) { - src1++; - src1len--; + if (*src1len) { + *src1 += 1; + *src1len -= 1; } - if (src3len) { - src3++; - src3len--; + if (*src3len) { + *src3 += 1; + *src3len -= 1; } } + return cc; +} + + +/* compare logical long */ +uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) +{ + uintptr_t ra = GETPC(); + uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24); + uint64_t src1 = get_address(env, r1); + uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24); + uint64_t src3 = get_address(env, r2); + uint8_t pad = env->regs[r2 + 1] >> 24; + uint32_t cc; + + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, ra); + + env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len); + env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len); + set_address(env, r1, src1); + set_address(env, r2, src3); + + return cc; +} + +/* compare logical long extended memcompare insn with padding */ +uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) +{ + uintptr_t ra = GETPC(); + uint64_t src1len = get_length(env, r1 + 1); + uint64_t src1 = get_address(env, r1); + uint64_t src3len = get_length(env, r3 + 1); + uint64_t src3 = get_address(env, r3); + uint8_t pad = a2; + uint32_t cc; + + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, ra); + set_length(env, r1 + 1, src1len); set_length(env, r3 + 1, src3len); set_address(env, r1, src1); |