|
|
1.1 root 1: /*
2: * S/390 helper routines
3: *
1.1.1.3 root 4: * Copyright (c) 2009 Ulrich Hecht
1.1 root 5: * Copyright (c) 2009 Alexander Graf
6: *
7: * This library is free software; you can redistribute it and/or
8: * modify it under the terms of the GNU Lesser General Public
9: * License as published by the Free Software Foundation; either
10: * version 2 of the License, or (at your option) any later version.
11: *
12: * This library is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: * Lesser General Public License for more details.
16: *
17: * You should have received a copy of the GNU Lesser General Public
1.1.1.2 root 18: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 19: */
20:
1.1.1.4 root 21: #include "cpu.h"
22: #include "dyngen-exec.h"
1.1.1.3 root 23: #include "host-utils.h"
1.1.1.5 ! root 24: #include "helper.h"
1.1.1.3 root 25: #include <string.h>
26: #include "kvm.h"
27: #include "qemu-timer.h"
28: #ifdef CONFIG_KVM
29: #include <linux/kvm.h>
30: #endif
1.1 root 31:
1.1.1.4 root 32: #if !defined (CONFIG_USER_ONLY)
33: #include "sysemu.h"
34: #endif
35:
1.1 root 36: /*****************************************************************************/
37: /* Softmmu support */
38: #if !defined (CONFIG_USER_ONLY)
1.1.1.4 root 39: #include "softmmu_exec.h"
1.1 root 40:
41: #define MMUSUFFIX _mmu
42:
43: #define SHIFT 0
44: #include "softmmu_template.h"
45:
46: #define SHIFT 1
47: #include "softmmu_template.h"
48:
49: #define SHIFT 2
50: #include "softmmu_template.h"
51:
52: #define SHIFT 3
53: #include "softmmu_template.h"
54:
55: /* try to fill the TLB and return an exception if error. If retaddr is
56: NULL, it means that the function was called in C code (i.e. not
57: from generated code or from helper.c) */
58: /* XXX: fix it to restore all registers */
1.1.1.5 ! root 59: void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
! 60: uintptr_t retaddr)
1.1 root 61: {
62: TranslationBlock *tb;
1.1.1.5 ! root 63: CPUS390XState *saved_env;
1.1 root 64: int ret;
65:
66: saved_env = env;
1.1.1.4 root 67: env = env1;
68: ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
1.1 root 69: if (unlikely(ret != 0)) {
70: if (likely(retaddr)) {
71: /* now we have a real cpu fault */
1.1.1.5 ! root 72: tb = tb_find_pc(retaddr);
1.1 root 73: if (likely(tb)) {
74: /* the PC is inside the translated code. It means that we have
75: a virtual CPU fault */
1.1.1.5 ! root 76: cpu_restore_state(tb, env, retaddr);
1.1 root 77: }
78: }
1.1.1.3 root 79: cpu_loop_exit(env);
1.1 root 80: }
81: env = saved_env;
82: }
83:
84: #endif
1.1.1.3 root 85:
86: /* #define DEBUG_HELPER */
87: #ifdef DEBUG_HELPER
88: #define HELPER_LOG(x...) qemu_log(x)
89: #else
90: #define HELPER_LOG(x...)
91: #endif
92:
93: /* raise an exception */
94: void HELPER(exception)(uint32_t excp)
95: {
96: HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp);
97: env->exception_index = excp;
98: cpu_loop_exit(env);
99: }
100:
101: #ifndef CONFIG_USER_ONLY
1.1.1.5 ! root 102: static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
1.1.1.3 root 103: uint8_t byte)
104: {
105: target_phys_addr_t dest_phys;
106: target_phys_addr_t len = l;
107: void *dest_p;
108: uint64_t asc = env->psw.mask & PSW_MASK_ASC;
109: int flags;
110:
111: if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
112: stb(dest, byte);
113: cpu_abort(env, "should never reach here");
114: }
115: dest_phys |= dest & ~TARGET_PAGE_MASK;
116:
117: dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
118:
119: memset(dest_p, byte, len);
120:
121: cpu_physical_memory_unmap(dest_p, 1, len, len);
122: }
123:
1.1.1.5 ! root 124: static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
1.1.1.3 root 125: uint64_t src)
126: {
127: target_phys_addr_t dest_phys;
128: target_phys_addr_t src_phys;
129: target_phys_addr_t len = l;
130: void *dest_p;
131: void *src_p;
132: uint64_t asc = env->psw.mask & PSW_MASK_ASC;
133: int flags;
134:
135: if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
136: stb(dest, 0);
137: cpu_abort(env, "should never reach here");
138: }
139: dest_phys |= dest & ~TARGET_PAGE_MASK;
140:
141: if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
142: ldub(src);
143: cpu_abort(env, "should never reach here");
144: }
145: src_phys |= src & ~TARGET_PAGE_MASK;
146:
147: dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
148: src_p = cpu_physical_memory_map(src_phys, &len, 0);
149:
150: memmove(dest_p, src_p, len);
151:
152: cpu_physical_memory_unmap(dest_p, 1, len, len);
153: cpu_physical_memory_unmap(src_p, 0, len, len);
154: }
155: #endif
156:
157: /* and on array */
158: uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
159: {
160: int i;
161: unsigned char x;
162: uint32_t cc = 0;
163:
164: HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
165: __FUNCTION__, l, dest, src);
166: for (i = 0; i <= l; i++) {
167: x = ldub(dest + i) & ldub(src + i);
168: if (x) {
169: cc = 1;
170: }
171: stb(dest + i, x);
172: }
173: return cc;
174: }
175:
176: /* xor on array */
177: uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
178: {
179: int i;
180: unsigned char x;
181: uint32_t cc = 0;
182:
183: HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
184: __FUNCTION__, l, dest, src);
185:
186: #ifndef CONFIG_USER_ONLY
187: /* xor with itself is the same as memset(0) */
188: if ((l > 32) && (src == dest) &&
189: (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
190: mvc_fast_memset(env, l + 1, dest, 0);
191: return 0;
192: }
193: #else
194: if (src == dest) {
195: memset(g2h(dest), 0, l + 1);
196: return 0;
197: }
198: #endif
199:
200: for (i = 0; i <= l; i++) {
201: x = ldub(dest + i) ^ ldub(src + i);
202: if (x) {
203: cc = 1;
204: }
205: stb(dest + i, x);
206: }
207: return cc;
208: }
209:
210: /* or on array */
211: uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
212: {
213: int i;
214: unsigned char x;
215: uint32_t cc = 0;
216:
217: HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
218: __FUNCTION__, l, dest, src);
219: for (i = 0; i <= l; i++) {
220: x = ldub(dest + i) | ldub(src + i);
221: if (x) {
222: cc = 1;
223: }
224: stb(dest + i, x);
225: }
226: return cc;
227: }
228:
229: /* memmove */
230: void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
231: {
232: int i = 0;
233: int x = 0;
234: uint32_t l_64 = (l + 1) / 8;
235:
236: HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
237: __FUNCTION__, l, dest, src);
238:
239: #ifndef CONFIG_USER_ONLY
240: if ((l > 32) &&
241: (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
242: (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
243: if (dest == (src + 1)) {
244: mvc_fast_memset(env, l + 1, dest, ldub(src));
245: return;
246: } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
247: mvc_fast_memmove(env, l + 1, dest, src);
248: return;
249: }
250: }
251: #else
252: if (dest == (src + 1)) {
253: memset(g2h(dest), ldub(src), l + 1);
254: return;
255: } else {
256: memmove(g2h(dest), g2h(src), l + 1);
257: return;
258: }
259: #endif
260:
261: /* handle the parts that fit into 8-byte loads/stores */
262: if (dest != (src + 1)) {
263: for (i = 0; i < l_64; i++) {
264: stq(dest + x, ldq(src + x));
265: x += 8;
266: }
267: }
268:
269: /* slow version crossing pages with byte accesses */
270: for (i = x; i <= l; i++) {
271: stb(dest + i, ldub(src + i));
272: }
273: }
274:
275: /* compare unsigned byte arrays */
276: uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
277: {
278: int i;
279: unsigned char x,y;
280: uint32_t cc;
281: HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
282: __FUNCTION__, l, s1, s2);
283: for (i = 0; i <= l; i++) {
284: x = ldub(s1 + i);
285: y = ldub(s2 + i);
286: HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
287: if (x < y) {
288: cc = 1;
289: goto done;
290: } else if (x > y) {
291: cc = 2;
292: goto done;
293: }
294: }
295: cc = 0;
296: done:
297: HELPER_LOG("\n");
298: return cc;
299: }
300:
301: /* compare logical under mask */
302: uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
303: {
304: uint8_t r,d;
305: uint32_t cc;
306: HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1,
307: mask, addr);
308: cc = 0;
309: while (mask) {
310: if (mask & 8) {
311: d = ldub(addr);
312: r = (r1 & 0xff000000UL) >> 24;
313: HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
314: addr);
315: if (r < d) {
316: cc = 1;
317: break;
318: } else if (r > d) {
319: cc = 2;
320: break;
321: }
322: addr++;
323: }
324: mask = (mask << 1) & 0xf;
325: r1 <<= 8;
326: }
327: HELPER_LOG("\n");
328: return cc;
329: }
330:
331: /* store character under mask */
332: void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
333: {
334: uint8_t r;
335: HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask,
336: addr);
337: while (mask) {
338: if (mask & 8) {
339: r = (r1 & 0xff000000UL) >> 24;
340: stb(addr, r);
341: HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
342: addr++;
343: }
344: mask = (mask << 1) & 0xf;
345: r1 <<= 8;
346: }
347: HELPER_LOG("\n");
348: }
349:
350: /* 64/64 -> 128 unsigned multiplication */
351: void HELPER(mlg)(uint32_t r1, uint64_t v2)
352: {
353: #if HOST_LONG_BITS == 64 && defined(__GNUC__)
354: /* assuming 64-bit hosts have __uint128_t */
355: __uint128_t res = (__uint128_t)env->regs[r1 + 1];
356: res *= (__uint128_t)v2;
357: env->regs[r1] = (uint64_t)(res >> 64);
358: env->regs[r1 + 1] = (uint64_t)res;
359: #else
360: mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
361: #endif
362: }
363:
364: /* 128 -> 64/64 unsigned division */
365: void HELPER(dlg)(uint32_t r1, uint64_t v2)
366: {
367: uint64_t divisor = v2;
368:
369: if (!env->regs[r1]) {
370: /* 64 -> 64/64 case */
371: env->regs[r1] = env->regs[r1+1] % divisor;
372: env->regs[r1+1] = env->regs[r1+1] / divisor;
373: return;
374: } else {
375:
376: #if HOST_LONG_BITS == 64 && defined(__GNUC__)
377: /* assuming 64-bit hosts have __uint128_t */
378: __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
379: (env->regs[r1+1]);
380: __uint128_t quotient = dividend / divisor;
381: env->regs[r1+1] = quotient;
382: __uint128_t remainder = dividend % divisor;
383: env->regs[r1] = remainder;
384: #else
385: /* 32-bit hosts would need special wrapper functionality - just abort if
386: we encounter such a case; it's very unlikely anyways. */
387: cpu_abort(env, "128 -> 64/64 division not implemented\n");
388: #endif
389: }
390: }
391:
392: static inline uint64_t get_address(int x2, int b2, int d2)
393: {
394: uint64_t r = d2;
395:
396: if (x2) {
397: r += env->regs[x2];
398: }
399:
400: if (b2) {
401: r += env->regs[b2];
402: }
403:
404: /* 31-Bit mode */
405: if (!(env->psw.mask & PSW_MASK_64)) {
406: r &= 0x7fffffff;
407: }
408:
409: return r;
410: }
411:
412: static inline uint64_t get_address_31fix(int reg)
413: {
414: uint64_t r = env->regs[reg];
415:
416: /* 31-Bit mode */
417: if (!(env->psw.mask & PSW_MASK_64)) {
418: r &= 0x7fffffff;
419: }
420:
421: return r;
422: }
423:
424: /* search string (c is byte to search, r2 is string, r1 end of string) */
425: uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
426: {
427: uint64_t i;
428: uint32_t cc = 2;
429: uint64_t str = get_address_31fix(r2);
430: uint64_t end = get_address_31fix(r1);
431:
432: HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__,
433: c, env->regs[r1], env->regs[r2]);
434:
435: for (i = str; i != end; i++) {
436: if (ldub(i) == c) {
437: env->regs[r1] = i;
438: cc = 1;
439: break;
440: }
441: }
442:
443: return cc;
444: }
445:
446: /* unsigned string compare (c is string terminator) */
447: uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
448: {
449: uint64_t s1 = get_address_31fix(r1);
450: uint64_t s2 = get_address_31fix(r2);
451: uint8_t v1, v2;
452: uint32_t cc;
453: c = c & 0xff;
454: #ifdef CONFIG_USER_ONLY
455: if (!c) {
456: HELPER_LOG("%s: comparing '%s' and '%s'\n",
457: __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2));
458: }
459: #endif
460: for (;;) {
461: v1 = ldub(s1);
462: v2 = ldub(s2);
463: if ((v1 == c || v2 == c) || (v1 != v2)) {
464: break;
465: }
466: s1++;
467: s2++;
468: }
469:
470: if (v1 == v2) {
471: cc = 0;
472: } else {
473: cc = (v1 < v2) ? 1 : 2;
474: /* FIXME: 31-bit mode! */
475: env->regs[r1] = s1;
476: env->regs[r2] = s2;
477: }
478: return cc;
479: }
480:
481: /* move page */
482: void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
483: {
484: /* XXX missing r0 handling */
485: #ifdef CONFIG_USER_ONLY
486: int i;
487:
488: for (i = 0; i < TARGET_PAGE_SIZE; i++) {
489: stb(r1 + i, ldub(r2 + i));
490: }
491: #else
492: mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
493: #endif
494: }
495:
496: /* string copy (c is string terminator) */
497: void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
498: {
499: uint64_t dest = get_address_31fix(r1);
500: uint64_t src = get_address_31fix(r2);
501: uint8_t v;
502: c = c & 0xff;
503: #ifdef CONFIG_USER_ONLY
504: if (!c) {
505: HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src),
506: dest);
507: }
508: #endif
509: for (;;) {
510: v = ldub(src);
511: stb(dest, v);
512: if (v == c) {
513: break;
514: }
515: src++;
516: dest++;
517: }
518: env->regs[r1] = dest; /* FIXME: 31-bit mode! */
519: }
520:
521: /* compare and swap 64-bit */
522: uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
523: {
524: /* FIXME: locking? */
525: uint32_t cc;
526: uint64_t v2 = ldq(a2);
527: if (env->regs[r1] == v2) {
528: cc = 0;
529: stq(a2, env->regs[r3]);
530: } else {
531: cc = 1;
532: env->regs[r1] = v2;
533: }
534: return cc;
535: }
536:
537: /* compare double and swap 64-bit */
538: uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
539: {
540: /* FIXME: locking? */
541: uint32_t cc;
542: uint64_t v2_hi = ldq(a2);
543: uint64_t v2_lo = ldq(a2 + 8);
544: uint64_t v1_hi = env->regs[r1];
545: uint64_t v1_lo = env->regs[r1 + 1];
546:
547: if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
548: cc = 0;
549: stq(a2, env->regs[r3]);
550: stq(a2 + 8, env->regs[r3 + 1]);
551: } else {
552: cc = 1;
553: env->regs[r1] = v2_hi;
554: env->regs[r1 + 1] = v2_lo;
555: }
556:
557: return cc;
558: }
559:
560: /* compare and swap 32-bit */
561: uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
562: {
563: /* FIXME: locking? */
564: uint32_t cc;
565: HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3);
566: uint32_t v2 = ldl(a2);
567: if (((uint32_t)env->regs[r1]) == v2) {
568: cc = 0;
569: stl(a2, (uint32_t)env->regs[r3]);
570: } else {
571: cc = 1;
572: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
573: }
574: return cc;
575: }
576:
577: static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
578: {
579: int pos = 24; /* top of the lower half of r1 */
580: uint64_t rmask = 0xff000000ULL;
581: uint8_t val = 0;
582: int ccd = 0;
583: uint32_t cc = 0;
584:
585: while (mask) {
586: if (mask & 8) {
587: env->regs[r1] &= ~rmask;
588: val = ldub(address);
589: if ((val & 0x80) && !ccd) {
590: cc = 1;
591: }
592: ccd = 1;
593: if (val && cc == 0) {
594: cc = 2;
595: }
596: env->regs[r1] |= (uint64_t)val << pos;
597: address++;
598: }
599: mask = (mask << 1) & 0xf;
600: pos -= 8;
601: rmask >>= 8;
602: }
603:
604: return cc;
605: }
606:
607: /* execute instruction
608: this instruction executes an insn modified with the contents of r1
609: it does not change the executed instruction in memory
610: it does not change the program counter
611: in other words: tricky...
612: currently implemented by interpreting the cases it is most commonly used in
613: */
614: uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
615: {
616: uint16_t insn = lduw_code(addr);
617: HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr,
618: insn);
619: if ((insn & 0xf0ff) == 0xd000) {
620: uint32_t l, insn2, b1, b2, d1, d2;
621: l = v1 & 0xff;
622: insn2 = ldl_code(addr + 2);
623: b1 = (insn2 >> 28) & 0xf;
624: b2 = (insn2 >> 12) & 0xf;
625: d1 = (insn2 >> 16) & 0xfff;
626: d2 = insn2 & 0xfff;
627: switch (insn & 0xf00) {
628: case 0x200:
629: helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
630: break;
631: case 0x500:
632: cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
633: break;
634: case 0x700:
635: cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
636: break;
1.1.1.4 root 637: case 0xc00:
638: helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
639: break;
1.1.1.3 root 640: default:
641: goto abort;
642: break;
643: }
644: } else if ((insn & 0xff00) == 0x0a00) {
645: /* supervisor call */
646: HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff);
647: env->psw.addr = ret - 4;
648: env->int_svc_code = (insn|v1) & 0xff;
649: env->int_svc_ilc = 4;
650: helper_exception(EXCP_SVC);
651: } else if ((insn & 0xff00) == 0xbf00) {
652: uint32_t insn2, r1, r3, b2, d2;
653: insn2 = ldl_code(addr + 2);
654: r1 = (insn2 >> 20) & 0xf;
655: r3 = (insn2 >> 16) & 0xf;
656: b2 = (insn2 >> 12) & 0xf;
657: d2 = insn2 & 0xfff;
658: cc = helper_icm(r1, get_address(0, b2, d2), r3);
659: } else {
660: abort:
661: cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
662: insn);
663: }
664: return cc;
665: }
666:
667: /* absolute value 32-bit */
668: uint32_t HELPER(abs_i32)(int32_t val)
669: {
670: if (val < 0) {
671: return -val;
672: } else {
673: return val;
674: }
675: }
676:
677: /* negative absolute value 32-bit */
678: int32_t HELPER(nabs_i32)(int32_t val)
679: {
680: if (val < 0) {
681: return val;
682: } else {
683: return -val;
684: }
685: }
686:
687: /* absolute value 64-bit */
688: uint64_t HELPER(abs_i64)(int64_t val)
689: {
690: HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val);
691:
692: if (val < 0) {
693: return -val;
694: } else {
695: return val;
696: }
697: }
698:
699: /* negative absolute value 64-bit */
700: int64_t HELPER(nabs_i64)(int64_t val)
701: {
702: if (val < 0) {
703: return val;
704: } else {
705: return -val;
706: }
707: }
708:
709: /* add with carry 32-bit unsigned */
710: uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
711: {
712: uint32_t res;
713:
714: res = v1 + v2;
715: if (cc & 2) {
716: res++;
717: }
718:
719: return res;
720: }
721:
722: /* store character under mask high operates on the upper half of r1 */
723: void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
724: {
725: int pos = 56; /* top of the upper half of r1 */
726:
727: while (mask) {
728: if (mask & 8) {
729: stb(address, (env->regs[r1] >> pos) & 0xff);
730: address++;
731: }
732: mask = (mask << 1) & 0xf;
733: pos -= 8;
734: }
735: }
736:
737: /* insert character under mask high; same as icm, but operates on the
738: upper half of r1 */
739: uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
740: {
741: int pos = 56; /* top of the upper half of r1 */
742: uint64_t rmask = 0xff00000000000000ULL;
743: uint8_t val = 0;
744: int ccd = 0;
745: uint32_t cc = 0;
746:
747: while (mask) {
748: if (mask & 8) {
749: env->regs[r1] &= ~rmask;
750: val = ldub(address);
751: if ((val & 0x80) && !ccd) {
752: cc = 1;
753: }
754: ccd = 1;
755: if (val && cc == 0) {
756: cc = 2;
757: }
758: env->regs[r1] |= (uint64_t)val << pos;
759: address++;
760: }
761: mask = (mask << 1) & 0xf;
762: pos -= 8;
763: rmask >>= 8;
764: }
765:
766: return cc;
767: }
768:
769: /* insert psw mask and condition code into r1 */
770: void HELPER(ipm)(uint32_t cc, uint32_t r1)
771: {
772: uint64_t r = env->regs[r1];
773:
774: r &= 0xffffffff00ffffffULL;
775: r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf );
776: env->regs[r1] = r;
777: HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__,
778: cc, env->psw.mask, r);
779: }
780:
781: /* load access registers r1 to r3 from memory at a2 */
782: void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
783: {
784: int i;
785:
786: for (i = r1;; i = (i + 1) % 16) {
787: env->aregs[i] = ldl(a2);
788: a2 += 4;
789:
790: if (i == r3) {
791: break;
792: }
793: }
794: }
795:
796: /* store access registers r1 to r3 in memory at a2 */
797: void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
798: {
799: int i;
800:
801: for (i = r1;; i = (i + 1) % 16) {
802: stl(a2, env->aregs[i]);
803: a2 += 4;
804:
805: if (i == r3) {
806: break;
807: }
808: }
809: }
810:
811: /* move long */
812: uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
813: {
814: uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
815: uint64_t dest = get_address_31fix(r1);
816: uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
817: uint64_t src = get_address_31fix(r2);
818: uint8_t pad = src >> 24;
819: uint8_t v;
820: uint32_t cc;
821:
822: if (destlen == srclen) {
823: cc = 0;
824: } else if (destlen < srclen) {
825: cc = 1;
826: } else {
827: cc = 2;
828: }
829:
830: if (srclen > destlen) {
831: srclen = destlen;
832: }
833:
834: for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
835: v = ldub(src);
836: stb(dest, v);
837: }
838:
839: for (; destlen; dest++, destlen--) {
840: stb(dest, pad);
841: }
842:
843: env->regs[r1 + 1] = destlen;
844: /* can't use srclen here, we trunc'ed it */
845: env->regs[r2 + 1] -= src - env->regs[r2];
846: env->regs[r1] = dest;
847: env->regs[r2] = src;
848:
849: return cc;
850: }
851:
852: /* move long extended another memcopy insn with more bells and whistles */
853: uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
854: {
855: uint64_t destlen = env->regs[r1 + 1];
856: uint64_t dest = env->regs[r1];
857: uint64_t srclen = env->regs[r3 + 1];
858: uint64_t src = env->regs[r3];
859: uint8_t pad = a2 & 0xff;
860: uint8_t v;
861: uint32_t cc;
862:
863: if (!(env->psw.mask & PSW_MASK_64)) {
864: destlen = (uint32_t)destlen;
865: srclen = (uint32_t)srclen;
866: dest &= 0x7fffffff;
867: src &= 0x7fffffff;
868: }
869:
870: if (destlen == srclen) {
871: cc = 0;
872: } else if (destlen < srclen) {
873: cc = 1;
874: } else {
875: cc = 2;
876: }
877:
878: if (srclen > destlen) {
879: srclen = destlen;
880: }
881:
882: for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
883: v = ldub(src);
884: stb(dest, v);
885: }
886:
887: for (; destlen; dest++, destlen--) {
888: stb(dest, pad);
889: }
890:
891: env->regs[r1 + 1] = destlen;
892: /* can't use srclen here, we trunc'ed it */
893: /* FIXME: 31-bit mode! */
894: env->regs[r3 + 1] -= src - env->regs[r3];
895: env->regs[r1] = dest;
896: env->regs[r3] = src;
897:
898: return cc;
899: }
900:
901: /* compare logical long extended memcompare insn with padding */
902: uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
903: {
904: uint64_t destlen = env->regs[r1 + 1];
905: uint64_t dest = get_address_31fix(r1);
906: uint64_t srclen = env->regs[r3 + 1];
907: uint64_t src = get_address_31fix(r3);
908: uint8_t pad = a2 & 0xff;
909: uint8_t v1 = 0,v2 = 0;
910: uint32_t cc = 0;
911:
912: if (!(destlen || srclen)) {
913: return cc;
914: }
915:
916: if (srclen > destlen) {
917: srclen = destlen;
918: }
919:
920: for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
921: v1 = srclen ? ldub(src) : pad;
922: v2 = destlen ? ldub(dest) : pad;
923: if (v1 != v2) {
924: cc = (v1 < v2) ? 1 : 2;
925: break;
926: }
927: }
928:
929: env->regs[r1 + 1] = destlen;
930: /* can't use srclen here, we trunc'ed it */
931: env->regs[r3 + 1] -= src - env->regs[r3];
932: env->regs[r1] = dest;
933: env->regs[r3] = src;
934:
935: return cc;
936: }
937:
938: /* subtract unsigned v2 from v1 with borrow */
939: uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2)
940: {
941: uint32_t v1 = env->regs[r1];
942: uint32_t res = v1 + (~v2) + (cc >> 1);
943:
944: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
945: if (cc & 2) {
946: /* borrow */
947: return v1 ? 1 : 0;
948: } else {
949: return v1 ? 3 : 2;
950: }
951: }
952:
953: /* subtract unsigned v2 from v1 with borrow */
954: uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2)
955: {
956: uint64_t res = v1 + (~v2) + (cc >> 1);
957:
958: env->regs[r1] = res;
959: if (cc & 2) {
960: /* borrow */
961: return v1 ? 1 : 0;
962: } else {
963: return v1 ? 3 : 2;
964: }
965: }
966:
967: static inline int float_comp_to_cc(int float_compare)
968: {
969: switch (float_compare) {
970: case float_relation_equal:
971: return 0;
972: case float_relation_less:
973: return 1;
974: case float_relation_greater:
975: return 2;
976: case float_relation_unordered:
977: return 3;
978: default:
979: cpu_abort(env, "unknown return value for float compare\n");
980: }
981: }
982:
983: /* condition codes for binary FP ops */
984: static uint32_t set_cc_f32(float32 v1, float32 v2)
985: {
986: return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status));
987: }
988:
989: static uint32_t set_cc_f64(float64 v1, float64 v2)
990: {
991: return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status));
992: }
993:
994: /* condition codes for unary FP ops */
995: static uint32_t set_cc_nz_f32(float32 v)
996: {
997: if (float32_is_any_nan(v)) {
998: return 3;
999: } else if (float32_is_zero(v)) {
1000: return 0;
1001: } else if (float32_is_neg(v)) {
1002: return 1;
1003: } else {
1004: return 2;
1005: }
1006: }
1007:
1008: static uint32_t set_cc_nz_f64(float64 v)
1009: {
1010: if (float64_is_any_nan(v)) {
1011: return 3;
1012: } else if (float64_is_zero(v)) {
1013: return 0;
1014: } else if (float64_is_neg(v)) {
1015: return 1;
1016: } else {
1017: return 2;
1018: }
1019: }
1020:
1021: static uint32_t set_cc_nz_f128(float128 v)
1022: {
1023: if (float128_is_any_nan(v)) {
1024: return 3;
1025: } else if (float128_is_zero(v)) {
1026: return 0;
1027: } else if (float128_is_neg(v)) {
1028: return 1;
1029: } else {
1030: return 2;
1031: }
1032: }
1033:
1034: /* convert 32-bit int to 64-bit float */
1035: void HELPER(cdfbr)(uint32_t f1, int32_t v2)
1036: {
1037: HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1);
1038: env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
1039: }
1040:
1041: /* convert 32-bit int to 128-bit float */
1042: void HELPER(cxfbr)(uint32_t f1, int32_t v2)
1043: {
1044: CPU_QuadU v1;
1045: v1.q = int32_to_float128(v2, &env->fpu_status);
1046: env->fregs[f1].ll = v1.ll.upper;
1047: env->fregs[f1 + 2].ll = v1.ll.lower;
1048: }
1049:
1050: /* convert 64-bit int to 32-bit float */
1051: void HELPER(cegbr)(uint32_t f1, int64_t v2)
1052: {
1053: HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
1054: env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
1055: }
1056:
1057: /* convert 64-bit int to 64-bit float */
1058: void HELPER(cdgbr)(uint32_t f1, int64_t v2)
1059: {
1060: HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
1061: env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
1062: }
1063:
1064: /* convert 64-bit int to 128-bit float */
1065: void HELPER(cxgbr)(uint32_t f1, int64_t v2)
1066: {
1067: CPU_QuadU x1;
1068: x1.q = int64_to_float128(v2, &env->fpu_status);
1069: HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2,
1070: x1.ll.upper, x1.ll.lower);
1071: env->fregs[f1].ll = x1.ll.upper;
1072: env->fregs[f1 + 2].ll = x1.ll.lower;
1073: }
1074:
1075: /* convert 32-bit int to 32-bit float */
1076: void HELPER(cefbr)(uint32_t f1, int32_t v2)
1077: {
1078: env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
1079: HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2,
1080: env->fregs[f1].l.upper, f1);
1081: }
1082:
1083: /* 32-bit FP addition RR */
1084: uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2)
1085: {
1086: env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
1087: env->fregs[f2].l.upper,
1088: &env->fpu_status);
1089: HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
1090: env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
1091:
1092: return set_cc_nz_f32(env->fregs[f1].l.upper);
1093: }
1094:
1095: /* 64-bit FP addition RR */
1096: uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2)
1097: {
1098: env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
1099: &env->fpu_status);
1100: HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__,
1101: env->fregs[f2].d, env->fregs[f1].d, f1);
1102:
1103: return set_cc_nz_f64(env->fregs[f1].d);
1104: }
1105:
1106: /* 32-bit FP subtraction RR */
1107: uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2)
1108: {
1109: env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper,
1110: env->fregs[f2].l.upper,
1111: &env->fpu_status);
1112: HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
1113: env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
1114:
1115: return set_cc_nz_f32(env->fregs[f1].l.upper);
1116: }
1117:
1118: /* 64-bit FP subtraction RR */
1119: uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2)
1120: {
1121: env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d,
1122: &env->fpu_status);
1123: HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n",
1124: __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1);
1125:
1126: return set_cc_nz_f64(env->fregs[f1].d);
1127: }
1128:
1129: /* 32-bit FP division RR */
1130: void HELPER(debr)(uint32_t f1, uint32_t f2)
1131: {
1132: env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper,
1133: env->fregs[f2].l.upper,
1134: &env->fpu_status);
1135: }
1136:
1137: /* 128-bit FP division RR */
1138: void HELPER(dxbr)(uint32_t f1, uint32_t f2)
1139: {
1140: CPU_QuadU v1;
1141: v1.ll.upper = env->fregs[f1].ll;
1142: v1.ll.lower = env->fregs[f1 + 2].ll;
1143: CPU_QuadU v2;
1144: v2.ll.upper = env->fregs[f2].ll;
1145: v2.ll.lower = env->fregs[f2 + 2].ll;
1146: CPU_QuadU res;
1147: res.q = float128_div(v1.q, v2.q, &env->fpu_status);
1148: env->fregs[f1].ll = res.ll.upper;
1149: env->fregs[f1 + 2].ll = res.ll.lower;
1150: }
1151:
1152: /* 64-bit FP multiplication RR */
1153: void HELPER(mdbr)(uint32_t f1, uint32_t f2)
1154: {
1155: env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
1156: &env->fpu_status);
1157: }
1158:
1159: /* 128-bit FP multiplication RR */
1160: void HELPER(mxbr)(uint32_t f1, uint32_t f2)
1161: {
1162: CPU_QuadU v1;
1163: v1.ll.upper = env->fregs[f1].ll;
1164: v1.ll.lower = env->fregs[f1 + 2].ll;
1165: CPU_QuadU v2;
1166: v2.ll.upper = env->fregs[f2].ll;
1167: v2.ll.lower = env->fregs[f2 + 2].ll;
1168: CPU_QuadU res;
1169: res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
1170: env->fregs[f1].ll = res.ll.upper;
1171: env->fregs[f1 + 2].ll = res.ll.lower;
1172: }
1173:
1174: /* convert 32-bit float to 64-bit float */
1175: void HELPER(ldebr)(uint32_t r1, uint32_t r2)
1176: {
1177: env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
1178: &env->fpu_status);
1179: }
1180:
1181: /* convert 128-bit float to 64-bit float */
1182: void HELPER(ldxbr)(uint32_t f1, uint32_t f2)
1183: {
1184: CPU_QuadU x2;
1185: x2.ll.upper = env->fregs[f2].ll;
1186: x2.ll.lower = env->fregs[f2 + 2].ll;
1187: env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
1188: HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d);
1189: }
1190:
1191: /* convert 64-bit float to 128-bit float */
1192: void HELPER(lxdbr)(uint32_t f1, uint32_t f2)
1193: {
1194: CPU_QuadU res;
1195: res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
1196: env->fregs[f1].ll = res.ll.upper;
1197: env->fregs[f1 + 2].ll = res.ll.lower;
1198: }
1199:
1200: /* convert 64-bit float to 32-bit float */
1201: void HELPER(ledbr)(uint32_t f1, uint32_t f2)
1202: {
1203: float64 d2 = env->fregs[f2].d;
1204: env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
1205: }
1206:
1207: /* convert 128-bit float to 32-bit float */
1208: void HELPER(lexbr)(uint32_t f1, uint32_t f2)
1209: {
1210: CPU_QuadU x2;
1211: x2.ll.upper = env->fregs[f2].ll;
1212: x2.ll.lower = env->fregs[f2 + 2].ll;
1213: env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
1214: HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper);
1215: }
1216:
1217: /* absolute value of 32-bit float */
1218: uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2)
1219: {
1220: float32 v1;
1221: float32 v2 = env->fregs[f2].d;
1222: v1 = float32_abs(v2);
1223: env->fregs[f1].d = v1;
1224: return set_cc_nz_f32(v1);
1225: }
1226:
1227: /* absolute value of 64-bit float */
1228: uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2)
1229: {
1230: float64 v1;
1231: float64 v2 = env->fregs[f2].d;
1232: v1 = float64_abs(v2);
1233: env->fregs[f1].d = v1;
1234: return set_cc_nz_f64(v1);
1235: }
1236:
1237: /* absolute value of 128-bit float */
1238: uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2)
1239: {
1240: CPU_QuadU v1;
1241: CPU_QuadU v2;
1242: v2.ll.upper = env->fregs[f2].ll;
1243: v2.ll.lower = env->fregs[f2 + 2].ll;
1244: v1.q = float128_abs(v2.q);
1245: env->fregs[f1].ll = v1.ll.upper;
1246: env->fregs[f1 + 2].ll = v1.ll.lower;
1247: return set_cc_nz_f128(v1.q);
1248: }
1249:
1250: /* load and test 64-bit float */
1251: uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2)
1252: {
1253: env->fregs[f1].d = env->fregs[f2].d;
1254: return set_cc_nz_f64(env->fregs[f1].d);
1255: }
1256:
1257: /* load and test 32-bit float */
1258: uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2)
1259: {
1260: env->fregs[f1].l.upper = env->fregs[f2].l.upper;
1261: return set_cc_nz_f32(env->fregs[f1].l.upper);
1262: }
1263:
1264: /* load and test 128-bit float */
1265: uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2)
1266: {
1267: CPU_QuadU x;
1268: x.ll.upper = env->fregs[f2].ll;
1269: x.ll.lower = env->fregs[f2 + 2].ll;
1270: env->fregs[f1].ll = x.ll.upper;
1271: env->fregs[f1 + 2].ll = x.ll.lower;
1272: return set_cc_nz_f128(x.q);
1273: }
1274:
1275: /* load complement of 32-bit float */
1276: uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2)
1277: {
1278: env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
1279:
1280: return set_cc_nz_f32(env->fregs[f1].l.upper);
1281: }
1282:
1283: /* load complement of 64-bit float */
1284: uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2)
1285: {
1286: env->fregs[f1].d = float64_chs(env->fregs[f2].d);
1287:
1288: return set_cc_nz_f64(env->fregs[f1].d);
1289: }
1290:
1291: /* load complement of 128-bit float */
1292: uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2)
1293: {
1294: CPU_QuadU x1, x2;
1295: x2.ll.upper = env->fregs[f2].ll;
1296: x2.ll.lower = env->fregs[f2 + 2].ll;
1297: x1.q = float128_chs(x2.q);
1298: env->fregs[f1].ll = x1.ll.upper;
1299: env->fregs[f1 + 2].ll = x1.ll.lower;
1300: return set_cc_nz_f128(x1.q);
1301: }
1302:
1303: /* 32-bit FP addition RM */
1304: void HELPER(aeb)(uint32_t f1, uint32_t val)
1305: {
1306: float32 v1 = env->fregs[f1].l.upper;
1307: CPU_FloatU v2;
1308: v2.l = val;
1309: HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__,
1310: v1, f1, v2.f);
1311: env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
1312: }
1313:
1314: /* 32-bit FP division RM */
1315: void HELPER(deb)(uint32_t f1, uint32_t val)
1316: {
1317: float32 v1 = env->fregs[f1].l.upper;
1318: CPU_FloatU v2;
1319: v2.l = val;
1320: HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__,
1321: v1, f1, v2.f);
1322: env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status);
1323: }
1324:
1325: /* 32-bit FP multiplication RM */
1326: void HELPER(meeb)(uint32_t f1, uint32_t val)
1327: {
1328: float32 v1 = env->fregs[f1].l.upper;
1329: CPU_FloatU v2;
1330: v2.l = val;
1331: HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__,
1332: v1, f1, v2.f);
1333: env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
1334: }
1335:
1336: /* 32-bit FP compare RR */
1337: uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2)
1338: {
1339: float32 v1 = env->fregs[f1].l.upper;
1.1.1.5 ! root 1340: float32 v2 = env->fregs[f2].l.upper;
1.1.1.3 root 1341: HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__,
1342: v1, f1, v2);
1343: return set_cc_f32(v1, v2);
1344: }
1345:
1346: /* 64-bit FP compare RR */
1347: uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2)
1348: {
1349: float64 v1 = env->fregs[f1].d;
1.1.1.5 ! root 1350: float64 v2 = env->fregs[f2].d;
1.1.1.3 root 1351: HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__,
1352: v1, f1, v2);
1353: return set_cc_f64(v1, v2);
1354: }
1355:
1356: /* 128-bit FP compare RR */
1357: uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2)
1358: {
1359: CPU_QuadU v1;
1360: v1.ll.upper = env->fregs[f1].ll;
1361: v1.ll.lower = env->fregs[f1 + 2].ll;
1362: CPU_QuadU v2;
1363: v2.ll.upper = env->fregs[f2].ll;
1364: v2.ll.lower = env->fregs[f2 + 2].ll;
1365:
1366: return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q,
1367: &env->fpu_status));
1368: }
1369:
1370: /* 64-bit FP compare RM */
1371: uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2)
1372: {
1373: float64 v1 = env->fregs[f1].d;
1374: CPU_DoubleU v2;
1375: v2.ll = ldq(a2);
1376: HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1,
1377: f1, v2.d);
1378: return set_cc_f64(v1, v2.d);
1379: }
1380:
1381: /* 64-bit FP addition RM */
1382: uint32_t HELPER(adb)(uint32_t f1, uint64_t a2)
1383: {
1384: float64 v1 = env->fregs[f1].d;
1385: CPU_DoubleU v2;
1386: v2.ll = ldq(a2);
1387: HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__,
1388: v1, f1, v2.d);
1389: env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
1390: return set_cc_nz_f64(v1);
1391: }
1392:
1393: /* 32-bit FP subtraction RM */
1394: void HELPER(seb)(uint32_t f1, uint32_t val)
1395: {
1396: float32 v1 = env->fregs[f1].l.upper;
1397: CPU_FloatU v2;
1398: v2.l = val;
1399: env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status);
1400: }
1401:
1402: /* 64-bit FP subtraction RM */
1403: uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2)
1404: {
1405: float64 v1 = env->fregs[f1].d;
1406: CPU_DoubleU v2;
1407: v2.ll = ldq(a2);
1408: env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status);
1409: return set_cc_nz_f64(v1);
1410: }
1411:
1412: /* 64-bit FP multiplication RM */
1413: void HELPER(mdb)(uint32_t f1, uint64_t a2)
1414: {
1415: float64 v1 = env->fregs[f1].d;
1416: CPU_DoubleU v2;
1417: v2.ll = ldq(a2);
1418: HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__,
1419: v1, f1, v2.d);
1420: env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
1421: }
1422:
1423: /* 64-bit FP division RM */
1424: void HELPER(ddb)(uint32_t f1, uint64_t a2)
1425: {
1426: float64 v1 = env->fregs[f1].d;
1427: CPU_DoubleU v2;
1428: v2.ll = ldq(a2);
1429: HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__,
1430: v1, f1, v2.d);
1431: env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status);
1432: }
1433:
1434: static void set_round_mode(int m3)
1435: {
1436: switch (m3) {
1437: case 0:
1438: /* current mode */
1439: break;
1440: case 1:
1441: /* biased round no nearest */
1442: case 4:
1443: /* round to nearest */
1444: set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
1445: break;
1446: case 5:
1447: /* round to zero */
1448: set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
1449: break;
1450: case 6:
1451: /* round to +inf */
1452: set_float_rounding_mode(float_round_up, &env->fpu_status);
1453: break;
1454: case 7:
1455: /* round to -inf */
1456: set_float_rounding_mode(float_round_down, &env->fpu_status);
1457: break;
1458: }
1459: }
1460:
1461: /* convert 32-bit float to 64-bit int */
1462: uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3)
1463: {
1464: float32 v2 = env->fregs[f2].l.upper;
1465: set_round_mode(m3);
1466: env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
1467: return set_cc_nz_f32(v2);
1468: }
1469:
1470: /* convert 64-bit float to 64-bit int */
1471: uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1472: {
1473: float64 v2 = env->fregs[f2].d;
1474: set_round_mode(m3);
1475: env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
1476: return set_cc_nz_f64(v2);
1477: }
1478:
1479: /* convert 128-bit float to 64-bit int */
1480: uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1481: {
1482: CPU_QuadU v2;
1483: v2.ll.upper = env->fregs[f2].ll;
1484: v2.ll.lower = env->fregs[f2 + 2].ll;
1485: set_round_mode(m3);
1486: env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
1487: if (float128_is_any_nan(v2.q)) {
1488: return 3;
1489: } else if (float128_is_zero(v2.q)) {
1490: return 0;
1491: } else if (float128_is_neg(v2.q)) {
1492: return 1;
1493: } else {
1494: return 2;
1495: }
1496: }
1497:
1498: /* convert 32-bit float to 32-bit int */
1499: uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3)
1500: {
1501: float32 v2 = env->fregs[f2].l.upper;
1502: set_round_mode(m3);
1503: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1504: float32_to_int32(v2, &env->fpu_status);
1505: return set_cc_nz_f32(v2);
1506: }
1507:
1508: /* convert 64-bit float to 32-bit int */
1509: uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1510: {
1511: float64 v2 = env->fregs[f2].d;
1512: set_round_mode(m3);
1513: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1514: float64_to_int32(v2, &env->fpu_status);
1515: return set_cc_nz_f64(v2);
1516: }
1517:
1518: /* convert 128-bit float to 32-bit int */
1519: uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1520: {
1521: CPU_QuadU v2;
1522: v2.ll.upper = env->fregs[f2].ll;
1523: v2.ll.lower = env->fregs[f2 + 2].ll;
1524: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1525: float128_to_int32(v2.q, &env->fpu_status);
1526: return set_cc_nz_f128(v2.q);
1527: }
1528:
1529: /* load 32-bit FP zero */
1530: void HELPER(lzer)(uint32_t f1)
1531: {
1532: env->fregs[f1].l.upper = float32_zero;
1533: }
1534:
1535: /* load 64-bit FP zero */
1536: void HELPER(lzdr)(uint32_t f1)
1537: {
1538: env->fregs[f1].d = float64_zero;
1539: }
1540:
1541: /* load 128-bit FP zero */
1542: void HELPER(lzxr)(uint32_t f1)
1543: {
1544: CPU_QuadU x;
1545: x.q = float64_to_float128(float64_zero, &env->fpu_status);
1546: env->fregs[f1].ll = x.ll.upper;
1547: env->fregs[f1 + 1].ll = x.ll.lower;
1548: }
1549:
1550: /* 128-bit FP subtraction RR */
1551: uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2)
1552: {
1553: CPU_QuadU v1;
1554: v1.ll.upper = env->fregs[f1].ll;
1555: v1.ll.lower = env->fregs[f1 + 2].ll;
1556: CPU_QuadU v2;
1557: v2.ll.upper = env->fregs[f2].ll;
1558: v2.ll.lower = env->fregs[f2 + 2].ll;
1559: CPU_QuadU res;
1560: res.q = float128_sub(v1.q, v2.q, &env->fpu_status);
1561: env->fregs[f1].ll = res.ll.upper;
1562: env->fregs[f1 + 2].ll = res.ll.lower;
1563: return set_cc_nz_f128(res.q);
1564: }
1565:
1566: /* 128-bit FP addition RR */
1567: uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2)
1568: {
1569: CPU_QuadU v1;
1570: v1.ll.upper = env->fregs[f1].ll;
1571: v1.ll.lower = env->fregs[f1 + 2].ll;
1572: CPU_QuadU v2;
1573: v2.ll.upper = env->fregs[f2].ll;
1574: v2.ll.lower = env->fregs[f2 + 2].ll;
1575: CPU_QuadU res;
1576: res.q = float128_add(v1.q, v2.q, &env->fpu_status);
1577: env->fregs[f1].ll = res.ll.upper;
1578: env->fregs[f1 + 2].ll = res.ll.lower;
1579: return set_cc_nz_f128(res.q);
1580: }
1581:
1582: /* 32-bit FP multiplication RR */
1583: void HELPER(meebr)(uint32_t f1, uint32_t f2)
1584: {
1585: env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
1586: env->fregs[f2].l.upper,
1587: &env->fpu_status);
1588: }
1589:
1590: /* 64-bit FP division RR */
1591: void HELPER(ddbr)(uint32_t f1, uint32_t f2)
1592: {
1593: env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d,
1594: &env->fpu_status);
1595: }
1596:
1597: /* 64-bit FP multiply and add RM */
1598: void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3)
1599: {
1600: HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3);
1601: CPU_DoubleU v2;
1602: v2.ll = ldq(a2);
1603: env->fregs[f1].d = float64_add(env->fregs[f1].d,
1604: float64_mul(v2.d, env->fregs[f3].d,
1605: &env->fpu_status),
1606: &env->fpu_status);
1607: }
1608:
1609: /* 64-bit FP multiply and add RR */
1610: void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2)
1611: {
1612: HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
1613: env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
1614: env->fregs[f3].d,
1615: &env->fpu_status),
1616: env->fregs[f1].d, &env->fpu_status);
1617: }
1618:
1619: /* 64-bit FP multiply and subtract RR */
1620: void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2)
1621: {
1622: HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
1623: env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
1624: env->fregs[f3].d,
1625: &env->fpu_status),
1626: env->fregs[f1].d, &env->fpu_status);
1627: }
1628:
1629: /* 32-bit FP multiply and add RR */
1630: void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2)
1631: {
1632: env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
1633: float32_mul(env->fregs[f2].l.upper,
1634: env->fregs[f3].l.upper,
1635: &env->fpu_status),
1636: &env->fpu_status);
1637: }
1638:
1.1.1.4 root 1639: /* convert 32-bit float to 64-bit float */
1640: void HELPER(ldeb)(uint32_t f1, uint64_t a2)
1641: {
1642: uint32_t v2;
1643: v2 = ldl(a2);
1644: env->fregs[f1].d = float32_to_float64(v2,
1645: &env->fpu_status);
1646: }
1647:
1.1.1.3 root 1648: /* convert 64-bit float to 128-bit float */
1649: void HELPER(lxdb)(uint32_t f1, uint64_t a2)
1650: {
1651: CPU_DoubleU v2;
1652: v2.ll = ldq(a2);
1653: CPU_QuadU v1;
1654: v1.q = float64_to_float128(v2.d, &env->fpu_status);
1655: env->fregs[f1].ll = v1.ll.upper;
1656: env->fregs[f1 + 2].ll = v1.ll.lower;
1657: }
1658:
1659: /* test data class 32-bit */
1660: uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2)
1661: {
1662: float32 v1 = env->fregs[f1].l.upper;
1663: int neg = float32_is_neg(v1);
1664: uint32_t cc = 0;
1665:
1666: HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg);
1667: if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
1668: (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
1669: (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
1670: (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
1671: cc = 1;
1672: } else if (m2 & (1 << (9-neg))) {
1673: /* assume normalized number */
1674: cc = 1;
1675: }
1676:
1677: /* FIXME: denormalized? */
1678: return cc;
1679: }
1680:
1681: /* test data class 64-bit */
1682: uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2)
1683: {
1684: float64 v1 = env->fregs[f1].d;
1685: int neg = float64_is_neg(v1);
1686: uint32_t cc = 0;
1687:
1688: HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg);
1689: if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
1690: (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
1691: (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
1692: (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
1693: cc = 1;
1694: } else if (m2 & (1 << (9-neg))) {
1695: /* assume normalized number */
1696: cc = 1;
1697: }
1698: /* FIXME: denormalized? */
1699: return cc;
1700: }
1701:
1702: /* test data class 128-bit */
1703: uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2)
1704: {
1705: CPU_QuadU v1;
1706: uint32_t cc = 0;
1707: v1.ll.upper = env->fregs[f1].ll;
1708: v1.ll.lower = env->fregs[f1 + 2].ll;
1709:
1710: int neg = float128_is_neg(v1.q);
1711: if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
1712: (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
1713: (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
1714: (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
1715: cc = 1;
1716: } else if (m2 & (1 << (9-neg))) {
1717: /* assume normalized number */
1718: cc = 1;
1719: }
1720: /* FIXME: denormalized? */
1721: return cc;
1722: }
1723:
1724: /* find leftmost one */
1725: uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2)
1726: {
1727: uint64_t res = 0;
1728: uint64_t ov2 = v2;
1729:
1730: while (!(v2 & 0x8000000000000000ULL) && v2) {
1731: v2 <<= 1;
1732: res++;
1733: }
1734:
1735: if (!v2) {
1736: env->regs[r1] = 64;
1737: env->regs[r1 + 1] = 0;
1738: return 0;
1739: } else {
1740: env->regs[r1] = res;
1741: env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
1742: return 2;
1743: }
1744: }
1745:
1746: /* square root 64-bit RR */
1747: void HELPER(sqdbr)(uint32_t f1, uint32_t f2)
1748: {
1749: env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
1750: }
1751:
1752: /* checksum */
1753: void HELPER(cksm)(uint32_t r1, uint32_t r2)
1754: {
1755: uint64_t src = get_address_31fix(r2);
1756: uint64_t src_len = env->regs[(r2 + 1) & 15];
1757: uint64_t cksm = (uint32_t)env->regs[r1];
1758:
1759: while (src_len >= 4) {
1760: cksm += ldl(src);
1761:
1762: /* move to next word */
1763: src_len -= 4;
1764: src += 4;
1765: }
1766:
1767: switch (src_len) {
1768: case 0:
1769: break;
1770: case 1:
1771: cksm += ldub(src) << 24;
1772: break;
1773: case 2:
1774: cksm += lduw(src) << 16;
1775: break;
1776: case 3:
1777: cksm += lduw(src) << 16;
1778: cksm += ldub(src + 2) << 8;
1779: break;
1780: }
1781:
1782: /* indicate we've processed everything */
1783: env->regs[r2] = src + src_len;
1784: env->regs[(r2 + 1) & 15] = 0;
1785:
1786: /* store result */
1787: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1788: ((uint32_t)cksm + (cksm >> 32));
1789: }
1790:
1.1.1.5 ! root 1791: static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
1.1.1.3 root 1792: int32_t dst)
1793: {
1794: if (src == dst) {
1795: return 0;
1796: } else if (src < dst) {
1797: return 1;
1798: } else {
1799: return 2;
1800: }
1801: }
1802:
1.1.1.5 ! root 1803: static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
1.1.1.3 root 1804: {
1805: return cc_calc_ltgt_32(env, dst, 0);
1806: }
1807:
1.1.1.5 ! root 1808: static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
1.1.1.3 root 1809: int64_t dst)
1810: {
1811: if (src == dst) {
1812: return 0;
1813: } else if (src < dst) {
1814: return 1;
1815: } else {
1816: return 2;
1817: }
1818: }
1819:
1.1.1.5 ! root 1820: static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
1.1.1.3 root 1821: {
1822: return cc_calc_ltgt_64(env, dst, 0);
1823: }
1824:
1.1.1.5 ! root 1825: static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
1.1.1.3 root 1826: uint32_t dst)
1827: {
1828: if (src == dst) {
1829: return 0;
1830: } else if (src < dst) {
1831: return 1;
1832: } else {
1833: return 2;
1834: }
1835: }
1836:
1.1.1.5 ! root 1837: static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
1.1.1.3 root 1838: uint64_t dst)
1839: {
1840: if (src == dst) {
1841: return 0;
1842: } else if (src < dst) {
1843: return 1;
1844: } else {
1845: return 2;
1846: }
1847: }
1848:
1.1.1.5 ! root 1849: static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask)
1.1.1.3 root 1850: {
1851: HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask);
1852: uint16_t r = val & mask;
1853: if (r == 0 || mask == 0) {
1854: return 0;
1855: } else if (r == mask) {
1856: return 3;
1857: } else {
1858: return 1;
1859: }
1860: }
1861:
1862: /* set condition code for test under mask */
1.1.1.5 ! root 1863: static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint32_t mask)
1.1.1.3 root 1864: {
1865: uint16_t r = val & mask;
1866: HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r);
1867: if (r == 0 || mask == 0) {
1868: return 0;
1869: } else if (r == mask) {
1870: return 3;
1871: } else {
1872: while (!(mask & 0x8000)) {
1873: mask <<= 1;
1874: val <<= 1;
1875: }
1876: if (val & 0x8000) {
1877: return 2;
1878: } else {
1879: return 1;
1880: }
1881: }
1882: }
1883:
1.1.1.5 ! root 1884: static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
1.1.1.3 root 1885: {
1886: return !!dst;
1887: }
1888:
1.1.1.5 ! root 1889: static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2,
1.1.1.3 root 1890: int64_t ar)
1891: {
1892: if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
1893: return 3; /* overflow */
1894: } else {
1895: if (ar < 0) {
1896: return 1;
1897: } else if (ar > 0) {
1898: return 2;
1899: } else {
1900: return 0;
1901: }
1902: }
1903: }
1904:
1.1.1.5 ! root 1905: static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t a2,
1.1.1.3 root 1906: uint64_t ar)
1907: {
1908: if (ar == 0) {
1909: if (a1) {
1910: return 2;
1911: } else {
1912: return 0;
1913: }
1914: } else {
1915: if (ar < a1 || ar < a2) {
1916: return 3;
1917: } else {
1918: return 1;
1919: }
1920: }
1921: }
1922:
1.1.1.5 ! root 1923: static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2,
1.1.1.3 root 1924: int64_t ar)
1925: {
1926: if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
1927: return 3; /* overflow */
1928: } else {
1929: if (ar < 0) {
1930: return 1;
1931: } else if (ar > 0) {
1932: return 2;
1933: } else {
1934: return 0;
1935: }
1936: }
1937: }
1938:
1.1.1.5 ! root 1939: static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, uint64_t a2,
1.1.1.3 root 1940: uint64_t ar)
1941: {
1942: if (ar == 0) {
1943: return 2;
1944: } else {
1945: if (a2 > a1) {
1946: return 1;
1947: } else {
1948: return 3;
1949: }
1950: }
1951: }
1952:
1.1.1.5 ! root 1953: static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
1.1.1.3 root 1954: {
1955: if ((uint64_t)dst == 0x8000000000000000ULL) {
1956: return 3;
1957: } else if (dst) {
1958: return 1;
1959: } else {
1960: return 0;
1961: }
1962: }
1963:
1.1.1.5 ! root 1964: static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
1.1.1.3 root 1965: {
1966: return !!dst;
1967: }
1968:
1.1.1.5 ! root 1969: static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
1.1.1.3 root 1970: {
1971: if ((uint64_t)dst == 0x8000000000000000ULL) {
1972: return 3;
1973: } else if (dst < 0) {
1974: return 1;
1975: } else if (dst > 0) {
1976: return 2;
1977: } else {
1978: return 0;
1979: }
1980: }
1981:
1982:
1.1.1.5 ! root 1983: static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2,
1.1.1.3 root 1984: int32_t ar)
1985: {
1986: if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
1987: return 3; /* overflow */
1988: } else {
1989: if (ar < 0) {
1990: return 1;
1991: } else if (ar > 0) {
1992: return 2;
1993: } else {
1994: return 0;
1995: }
1996: }
1997: }
1998:
1.1.1.5 ! root 1999: static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, uint32_t a2,
1.1.1.3 root 2000: uint32_t ar)
2001: {
2002: if (ar == 0) {
2003: if (a1) {
2004: return 2;
2005: } else {
2006: return 0;
2007: }
2008: } else {
2009: if (ar < a1 || ar < a2) {
2010: return 3;
2011: } else {
2012: return 1;
2013: }
2014: }
2015: }
2016:
1.1.1.5 ! root 2017: static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2,
1.1.1.3 root 2018: int32_t ar)
2019: {
2020: if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
2021: return 3; /* overflow */
2022: } else {
2023: if (ar < 0) {
2024: return 1;
2025: } else if (ar > 0) {
2026: return 2;
2027: } else {
2028: return 0;
2029: }
2030: }
2031: }
2032:
1.1.1.5 ! root 2033: static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, uint32_t a2,
1.1.1.3 root 2034: uint32_t ar)
2035: {
2036: if (ar == 0) {
2037: return 2;
2038: } else {
2039: if (a2 > a1) {
2040: return 1;
2041: } else {
2042: return 3;
2043: }
2044: }
2045: }
2046:
1.1.1.5 ! root 2047: static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
1.1.1.3 root 2048: {
2049: if ((uint32_t)dst == 0x80000000UL) {
2050: return 3;
2051: } else if (dst) {
2052: return 1;
2053: } else {
2054: return 0;
2055: }
2056: }
2057:
1.1.1.5 ! root 2058: static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
1.1.1.3 root 2059: {
2060: return !!dst;
2061: }
2062:
1.1.1.5 ! root 2063: static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
1.1.1.3 root 2064: {
2065: if ((uint32_t)dst == 0x80000000UL) {
2066: return 3;
2067: } else if (dst < 0) {
2068: return 1;
2069: } else if (dst > 0) {
2070: return 2;
2071: } else {
2072: return 0;
2073: }
2074: }
2075:
2076: /* calculate condition code for insert character under mask insn */
1.1.1.5 ! root 2077: static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_t val)
1.1.1.3 root 2078: {
2079: HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val);
2080: uint32_t cc;
2081:
2082: if (mask == 0xf) {
2083: if (!val) {
2084: return 0;
2085: } else if (val & 0x80000000) {
2086: return 1;
2087: } else {
2088: return 2;
2089: }
2090: }
2091:
2092: if (!val || !mask) {
2093: cc = 0;
2094: } else {
2095: while (mask != 1) {
2096: mask >>= 1;
2097: val >>= 8;
2098: }
2099: if (val & 0x80) {
2100: cc = 1;
2101: } else {
2102: cc = 2;
2103: }
2104: }
2105: return cc;
2106: }
2107:
1.1.1.5 ! root 2108: static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t shift)
1.1.1.3 root 2109: {
2110: uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
2111: uint64_t match, r;
2112:
2113: /* check if the sign bit stays the same */
2114: if (src & (1ULL << 63)) {
2115: match = mask;
2116: } else {
2117: match = 0;
2118: }
2119:
2120: if ((src & mask) != match) {
2121: /* overflow */
2122: return 3;
2123: }
2124:
2125: r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
2126:
2127: if ((int64_t)r == 0) {
2128: return 0;
2129: } else if ((int64_t)r < 0) {
2130: return 1;
2131: }
2132:
2133: return 2;
2134: }
2135:
2136:
1.1.1.5 ! root 2137: static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src,
1.1.1.3 root 2138: uint64_t dst, uint64_t vr)
2139: {
2140: uint32_t r = 0;
2141:
2142: switch (cc_op) {
2143: case CC_OP_CONST0:
2144: case CC_OP_CONST1:
2145: case CC_OP_CONST2:
2146: case CC_OP_CONST3:
2147: /* cc_op value _is_ cc */
2148: r = cc_op;
2149: break;
2150: case CC_OP_LTGT0_32:
2151: r = cc_calc_ltgt0_32(env, dst);
2152: break;
2153: case CC_OP_LTGT0_64:
2154: r = cc_calc_ltgt0_64(env, dst);
2155: break;
2156: case CC_OP_LTGT_32:
2157: r = cc_calc_ltgt_32(env, src, dst);
2158: break;
2159: case CC_OP_LTGT_64:
2160: r = cc_calc_ltgt_64(env, src, dst);
2161: break;
2162: case CC_OP_LTUGTU_32:
2163: r = cc_calc_ltugtu_32(env, src, dst);
2164: break;
2165: case CC_OP_LTUGTU_64:
2166: r = cc_calc_ltugtu_64(env, src, dst);
2167: break;
2168: case CC_OP_TM_32:
2169: r = cc_calc_tm_32(env, src, dst);
2170: break;
2171: case CC_OP_TM_64:
2172: r = cc_calc_tm_64(env, src, dst);
2173: break;
2174: case CC_OP_NZ:
2175: r = cc_calc_nz(env, dst);
2176: break;
2177: case CC_OP_ADD_64:
2178: r = cc_calc_add_64(env, src, dst, vr);
2179: break;
2180: case CC_OP_ADDU_64:
2181: r = cc_calc_addu_64(env, src, dst, vr);
2182: break;
2183: case CC_OP_SUB_64:
2184: r = cc_calc_sub_64(env, src, dst, vr);
2185: break;
2186: case CC_OP_SUBU_64:
2187: r = cc_calc_subu_64(env, src, dst, vr);
2188: break;
2189: case CC_OP_ABS_64:
2190: r = cc_calc_abs_64(env, dst);
2191: break;
2192: case CC_OP_NABS_64:
2193: r = cc_calc_nabs_64(env, dst);
2194: break;
2195: case CC_OP_COMP_64:
2196: r = cc_calc_comp_64(env, dst);
2197: break;
2198:
2199: case CC_OP_ADD_32:
2200: r = cc_calc_add_32(env, src, dst, vr);
2201: break;
2202: case CC_OP_ADDU_32:
2203: r = cc_calc_addu_32(env, src, dst, vr);
2204: break;
2205: case CC_OP_SUB_32:
2206: r = cc_calc_sub_32(env, src, dst, vr);
2207: break;
2208: case CC_OP_SUBU_32:
2209: r = cc_calc_subu_32(env, src, dst, vr);
2210: break;
2211: case CC_OP_ABS_32:
2212: r = cc_calc_abs_64(env, dst);
2213: break;
2214: case CC_OP_NABS_32:
2215: r = cc_calc_nabs_64(env, dst);
2216: break;
2217: case CC_OP_COMP_32:
2218: r = cc_calc_comp_32(env, dst);
2219: break;
2220:
2221: case CC_OP_ICM:
2222: r = cc_calc_icm_32(env, src, dst);
2223: break;
2224: case CC_OP_SLAG:
2225: r = cc_calc_slag(env, src, dst);
2226: break;
2227:
2228: case CC_OP_LTGT_F32:
2229: r = set_cc_f32(src, dst);
2230: break;
2231: case CC_OP_LTGT_F64:
2232: r = set_cc_f64(src, dst);
2233: break;
2234: case CC_OP_NZ_F32:
2235: r = set_cc_nz_f32(dst);
2236: break;
2237: case CC_OP_NZ_F64:
2238: r = set_cc_nz_f64(dst);
2239: break;
2240:
2241: default:
2242: cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
2243: }
2244:
2245: HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__,
2246: cc_name(cc_op), src, dst, vr, r);
2247: return r;
2248: }
2249:
1.1.1.5 ! root 2250: uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
1.1.1.3 root 2251: uint64_t vr)
2252: {
2253: return do_calc_cc(env, cc_op, src, dst, vr);
2254: }
2255:
2256: uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
2257: uint64_t vr)
2258: {
2259: return do_calc_cc(env, cc_op, src, dst, vr);
2260: }
2261:
2262: uint64_t HELPER(cvd)(int32_t bin)
2263: {
2264: /* positive 0 */
2265: uint64_t dec = 0x0c;
2266: int shift = 4;
2267:
2268: if (bin < 0) {
2269: bin = -bin;
2270: dec = 0x0d;
2271: }
2272:
2273: for (shift = 4; (shift < 64) && bin; shift += 4) {
2274: int current_number = bin % 10;
2275:
2276: dec |= (current_number) << shift;
2277: bin /= 10;
2278: }
2279:
2280: return dec;
2281: }
2282:
2283: void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
2284: {
2285: int len_dest = len >> 4;
2286: int len_src = len & 0xf;
2287: uint8_t b;
2288: int second_nibble = 0;
2289:
2290: dest += len_dest;
2291: src += len_src;
2292:
2293: /* last byte is special, it only flips the nibbles */
2294: b = ldub(src);
2295: stb(dest, (b << 4) | (b >> 4));
2296: src--;
2297: len_src--;
2298:
2299: /* now pad every nibble with 0xf0 */
2300:
2301: while (len_dest > 0) {
2302: uint8_t cur_byte = 0;
2303:
2304: if (len_src > 0) {
2305: cur_byte = ldub(src);
2306: }
2307:
2308: len_dest--;
2309: dest--;
2310:
2311: /* only advance one nibble at a time */
2312: if (second_nibble) {
2313: cur_byte >>= 4;
2314: len_src--;
2315: src--;
2316: }
2317: second_nibble = !second_nibble;
2318:
2319: /* digit */
2320: cur_byte = (cur_byte & 0xf);
2321: /* zone bits */
2322: cur_byte |= 0xf0;
2323:
2324: stb(dest, cur_byte);
2325: }
2326: }
2327:
2328: void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
2329: {
2330: int i;
2331:
2332: for (i = 0; i <= len; i++) {
2333: uint8_t byte = ldub(array + i);
2334: uint8_t new_byte = ldub(trans + byte);
2335: stb(array + i, new_byte);
2336: }
2337: }
2338:
2339: #ifndef CONFIG_USER_ONLY
2340:
2341: void HELPER(load_psw)(uint64_t mask, uint64_t addr)
2342: {
2343: load_psw(env, mask, addr);
2344: cpu_loop_exit(env);
2345: }
2346:
1.1.1.5 ! root 2347: static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
1.1.1.3 root 2348: {
2349: qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
2350:
2351: if (kvm_enabled()) {
2352: #ifdef CONFIG_KVM
2353: kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
2354: #endif
2355: } else {
2356: env->int_pgm_code = code;
2357: env->int_pgm_ilc = ilc;
2358: env->exception_index = EXCP_PGM;
2359: cpu_loop_exit(env);
2360: }
2361: }
2362:
1.1.1.5 ! root 2363: static void ext_interrupt(CPUS390XState *env, int type, uint32_t param,
1.1.1.3 root 2364: uint64_t param64)
2365: {
2366: cpu_inject_ext(env, type, param, param64);
2367: }
2368:
1.1.1.5 ! root 2369: int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
1.1.1.3 root 2370: {
2371: int r = 0;
2372: int shift = 0;
2373:
2374: #ifdef DEBUG_HELPER
2375: printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
2376: #endif
2377:
2378: if (sccb & ~0x7ffffff8ul) {
2379: fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
2380: r = -1;
2381: goto out;
2382: }
2383:
2384: switch(code) {
2385: case SCLP_CMDW_READ_SCP_INFO:
2386: case SCLP_CMDW_READ_SCP_INFO_FORCED:
2387: while ((ram_size >> (20 + shift)) > 65535) {
2388: shift++;
2389: }
2390: stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
2391: stb_phys(sccb + SCP_INCREMENT, 1 << shift);
2392: stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
2393:
2394: if (kvm_enabled()) {
2395: #ifdef CONFIG_KVM
2396: kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
2397: sccb & ~3, 0, 1);
2398: #endif
2399: } else {
2400: env->psw.addr += 4;
2401: ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
2402: }
2403: break;
2404: default:
2405: #ifdef DEBUG_HELPER
2406: printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
2407: #endif
2408: r = -1;
2409: break;
2410: }
2411:
2412: out:
2413: return r;
2414: }
2415:
2416: /* SCLP service call */
2417: uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
2418: {
2419: if (sclp_service_call(env, r1, r2)) {
2420: return 3;
2421: }
2422:
2423: return 0;
2424: }
2425:
2426: /* DIAG */
2427: uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
2428: {
2429: uint64_t r;
2430:
2431: switch (num) {
2432: case 0x500:
2433: /* KVM hypercall */
2434: r = s390_virtio_hypercall(env, mem, code);
2435: break;
2436: case 0x44:
2437: /* yield */
2438: r = 0;
2439: break;
2440: case 0x308:
2441: /* ipl */
2442: r = 0;
2443: break;
2444: default:
2445: r = -1;
2446: break;
2447: }
2448:
2449: if (r) {
2450: program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
2451: }
2452:
2453: return r;
2454: }
2455:
2456: /* Store CPU ID */
2457: void HELPER(stidp)(uint64_t a1)
2458: {
2459: stq(a1, env->cpu_num);
2460: }
2461:
2462: /* Set Prefix */
2463: void HELPER(spx)(uint64_t a1)
2464: {
2465: uint32_t prefix;
2466:
2467: prefix = ldl(a1);
2468: env->psa = prefix & 0xfffff000;
2469: qemu_log("prefix: %#x\n", prefix);
2470: tlb_flush_page(env, 0);
2471: tlb_flush_page(env, TARGET_PAGE_SIZE);
2472: }
2473:
2474: /* Set Clock */
2475: uint32_t HELPER(sck)(uint64_t a1)
2476: {
2477: /* XXX not implemented - is it necessary? */
2478:
2479: return 0;
2480: }
2481:
1.1.1.5 ! root 2482: static inline uint64_t clock_value(CPUS390XState *env)
1.1.1.3 root 2483: {
2484: uint64_t time;
2485:
2486: time = env->tod_offset +
2487: time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
2488:
2489: return time;
2490: }
2491:
2492: /* Store Clock */
2493: uint32_t HELPER(stck)(uint64_t a1)
2494: {
2495: stq(a1, clock_value(env));
2496:
2497: return 0;
2498: }
2499:
2500: /* Store Clock Extended */
2501: uint32_t HELPER(stcke)(uint64_t a1)
2502: {
2503: stb(a1, 0);
2504: /* basically the same value as stck */
2505: stq(a1 + 1, clock_value(env) | env->cpu_num);
2506: /* more fine grained than stck */
2507: stq(a1 + 9, 0);
2508: /* XXX programmable fields */
2509: stw(a1 + 17, 0);
2510:
2511:
2512: return 0;
2513: }
2514:
2515: /* Set Clock Comparator */
2516: void HELPER(sckc)(uint64_t a1)
2517: {
2518: uint64_t time = ldq(a1);
2519:
2520: if (time == -1ULL) {
2521: return;
2522: }
2523:
2524: /* difference between now and then */
2525: time -= clock_value(env);
2526: /* nanoseconds */
2527: time = (time * 125) >> 9;
2528:
2529: qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
2530: }
2531:
2532: /* Store Clock Comparator */
2533: void HELPER(stckc)(uint64_t a1)
2534: {
2535: /* XXX implement */
2536: stq(a1, 0);
2537: }
2538:
2539: /* Set CPU Timer */
2540: void HELPER(spt)(uint64_t a1)
2541: {
2542: uint64_t time = ldq(a1);
2543:
2544: if (time == -1ULL) {
2545: return;
2546: }
2547:
2548: /* nanoseconds */
2549: time = (time * 125) >> 9;
2550:
2551: qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
2552: }
2553:
2554: /* Store CPU Timer */
2555: void HELPER(stpt)(uint64_t a1)
2556: {
2557: /* XXX implement */
2558: stq(a1, 0);
2559: }
2560:
2561: /* Store System Information */
2562: uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
2563: {
2564: int cc = 0;
2565: int sel1, sel2;
2566:
2567: if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
2568: ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
2569: /* valid function code, invalid reserved bits */
2570: program_interrupt(env, PGM_SPECIFICATION, 2);
2571: }
2572:
2573: sel1 = r0 & STSI_R0_SEL1_MASK;
2574: sel2 = r1 & STSI_R1_SEL2_MASK;
2575:
2576: /* XXX: spec exception if sysib is not 4k-aligned */
2577:
2578: switch (r0 & STSI_LEVEL_MASK) {
2579: case STSI_LEVEL_1:
2580: if ((sel1 == 1) && (sel2 == 1)) {
2581: /* Basic Machine Configuration */
2582: struct sysib_111 sysib;
2583:
2584: memset(&sysib, 0, sizeof(sysib));
2585: ebcdic_put(sysib.manuf, "QEMU ", 16);
2586: /* same as machine type number in STORE CPU ID */
2587: ebcdic_put(sysib.type, "QEMU", 4);
2588: /* same as model number in STORE CPU ID */
2589: ebcdic_put(sysib.model, "QEMU ", 16);
2590: ebcdic_put(sysib.sequence, "QEMU ", 16);
2591: ebcdic_put(sysib.plant, "QEMU", 4);
2592: cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2593: } else if ((sel1 == 2) && (sel2 == 1)) {
2594: /* Basic Machine CPU */
2595: struct sysib_121 sysib;
2596:
2597: memset(&sysib, 0, sizeof(sysib));
2598: /* XXX make different for different CPUs? */
2599: ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
2600: ebcdic_put(sysib.plant, "QEMU", 4);
2601: stw_p(&sysib.cpu_addr, env->cpu_num);
2602: cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2603: } else if ((sel1 == 2) && (sel2 == 2)) {
2604: /* Basic Machine CPUs */
2605: struct sysib_122 sysib;
2606:
2607: memset(&sysib, 0, sizeof(sysib));
2608: stl_p(&sysib.capability, 0x443afc29);
2609: /* XXX change when SMP comes */
2610: stw_p(&sysib.total_cpus, 1);
2611: stw_p(&sysib.active_cpus, 1);
2612: stw_p(&sysib.standby_cpus, 0);
2613: stw_p(&sysib.reserved_cpus, 0);
2614: cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2615: } else {
2616: cc = 3;
2617: }
2618: break;
2619: case STSI_LEVEL_2:
2620: {
2621: if ((sel1 == 2) && (sel2 == 1)) {
2622: /* LPAR CPU */
2623: struct sysib_221 sysib;
2624:
2625: memset(&sysib, 0, sizeof(sysib));
2626: /* XXX make different for different CPUs? */
2627: ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
2628: ebcdic_put(sysib.plant, "QEMU", 4);
2629: stw_p(&sysib.cpu_addr, env->cpu_num);
2630: stw_p(&sysib.cpu_id, 0);
2631: cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2632: } else if ((sel1 == 2) && (sel2 == 2)) {
2633: /* LPAR CPUs */
2634: struct sysib_222 sysib;
2635:
2636: memset(&sysib, 0, sizeof(sysib));
2637: stw_p(&sysib.lpar_num, 0);
2638: sysib.lcpuc = 0;
2639: /* XXX change when SMP comes */
2640: stw_p(&sysib.total_cpus, 1);
2641: stw_p(&sysib.conf_cpus, 1);
2642: stw_p(&sysib.standby_cpus, 0);
2643: stw_p(&sysib.reserved_cpus, 0);
2644: ebcdic_put(sysib.name, "QEMU ", 8);
2645: stl_p(&sysib.caf, 1000);
2646: stw_p(&sysib.dedicated_cpus, 0);
2647: stw_p(&sysib.shared_cpus, 0);
2648: cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2649: } else {
2650: cc = 3;
2651: }
2652: break;
2653: }
2654: case STSI_LEVEL_3:
2655: {
2656: if ((sel1 == 2) && (sel2 == 2)) {
2657: /* VM CPUs */
2658: struct sysib_322 sysib;
2659:
2660: memset(&sysib, 0, sizeof(sysib));
2661: sysib.count = 1;
2662: /* XXX change when SMP comes */
2663: stw_p(&sysib.vm[0].total_cpus, 1);
2664: stw_p(&sysib.vm[0].conf_cpus, 1);
2665: stw_p(&sysib.vm[0].standby_cpus, 0);
2666: stw_p(&sysib.vm[0].reserved_cpus, 0);
2667: ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
2668: stl_p(&sysib.vm[0].caf, 1000);
2669: ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
2670: cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2671: } else {
2672: cc = 3;
2673: }
2674: break;
2675: }
2676: case STSI_LEVEL_CURRENT:
2677: env->regs[0] = STSI_LEVEL_3;
2678: break;
2679: default:
2680: cc = 3;
2681: break;
2682: }
2683:
2684: return cc;
2685: }
2686:
2687: void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
2688: {
2689: int i;
2690: uint64_t src = a2;
2691:
2692: for (i = r1;; i = (i + 1) % 16) {
2693: env->cregs[i] = ldq(src);
2694: HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
2695: i, src, env->cregs[i]);
2696: src += sizeof(uint64_t);
2697:
2698: if (i == r3) {
2699: break;
2700: }
2701: }
2702:
2703: tlb_flush(env, 1);
2704: }
2705:
2706: void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
2707: {
2708: int i;
2709: uint64_t src = a2;
2710:
2711: for (i = r1;; i = (i + 1) % 16) {
2712: env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
2713: src += sizeof(uint32_t);
2714:
2715: if (i == r3) {
2716: break;
2717: }
2718: }
2719:
2720: tlb_flush(env, 1);
2721: }
2722:
2723: void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
2724: {
2725: int i;
2726: uint64_t dest = a2;
2727:
2728: for (i = r1;; i = (i + 1) % 16) {
2729: stq(dest, env->cregs[i]);
2730: dest += sizeof(uint64_t);
2731:
2732: if (i == r3) {
2733: break;
2734: }
2735: }
2736: }
2737:
2738: void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
2739: {
2740: int i;
2741: uint64_t dest = a2;
2742:
2743: for (i = r1;; i = (i + 1) % 16) {
2744: stl(dest, env->cregs[i]);
2745: dest += sizeof(uint32_t);
2746:
2747: if (i == r3) {
2748: break;
2749: }
2750: }
2751: }
2752:
2753: uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
2754: {
2755: /* XXX implement */
2756:
2757: return 0;
2758: }
2759:
2760: /* insert storage key extended */
2761: uint64_t HELPER(iske)(uint64_t r2)
2762: {
2763: uint64_t addr = get_address(0, 0, r2);
2764:
2765: if (addr > ram_size) {
2766: return 0;
2767: }
2768:
2769: return env->storage_keys[addr / TARGET_PAGE_SIZE];
2770: }
2771:
2772: /* set storage key extended */
2773: void HELPER(sske)(uint32_t r1, uint64_t r2)
2774: {
2775: uint64_t addr = get_address(0, 0, r2);
2776:
2777: if (addr > ram_size) {
2778: return;
2779: }
2780:
2781: env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
2782: }
2783:
2784: /* reset reference bit extended */
2785: uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
2786: {
1.1.1.4 root 2787: uint8_t re;
2788: uint8_t key;
1.1.1.3 root 2789: if (r2 > ram_size) {
2790: return 0;
2791: }
2792:
1.1.1.4 root 2793: key = env->storage_keys[r2 / TARGET_PAGE_SIZE];
2794: re = key & (SK_R | SK_C);
2795: env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R);
1.1.1.3 root 2796:
2797: /*
2798: * cc
2799: *
2800: * 0 Reference bit zero; change bit zero
2801: * 1 Reference bit zero; change bit one
2802: * 2 Reference bit one; change bit zero
2803: * 3 Reference bit one; change bit one
2804: */
1.1.1.4 root 2805:
2806: return re >> 1;
1.1.1.3 root 2807: }
2808:
2809: /* compare and swap and purge */
2810: uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
2811: {
2812: uint32_t cc;
2813: uint32_t o1 = env->regs[r1];
2814: uint64_t a2 = get_address_31fix(r2) & ~3ULL;
2815: uint32_t o2 = ldl(a2);
2816:
2817: if (o1 == o2) {
2818: stl(a2, env->regs[(r1 + 1) & 15]);
2819: if (env->regs[r2] & 0x3) {
2820: /* flush TLB / ALB */
2821: tlb_flush(env, 1);
2822: }
2823: cc = 0;
2824: } else {
2825: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
2826: cc = 1;
2827: }
2828:
2829: return cc;
2830: }
2831:
2832: static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
2833: uint64_t mode2)
2834: {
2835: target_ulong src, dest;
2836: int flags, cc = 0, i;
2837:
2838: if (!l) {
2839: return 0;
2840: } else if (l > 256) {
2841: /* max 256 */
2842: l = 256;
2843: cc = 3;
2844: }
2845:
2846: if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
2847: cpu_loop_exit(env);
2848: }
2849: dest |= a1 & ~TARGET_PAGE_MASK;
2850:
2851: if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
2852: cpu_loop_exit(env);
2853: }
2854: src |= a2 & ~TARGET_PAGE_MASK;
2855:
2856: /* XXX replace w/ memcpy */
2857: for (i = 0; i < l; i++) {
2858: /* XXX be more clever */
2859: if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
2860: (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
2861: mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
2862: break;
2863: }
2864: stb_phys(dest + i, ldub_phys(src + i));
2865: }
2866:
2867: return cc;
2868: }
2869:
2870: uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
2871: {
2872: HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2873: __FUNCTION__, l, a1, a2);
2874:
2875: return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
2876: }
2877:
2878: uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
2879: {
2880: HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2881: __FUNCTION__, l, a1, a2);
2882:
2883: return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
2884: }
2885:
2886: uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
2887: {
2888: int cc = 0;
2889:
2890: HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
2891: __FUNCTION__, order_code, r1, cpu_addr);
2892:
2893: /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register"
2894: as parameter (input). Status (output) is always R1. */
2895:
2896: switch (order_code) {
2897: case SIGP_SET_ARCH:
2898: /* switch arch */
2899: break;
2900: case SIGP_SENSE:
2901: /* enumerate CPU status */
2902: if (cpu_addr) {
2903: /* XXX implement when SMP comes */
2904: return 3;
2905: }
2906: env->regs[r1] &= 0xffffffff00000000ULL;
2907: cc = 1;
2908: break;
1.1.1.4 root 2909: #if !defined (CONFIG_USER_ONLY)
2910: case SIGP_RESTART:
2911: qemu_system_reset_request();
2912: cpu_loop_exit(env);
2913: break;
2914: case SIGP_STOP:
2915: qemu_system_shutdown_request();
2916: cpu_loop_exit(env);
2917: break;
2918: #endif
1.1.1.3 root 2919: default:
2920: /* unknown sigp */
2921: fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
2922: cc = 3;
2923: }
2924:
2925: return cc;
2926: }
2927:
2928: void HELPER(sacf)(uint64_t a1)
2929: {
2930: HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1);
2931:
2932: switch (a1 & 0xf00) {
2933: case 0x000:
2934: env->psw.mask &= ~PSW_MASK_ASC;
2935: env->psw.mask |= PSW_ASC_PRIMARY;
2936: break;
2937: case 0x100:
2938: env->psw.mask &= ~PSW_MASK_ASC;
2939: env->psw.mask |= PSW_ASC_SECONDARY;
2940: break;
2941: case 0x300:
2942: env->psw.mask &= ~PSW_MASK_ASC;
2943: env->psw.mask |= PSW_ASC_HOME;
2944: break;
2945: default:
2946: qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
2947: program_interrupt(env, PGM_SPECIFICATION, 2);
2948: break;
2949: }
2950: }
2951:
2952: /* invalidate pte */
2953: void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
2954: {
2955: uint64_t page = vaddr & TARGET_PAGE_MASK;
2956: uint64_t pte = 0;
2957:
2958: /* XXX broadcast to other CPUs */
2959:
2960: /* XXX Linux is nice enough to give us the exact pte address.
2961: According to spec we'd have to find it out ourselves */
2962: /* XXX Linux is fine with overwriting the pte, the spec requires
2963: us to only set the invalid bit */
2964: stq_phys(pte_addr, pte | _PAGE_INVALID);
2965:
2966: /* XXX we exploit the fact that Linux passes the exact virtual
2967: address here - it's not obliged to! */
2968: tlb_flush_page(env, page);
1.1.1.4 root 2969:
2970: /* XXX 31-bit hack */
2971: if (page & 0x80000000) {
2972: tlb_flush_page(env, page & ~0x80000000);
2973: } else {
2974: tlb_flush_page(env, page | 0x80000000);
2975: }
1.1.1.3 root 2976: }
2977:
2978: /* flush local tlb */
2979: void HELPER(ptlb)(void)
2980: {
2981: tlb_flush(env, 1);
2982: }
2983:
2984: /* store using real address */
2985: void HELPER(stura)(uint64_t addr, uint32_t v1)
2986: {
2987: stw_phys(get_address(0, 0, addr), v1);
2988: }
2989:
2990: /* load real address */
2991: uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
2992: {
2993: uint32_t cc = 0;
2994: int old_exc = env->exception_index;
2995: uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2996: uint64_t ret;
2997: int flags;
2998:
2999: /* XXX incomplete - has more corner cases */
3000: if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
3001: program_interrupt(env, PGM_SPECIAL_OP, 2);
3002: }
3003:
3004: env->exception_index = old_exc;
3005: if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
3006: cc = 3;
3007: }
3008: if (env->exception_index == EXCP_PGM) {
3009: ret = env->int_pgm_code | 0x80000000;
3010: } else {
3011: ret |= addr & ~TARGET_PAGE_MASK;
3012: }
3013: env->exception_index = old_exc;
3014:
3015: if (!(env->psw.mask & PSW_MASK_64)) {
3016: env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL);
3017: } else {
3018: env->regs[r1] = ret;
3019: }
3020:
3021: return cc;
3022: }
3023:
3024: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.