|
@@ -666,35 +666,55 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2,
|
|
|
uint32_t r3)
|
|
|
{
|
|
|
uintptr_t ra = GETPC();
|
|
|
- uint64_t destlen = get_length(env, r1 + 1);
|
|
|
- uint64_t dest = get_address(env, r1);
|
|
|
- uint64_t srclen = get_length(env, r3 + 1);
|
|
|
- uint64_t src = get_address(env, r3);
|
|
|
+ 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);
|
|
|
uint32_t cc = 0;
|
|
|
|
|
|
- if (!(destlen || srclen)) {
|
|
|
+ if (!len) {
|
|
|
return cc;
|
|
|
}
|
|
|
|
|
|
- if (srclen > destlen) {
|
|
|
- srclen = destlen;
|
|
|
+ /* 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;
|
|
|
+ cc = 3;
|
|
|
}
|
|
|
|
|
|
- for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
|
|
|
- uint8_t v1 = srclen ? cpu_ldub_data_ra(env, src, ra) : pad;
|
|
|
- uint8_t v2 = destlen ? cpu_ldub_data_ra(env, dest, ra) : pad;
|
|
|
- if (v1 != v2) {
|
|
|
- cc = (v1 < v2) ? 1 : 2;
|
|
|
+ for (; len; len--) {
|
|
|
+ uint8_t v1 = pad;
|
|
|
+ uint8_t v3 = pad;
|
|
|
+
|
|
|
+ if (src1len) {
|
|
|
+ v1 = cpu_ldub_data_ra(env, src1, ra);
|
|
|
+ }
|
|
|
+ if (src3len) {
|
|
|
+ v3 = cpu_ldub_data_ra(env, src3, ra);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (v1 != v3) {
|
|
|
+ cc = (v1 < v3) ? 1 : 2;
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ if (src1len) {
|
|
|
+ src1++;
|
|
|
+ src1len--;
|
|
|
+ }
|
|
|
+ if (src3len) {
|
|
|
+ src3++;
|
|
|
+ src3len--;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- set_length(env, r1 + 1, destlen);
|
|
|
- /* can't use srclen here, we trunc'ed it */
|
|
|
- set_length(env, r3 + 1, env->regs[r3 + 1] - src - env->regs[r3]);
|
|
|
- set_address(env, r1, dest);
|
|
|
- set_address(env, r3, src);
|
|
|
+ set_length(env, r1 + 1, src1len);
|
|
|
+ set_length(env, r3 + 1, src3len);
|
|
|
+ set_address(env, r1, src1);
|
|
|
+ set_address(env, r3, src3);
|
|
|
|
|
|
return cc;
|
|
|
}
|