block/vvfat: Fix potential memory leaks and other memory errors
[qemu.git] / target-s390x / op_helper.c
blobcd576781503b23e97e4e29d4295ecf4672f67603
1 /*
2 * S/390 helper routines
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
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.
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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "cpu.h"
22 #include "dyngen-exec.h"
23 #include "host-utils.h"
24 #include "helpers.h"
25 #include <string.h>
26 #include "kvm.h"
27 #include "qemu-timer.h"
28 #ifdef CONFIG_KVM
29 #include <linux/kvm.h>
30 #endif
32 /*****************************************************************************/
33 /* Softmmu support */
34 #if !defined (CONFIG_USER_ONLY)
35 #include "softmmu_exec.h"
37 #define MMUSUFFIX _mmu
39 #define SHIFT 0
40 #include "softmmu_template.h"
42 #define SHIFT 1
43 #include "softmmu_template.h"
45 #define SHIFT 2
46 #include "softmmu_template.h"
48 #define SHIFT 3
49 #include "softmmu_template.h"
51 /* try to fill the TLB and return an exception if error. If retaddr is
52 NULL, it means that the function was called in C code (i.e. not
53 from generated code or from helper.c) */
54 /* XXX: fix it to restore all registers */
55 void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
56 void *retaddr)
58 TranslationBlock *tb;
59 CPUState *saved_env;
60 unsigned long pc;
61 int ret;
63 saved_env = env;
64 env = env1;
65 ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
66 if (unlikely(ret != 0)) {
67 if (likely(retaddr)) {
68 /* now we have a real cpu fault */
69 pc = (unsigned long)retaddr;
70 tb = tb_find_pc(pc);
71 if (likely(tb)) {
72 /* the PC is inside the translated code. It means that we have
73 a virtual CPU fault */
74 cpu_restore_state(tb, env, pc);
77 cpu_loop_exit(env);
79 env = saved_env;
82 #endif
84 /* #define DEBUG_HELPER */
85 #ifdef DEBUG_HELPER
86 #define HELPER_LOG(x...) qemu_log(x)
87 #else
88 #define HELPER_LOG(x...)
89 #endif
91 /* raise an exception */
92 void HELPER(exception)(uint32_t excp)
94 HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp);
95 env->exception_index = excp;
96 cpu_loop_exit(env);
99 #ifndef CONFIG_USER_ONLY
100 static void mvc_fast_memset(CPUState *env, uint32_t l, uint64_t dest,
101 uint8_t byte)
103 target_phys_addr_t dest_phys;
104 target_phys_addr_t len = l;
105 void *dest_p;
106 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
107 int flags;
109 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
110 stb(dest, byte);
111 cpu_abort(env, "should never reach here");
113 dest_phys |= dest & ~TARGET_PAGE_MASK;
115 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
117 memset(dest_p, byte, len);
119 cpu_physical_memory_unmap(dest_p, 1, len, len);
122 static void mvc_fast_memmove(CPUState *env, uint32_t l, uint64_t dest,
123 uint64_t src)
125 target_phys_addr_t dest_phys;
126 target_phys_addr_t src_phys;
127 target_phys_addr_t len = l;
128 void *dest_p;
129 void *src_p;
130 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
131 int flags;
133 if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) {
134 stb(dest, 0);
135 cpu_abort(env, "should never reach here");
137 dest_phys |= dest & ~TARGET_PAGE_MASK;
139 if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) {
140 ldub(src);
141 cpu_abort(env, "should never reach here");
143 src_phys |= src & ~TARGET_PAGE_MASK;
145 dest_p = cpu_physical_memory_map(dest_phys, &len, 1);
146 src_p = cpu_physical_memory_map(src_phys, &len, 0);
148 memmove(dest_p, src_p, len);
150 cpu_physical_memory_unmap(dest_p, 1, len, len);
151 cpu_physical_memory_unmap(src_p, 0, len, len);
153 #endif
155 /* and on array */
156 uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src)
158 int i;
159 unsigned char x;
160 uint32_t cc = 0;
162 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
163 __FUNCTION__, l, dest, src);
164 for (i = 0; i <= l; i++) {
165 x = ldub(dest + i) & ldub(src + i);
166 if (x) {
167 cc = 1;
169 stb(dest + i, x);
171 return cc;
174 /* xor on array */
175 uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src)
177 int i;
178 unsigned char x;
179 uint32_t cc = 0;
181 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
182 __FUNCTION__, l, dest, src);
184 #ifndef CONFIG_USER_ONLY
185 /* xor with itself is the same as memset(0) */
186 if ((l > 32) && (src == dest) &&
187 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) {
188 mvc_fast_memset(env, l + 1, dest, 0);
189 return 0;
191 #else
192 if (src == dest) {
193 memset(g2h(dest), 0, l + 1);
194 return 0;
196 #endif
198 for (i = 0; i <= l; i++) {
199 x = ldub(dest + i) ^ ldub(src + i);
200 if (x) {
201 cc = 1;
203 stb(dest + i, x);
205 return cc;
208 /* or on array */
209 uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src)
211 int i;
212 unsigned char x;
213 uint32_t cc = 0;
215 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
216 __FUNCTION__, l, dest, src);
217 for (i = 0; i <= l; i++) {
218 x = ldub(dest + i) | ldub(src + i);
219 if (x) {
220 cc = 1;
222 stb(dest + i, x);
224 return cc;
227 /* memmove */
228 void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src)
230 int i = 0;
231 int x = 0;
232 uint32_t l_64 = (l + 1) / 8;
234 HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n",
235 __FUNCTION__, l, dest, src);
237 #ifndef CONFIG_USER_ONLY
238 if ((l > 32) &&
239 (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) &&
240 (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) {
241 if (dest == (src + 1)) {
242 mvc_fast_memset(env, l + 1, dest, ldub(src));
243 return;
244 } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) {
245 mvc_fast_memmove(env, l + 1, dest, src);
246 return;
249 #else
250 if (dest == (src + 1)) {
251 memset(g2h(dest), ldub(src), l + 1);
252 return;
253 } else {
254 memmove(g2h(dest), g2h(src), l + 1);
255 return;
257 #endif
259 /* handle the parts that fit into 8-byte loads/stores */
260 if (dest != (src + 1)) {
261 for (i = 0; i < l_64; i++) {
262 stq(dest + x, ldq(src + x));
263 x += 8;
267 /* slow version crossing pages with byte accesses */
268 for (i = x; i <= l; i++) {
269 stb(dest + i, ldub(src + i));
273 /* compare unsigned byte arrays */
274 uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2)
276 int i;
277 unsigned char x,y;
278 uint32_t cc;
279 HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n",
280 __FUNCTION__, l, s1, s2);
281 for (i = 0; i <= l; i++) {
282 x = ldub(s1 + i);
283 y = ldub(s2 + i);
284 HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y);
285 if (x < y) {
286 cc = 1;
287 goto done;
288 } else if (x > y) {
289 cc = 2;
290 goto done;
293 cc = 0;
294 done:
295 HELPER_LOG("\n");
296 return cc;
299 /* compare logical under mask */
300 uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr)
302 uint8_t r,d;
303 uint32_t cc;
304 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1,
305 mask, addr);
306 cc = 0;
307 while (mask) {
308 if (mask & 8) {
309 d = ldub(addr);
310 r = (r1 & 0xff000000UL) >> 24;
311 HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d,
312 addr);
313 if (r < d) {
314 cc = 1;
315 break;
316 } else if (r > d) {
317 cc = 2;
318 break;
320 addr++;
322 mask = (mask << 1) & 0xf;
323 r1 <<= 8;
325 HELPER_LOG("\n");
326 return cc;
329 /* store character under mask */
330 void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr)
332 uint8_t r;
333 HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask,
334 addr);
335 while (mask) {
336 if (mask & 8) {
337 r = (r1 & 0xff000000UL) >> 24;
338 stb(addr, r);
339 HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr);
340 addr++;
342 mask = (mask << 1) & 0xf;
343 r1 <<= 8;
345 HELPER_LOG("\n");
348 /* 64/64 -> 128 unsigned multiplication */
349 void HELPER(mlg)(uint32_t r1, uint64_t v2)
351 #if HOST_LONG_BITS == 64 && defined(__GNUC__)
352 /* assuming 64-bit hosts have __uint128_t */
353 __uint128_t res = (__uint128_t)env->regs[r1 + 1];
354 res *= (__uint128_t)v2;
355 env->regs[r1] = (uint64_t)(res >> 64);
356 env->regs[r1 + 1] = (uint64_t)res;
357 #else
358 mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2);
359 #endif
362 /* 128 -> 64/64 unsigned division */
363 void HELPER(dlg)(uint32_t r1, uint64_t v2)
365 uint64_t divisor = v2;
367 if (!env->regs[r1]) {
368 /* 64 -> 64/64 case */
369 env->regs[r1] = env->regs[r1+1] % divisor;
370 env->regs[r1+1] = env->regs[r1+1] / divisor;
371 return;
372 } else {
374 #if HOST_LONG_BITS == 64 && defined(__GNUC__)
375 /* assuming 64-bit hosts have __uint128_t */
376 __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) |
377 (env->regs[r1+1]);
378 __uint128_t quotient = dividend / divisor;
379 env->regs[r1+1] = quotient;
380 __uint128_t remainder = dividend % divisor;
381 env->regs[r1] = remainder;
382 #else
383 /* 32-bit hosts would need special wrapper functionality - just abort if
384 we encounter such a case; it's very unlikely anyways. */
385 cpu_abort(env, "128 -> 64/64 division not implemented\n");
386 #endif
390 static inline uint64_t get_address(int x2, int b2, int d2)
392 uint64_t r = d2;
394 if (x2) {
395 r += env->regs[x2];
398 if (b2) {
399 r += env->regs[b2];
402 /* 31-Bit mode */
403 if (!(env->psw.mask & PSW_MASK_64)) {
404 r &= 0x7fffffff;
407 return r;
410 static inline uint64_t get_address_31fix(int reg)
412 uint64_t r = env->regs[reg];
414 /* 31-Bit mode */
415 if (!(env->psw.mask & PSW_MASK_64)) {
416 r &= 0x7fffffff;
419 return r;
422 /* search string (c is byte to search, r2 is string, r1 end of string) */
423 uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2)
425 uint64_t i;
426 uint32_t cc = 2;
427 uint64_t str = get_address_31fix(r2);
428 uint64_t end = get_address_31fix(r1);
430 HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__,
431 c, env->regs[r1], env->regs[r2]);
433 for (i = str; i != end; i++) {
434 if (ldub(i) == c) {
435 env->regs[r1] = i;
436 cc = 1;
437 break;
441 return cc;
444 /* unsigned string compare (c is string terminator) */
445 uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2)
447 uint64_t s1 = get_address_31fix(r1);
448 uint64_t s2 = get_address_31fix(r2);
449 uint8_t v1, v2;
450 uint32_t cc;
451 c = c & 0xff;
452 #ifdef CONFIG_USER_ONLY
453 if (!c) {
454 HELPER_LOG("%s: comparing '%s' and '%s'\n",
455 __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2));
457 #endif
458 for (;;) {
459 v1 = ldub(s1);
460 v2 = ldub(s2);
461 if ((v1 == c || v2 == c) || (v1 != v2)) {
462 break;
464 s1++;
465 s2++;
468 if (v1 == v2) {
469 cc = 0;
470 } else {
471 cc = (v1 < v2) ? 1 : 2;
472 /* FIXME: 31-bit mode! */
473 env->regs[r1] = s1;
474 env->regs[r2] = s2;
476 return cc;
479 /* move page */
480 void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2)
482 /* XXX missing r0 handling */
483 #ifdef CONFIG_USER_ONLY
484 int i;
486 for (i = 0; i < TARGET_PAGE_SIZE; i++) {
487 stb(r1 + i, ldub(r2 + i));
489 #else
490 mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2);
491 #endif
494 /* string copy (c is string terminator) */
495 void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2)
497 uint64_t dest = get_address_31fix(r1);
498 uint64_t src = get_address_31fix(r2);
499 uint8_t v;
500 c = c & 0xff;
501 #ifdef CONFIG_USER_ONLY
502 if (!c) {
503 HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src),
504 dest);
506 #endif
507 for (;;) {
508 v = ldub(src);
509 stb(dest, v);
510 if (v == c) {
511 break;
513 src++;
514 dest++;
516 env->regs[r1] = dest; /* FIXME: 31-bit mode! */
519 /* compare and swap 64-bit */
520 uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3)
522 /* FIXME: locking? */
523 uint32_t cc;
524 uint64_t v2 = ldq(a2);
525 if (env->regs[r1] == v2) {
526 cc = 0;
527 stq(a2, env->regs[r3]);
528 } else {
529 cc = 1;
530 env->regs[r1] = v2;
532 return cc;
535 /* compare double and swap 64-bit */
536 uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3)
538 /* FIXME: locking? */
539 uint32_t cc;
540 uint64_t v2_hi = ldq(a2);
541 uint64_t v2_lo = ldq(a2 + 8);
542 uint64_t v1_hi = env->regs[r1];
543 uint64_t v1_lo = env->regs[r1 + 1];
545 if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) {
546 cc = 0;
547 stq(a2, env->regs[r3]);
548 stq(a2 + 8, env->regs[r3 + 1]);
549 } else {
550 cc = 1;
551 env->regs[r1] = v2_hi;
552 env->regs[r1 + 1] = v2_lo;
555 return cc;
558 /* compare and swap 32-bit */
559 uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3)
561 /* FIXME: locking? */
562 uint32_t cc;
563 HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3);
564 uint32_t v2 = ldl(a2);
565 if (((uint32_t)env->regs[r1]) == v2) {
566 cc = 0;
567 stl(a2, (uint32_t)env->regs[r3]);
568 } else {
569 cc = 1;
570 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2;
572 return cc;
575 static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask)
577 int pos = 24; /* top of the lower half of r1 */
578 uint64_t rmask = 0xff000000ULL;
579 uint8_t val = 0;
580 int ccd = 0;
581 uint32_t cc = 0;
583 while (mask) {
584 if (mask & 8) {
585 env->regs[r1] &= ~rmask;
586 val = ldub(address);
587 if ((val & 0x80) && !ccd) {
588 cc = 1;
590 ccd = 1;
591 if (val && cc == 0) {
592 cc = 2;
594 env->regs[r1] |= (uint64_t)val << pos;
595 address++;
597 mask = (mask << 1) & 0xf;
598 pos -= 8;
599 rmask >>= 8;
602 return cc;
605 /* execute instruction
606 this instruction executes an insn modified with the contents of r1
607 it does not change the executed instruction in memory
608 it does not change the program counter
609 in other words: tricky...
610 currently implemented by interpreting the cases it is most commonly used in
612 uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret)
614 uint16_t insn = lduw_code(addr);
615 HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr,
616 insn);
617 if ((insn & 0xf0ff) == 0xd000) {
618 uint32_t l, insn2, b1, b2, d1, d2;
619 l = v1 & 0xff;
620 insn2 = ldl_code(addr + 2);
621 b1 = (insn2 >> 28) & 0xf;
622 b2 = (insn2 >> 12) & 0xf;
623 d1 = (insn2 >> 16) & 0xfff;
624 d2 = insn2 & 0xfff;
625 switch (insn & 0xf00) {
626 case 0x200:
627 helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2));
628 break;
629 case 0x500:
630 cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2));
631 break;
632 case 0x700:
633 cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2));
634 break;
635 default:
636 goto abort;
637 break;
639 } else if ((insn & 0xff00) == 0x0a00) {
640 /* supervisor call */
641 HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff);
642 env->psw.addr = ret - 4;
643 env->int_svc_code = (insn|v1) & 0xff;
644 env->int_svc_ilc = 4;
645 helper_exception(EXCP_SVC);
646 } else if ((insn & 0xff00) == 0xbf00) {
647 uint32_t insn2, r1, r3, b2, d2;
648 insn2 = ldl_code(addr + 2);
649 r1 = (insn2 >> 20) & 0xf;
650 r3 = (insn2 >> 16) & 0xf;
651 b2 = (insn2 >> 12) & 0xf;
652 d2 = insn2 & 0xfff;
653 cc = helper_icm(r1, get_address(0, b2, d2), r3);
654 } else {
655 abort:
656 cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n",
657 insn);
659 return cc;
662 /* absolute value 32-bit */
663 uint32_t HELPER(abs_i32)(int32_t val)
665 if (val < 0) {
666 return -val;
667 } else {
668 return val;
672 /* negative absolute value 32-bit */
673 int32_t HELPER(nabs_i32)(int32_t val)
675 if (val < 0) {
676 return val;
677 } else {
678 return -val;
682 /* absolute value 64-bit */
683 uint64_t HELPER(abs_i64)(int64_t val)
685 HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val);
687 if (val < 0) {
688 return -val;
689 } else {
690 return val;
694 /* negative absolute value 64-bit */
695 int64_t HELPER(nabs_i64)(int64_t val)
697 if (val < 0) {
698 return val;
699 } else {
700 return -val;
704 /* add with carry 32-bit unsigned */
705 uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2)
707 uint32_t res;
709 res = v1 + v2;
710 if (cc & 2) {
711 res++;
714 return res;
717 /* store character under mask high operates on the upper half of r1 */
718 void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask)
720 int pos = 56; /* top of the upper half of r1 */
722 while (mask) {
723 if (mask & 8) {
724 stb(address, (env->regs[r1] >> pos) & 0xff);
725 address++;
727 mask = (mask << 1) & 0xf;
728 pos -= 8;
732 /* insert character under mask high; same as icm, but operates on the
733 upper half of r1 */
734 uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask)
736 int pos = 56; /* top of the upper half of r1 */
737 uint64_t rmask = 0xff00000000000000ULL;
738 uint8_t val = 0;
739 int ccd = 0;
740 uint32_t cc = 0;
742 while (mask) {
743 if (mask & 8) {
744 env->regs[r1] &= ~rmask;
745 val = ldub(address);
746 if ((val & 0x80) && !ccd) {
747 cc = 1;
749 ccd = 1;
750 if (val && cc == 0) {
751 cc = 2;
753 env->regs[r1] |= (uint64_t)val << pos;
754 address++;
756 mask = (mask << 1) & 0xf;
757 pos -= 8;
758 rmask >>= 8;
761 return cc;
764 /* insert psw mask and condition code into r1 */
765 void HELPER(ipm)(uint32_t cc, uint32_t r1)
767 uint64_t r = env->regs[r1];
769 r &= 0xffffffff00ffffffULL;
770 r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf );
771 env->regs[r1] = r;
772 HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__,
773 cc, env->psw.mask, r);
776 /* load access registers r1 to r3 from memory at a2 */
777 void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3)
779 int i;
781 for (i = r1;; i = (i + 1) % 16) {
782 env->aregs[i] = ldl(a2);
783 a2 += 4;
785 if (i == r3) {
786 break;
791 /* store access registers r1 to r3 in memory at a2 */
792 void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3)
794 int i;
796 for (i = r1;; i = (i + 1) % 16) {
797 stl(a2, env->aregs[i]);
798 a2 += 4;
800 if (i == r3) {
801 break;
806 /* move long */
807 uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2)
809 uint64_t destlen = env->regs[r1 + 1] & 0xffffff;
810 uint64_t dest = get_address_31fix(r1);
811 uint64_t srclen = env->regs[r2 + 1] & 0xffffff;
812 uint64_t src = get_address_31fix(r2);
813 uint8_t pad = src >> 24;
814 uint8_t v;
815 uint32_t cc;
817 if (destlen == srclen) {
818 cc = 0;
819 } else if (destlen < srclen) {
820 cc = 1;
821 } else {
822 cc = 2;
825 if (srclen > destlen) {
826 srclen = destlen;
829 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
830 v = ldub(src);
831 stb(dest, v);
834 for (; destlen; dest++, destlen--) {
835 stb(dest, pad);
838 env->regs[r1 + 1] = destlen;
839 /* can't use srclen here, we trunc'ed it */
840 env->regs[r2 + 1] -= src - env->regs[r2];
841 env->regs[r1] = dest;
842 env->regs[r2] = src;
844 return cc;
847 /* move long extended another memcopy insn with more bells and whistles */
848 uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3)
850 uint64_t destlen = env->regs[r1 + 1];
851 uint64_t dest = env->regs[r1];
852 uint64_t srclen = env->regs[r3 + 1];
853 uint64_t src = env->regs[r3];
854 uint8_t pad = a2 & 0xff;
855 uint8_t v;
856 uint32_t cc;
858 if (!(env->psw.mask & PSW_MASK_64)) {
859 destlen = (uint32_t)destlen;
860 srclen = (uint32_t)srclen;
861 dest &= 0x7fffffff;
862 src &= 0x7fffffff;
865 if (destlen == srclen) {
866 cc = 0;
867 } else if (destlen < srclen) {
868 cc = 1;
869 } else {
870 cc = 2;
873 if (srclen > destlen) {
874 srclen = destlen;
877 for (; destlen && srclen; src++, dest++, destlen--, srclen--) {
878 v = ldub(src);
879 stb(dest, v);
882 for (; destlen; dest++, destlen--) {
883 stb(dest, pad);
886 env->regs[r1 + 1] = destlen;
887 /* can't use srclen here, we trunc'ed it */
888 /* FIXME: 31-bit mode! */
889 env->regs[r3 + 1] -= src - env->regs[r3];
890 env->regs[r1] = dest;
891 env->regs[r3] = src;
893 return cc;
896 /* compare logical long extended memcompare insn with padding */
897 uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3)
899 uint64_t destlen = env->regs[r1 + 1];
900 uint64_t dest = get_address_31fix(r1);
901 uint64_t srclen = env->regs[r3 + 1];
902 uint64_t src = get_address_31fix(r3);
903 uint8_t pad = a2 & 0xff;
904 uint8_t v1 = 0,v2 = 0;
905 uint32_t cc = 0;
907 if (!(destlen || srclen)) {
908 return cc;
911 if (srclen > destlen) {
912 srclen = destlen;
915 for (; destlen || srclen; src++, dest++, destlen--, srclen--) {
916 v1 = srclen ? ldub(src) : pad;
917 v2 = destlen ? ldub(dest) : pad;
918 if (v1 != v2) {
919 cc = (v1 < v2) ? 1 : 2;
920 break;
924 env->regs[r1 + 1] = destlen;
925 /* can't use srclen here, we trunc'ed it */
926 env->regs[r3 + 1] -= src - env->regs[r3];
927 env->regs[r1] = dest;
928 env->regs[r3] = src;
930 return cc;
933 /* subtract unsigned v2 from v1 with borrow */
934 uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2)
936 uint32_t v1 = env->regs[r1];
937 uint32_t res = v1 + (~v2) + (cc >> 1);
939 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res;
940 if (cc & 2) {
941 /* borrow */
942 return v1 ? 1 : 0;
943 } else {
944 return v1 ? 3 : 2;
948 /* subtract unsigned v2 from v1 with borrow */
949 uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2)
951 uint64_t res = v1 + (~v2) + (cc >> 1);
953 env->regs[r1] = res;
954 if (cc & 2) {
955 /* borrow */
956 return v1 ? 1 : 0;
957 } else {
958 return v1 ? 3 : 2;
962 static inline int float_comp_to_cc(int float_compare)
964 switch (float_compare) {
965 case float_relation_equal:
966 return 0;
967 case float_relation_less:
968 return 1;
969 case float_relation_greater:
970 return 2;
971 case float_relation_unordered:
972 return 3;
973 default:
974 cpu_abort(env, "unknown return value for float compare\n");
978 /* condition codes for binary FP ops */
979 static uint32_t set_cc_f32(float32 v1, float32 v2)
981 return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status));
984 static uint32_t set_cc_f64(float64 v1, float64 v2)
986 return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status));
989 /* condition codes for unary FP ops */
990 static uint32_t set_cc_nz_f32(float32 v)
992 if (float32_is_any_nan(v)) {
993 return 3;
994 } else if (float32_is_zero(v)) {
995 return 0;
996 } else if (float32_is_neg(v)) {
997 return 1;
998 } else {
999 return 2;
1003 static uint32_t set_cc_nz_f64(float64 v)
1005 if (float64_is_any_nan(v)) {
1006 return 3;
1007 } else if (float64_is_zero(v)) {
1008 return 0;
1009 } else if (float64_is_neg(v)) {
1010 return 1;
1011 } else {
1012 return 2;
1016 static uint32_t set_cc_nz_f128(float128 v)
1018 if (float128_is_any_nan(v)) {
1019 return 3;
1020 } else if (float128_is_zero(v)) {
1021 return 0;
1022 } else if (float128_is_neg(v)) {
1023 return 1;
1024 } else {
1025 return 2;
1029 /* convert 32-bit int to 64-bit float */
1030 void HELPER(cdfbr)(uint32_t f1, int32_t v2)
1032 HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1);
1033 env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
1036 /* convert 32-bit int to 128-bit float */
1037 void HELPER(cxfbr)(uint32_t f1, int32_t v2)
1039 CPU_QuadU v1;
1040 v1.q = int32_to_float128(v2, &env->fpu_status);
1041 env->fregs[f1].ll = v1.ll.upper;
1042 env->fregs[f1 + 2].ll = v1.ll.lower;
1045 /* convert 64-bit int to 32-bit float */
1046 void HELPER(cegbr)(uint32_t f1, int64_t v2)
1048 HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
1049 env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
1052 /* convert 64-bit int to 64-bit float */
1053 void HELPER(cdgbr)(uint32_t f1, int64_t v2)
1055 HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1);
1056 env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
1059 /* convert 64-bit int to 128-bit float */
1060 void HELPER(cxgbr)(uint32_t f1, int64_t v2)
1062 CPU_QuadU x1;
1063 x1.q = int64_to_float128(v2, &env->fpu_status);
1064 HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2,
1065 x1.ll.upper, x1.ll.lower);
1066 env->fregs[f1].ll = x1.ll.upper;
1067 env->fregs[f1 + 2].ll = x1.ll.lower;
1070 /* convert 32-bit int to 32-bit float */
1071 void HELPER(cefbr)(uint32_t f1, int32_t v2)
1073 env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
1074 HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2,
1075 env->fregs[f1].l.upper, f1);
1078 /* 32-bit FP addition RR */
1079 uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2)
1081 env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
1082 env->fregs[f2].l.upper,
1083 &env->fpu_status);
1084 HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
1085 env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
1087 return set_cc_nz_f32(env->fregs[f1].l.upper);
1090 /* 64-bit FP addition RR */
1091 uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2)
1093 env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d,
1094 &env->fpu_status);
1095 HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__,
1096 env->fregs[f2].d, env->fregs[f1].d, f1);
1098 return set_cc_nz_f64(env->fregs[f1].d);
1101 /* 32-bit FP subtraction RR */
1102 uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2)
1104 env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper,
1105 env->fregs[f2].l.upper,
1106 &env->fpu_status);
1107 HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__,
1108 env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1);
1110 return set_cc_nz_f32(env->fregs[f1].l.upper);
1113 /* 64-bit FP subtraction RR */
1114 uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2)
1116 env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d,
1117 &env->fpu_status);
1118 HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n",
1119 __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1);
1121 return set_cc_nz_f64(env->fregs[f1].d);
1124 /* 32-bit FP division RR */
1125 void HELPER(debr)(uint32_t f1, uint32_t f2)
1127 env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper,
1128 env->fregs[f2].l.upper,
1129 &env->fpu_status);
1132 /* 128-bit FP division RR */
1133 void HELPER(dxbr)(uint32_t f1, uint32_t f2)
1135 CPU_QuadU v1;
1136 v1.ll.upper = env->fregs[f1].ll;
1137 v1.ll.lower = env->fregs[f1 + 2].ll;
1138 CPU_QuadU v2;
1139 v2.ll.upper = env->fregs[f2].ll;
1140 v2.ll.lower = env->fregs[f2 + 2].ll;
1141 CPU_QuadU res;
1142 res.q = float128_div(v1.q, v2.q, &env->fpu_status);
1143 env->fregs[f1].ll = res.ll.upper;
1144 env->fregs[f1 + 2].ll = res.ll.lower;
1147 /* 64-bit FP multiplication RR */
1148 void HELPER(mdbr)(uint32_t f1, uint32_t f2)
1150 env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
1151 &env->fpu_status);
1154 /* 128-bit FP multiplication RR */
1155 void HELPER(mxbr)(uint32_t f1, uint32_t f2)
1157 CPU_QuadU v1;
1158 v1.ll.upper = env->fregs[f1].ll;
1159 v1.ll.lower = env->fregs[f1 + 2].ll;
1160 CPU_QuadU v2;
1161 v2.ll.upper = env->fregs[f2].ll;
1162 v2.ll.lower = env->fregs[f2 + 2].ll;
1163 CPU_QuadU res;
1164 res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
1165 env->fregs[f1].ll = res.ll.upper;
1166 env->fregs[f1 + 2].ll = res.ll.lower;
1169 /* convert 32-bit float to 64-bit float */
1170 void HELPER(ldebr)(uint32_t r1, uint32_t r2)
1172 env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper,
1173 &env->fpu_status);
1176 /* convert 128-bit float to 64-bit float */
1177 void HELPER(ldxbr)(uint32_t f1, uint32_t f2)
1179 CPU_QuadU x2;
1180 x2.ll.upper = env->fregs[f2].ll;
1181 x2.ll.lower = env->fregs[f2 + 2].ll;
1182 env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status);
1183 HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d);
1186 /* convert 64-bit float to 128-bit float */
1187 void HELPER(lxdbr)(uint32_t f1, uint32_t f2)
1189 CPU_QuadU res;
1190 res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status);
1191 env->fregs[f1].ll = res.ll.upper;
1192 env->fregs[f1 + 2].ll = res.ll.lower;
1195 /* convert 64-bit float to 32-bit float */
1196 void HELPER(ledbr)(uint32_t f1, uint32_t f2)
1198 float64 d2 = env->fregs[f2].d;
1199 env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status);
1202 /* convert 128-bit float to 32-bit float */
1203 void HELPER(lexbr)(uint32_t f1, uint32_t f2)
1205 CPU_QuadU x2;
1206 x2.ll.upper = env->fregs[f2].ll;
1207 x2.ll.lower = env->fregs[f2 + 2].ll;
1208 env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status);
1209 HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper);
1212 /* absolute value of 32-bit float */
1213 uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2)
1215 float32 v1;
1216 float32 v2 = env->fregs[f2].d;
1217 v1 = float32_abs(v2);
1218 env->fregs[f1].d = v1;
1219 return set_cc_nz_f32(v1);
1222 /* absolute value of 64-bit float */
1223 uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2)
1225 float64 v1;
1226 float64 v2 = env->fregs[f2].d;
1227 v1 = float64_abs(v2);
1228 env->fregs[f1].d = v1;
1229 return set_cc_nz_f64(v1);
1232 /* absolute value of 128-bit float */
1233 uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2)
1235 CPU_QuadU v1;
1236 CPU_QuadU v2;
1237 v2.ll.upper = env->fregs[f2].ll;
1238 v2.ll.lower = env->fregs[f2 + 2].ll;
1239 v1.q = float128_abs(v2.q);
1240 env->fregs[f1].ll = v1.ll.upper;
1241 env->fregs[f1 + 2].ll = v1.ll.lower;
1242 return set_cc_nz_f128(v1.q);
1245 /* load and test 64-bit float */
1246 uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2)
1248 env->fregs[f1].d = env->fregs[f2].d;
1249 return set_cc_nz_f64(env->fregs[f1].d);
1252 /* load and test 32-bit float */
1253 uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2)
1255 env->fregs[f1].l.upper = env->fregs[f2].l.upper;
1256 return set_cc_nz_f32(env->fregs[f1].l.upper);
1259 /* load and test 128-bit float */
1260 uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2)
1262 CPU_QuadU x;
1263 x.ll.upper = env->fregs[f2].ll;
1264 x.ll.lower = env->fregs[f2 + 2].ll;
1265 env->fregs[f1].ll = x.ll.upper;
1266 env->fregs[f1 + 2].ll = x.ll.lower;
1267 return set_cc_nz_f128(x.q);
1270 /* load complement of 32-bit float */
1271 uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2)
1273 env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
1275 return set_cc_nz_f32(env->fregs[f1].l.upper);
1278 /* load complement of 64-bit float */
1279 uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2)
1281 env->fregs[f1].d = float64_chs(env->fregs[f2].d);
1283 return set_cc_nz_f64(env->fregs[f1].d);
1286 /* load complement of 128-bit float */
1287 uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2)
1289 CPU_QuadU x1, x2;
1290 x2.ll.upper = env->fregs[f2].ll;
1291 x2.ll.lower = env->fregs[f2 + 2].ll;
1292 x1.q = float128_chs(x2.q);
1293 env->fregs[f1].ll = x1.ll.upper;
1294 env->fregs[f1 + 2].ll = x1.ll.lower;
1295 return set_cc_nz_f128(x1.q);
1298 /* 32-bit FP addition RM */
1299 void HELPER(aeb)(uint32_t f1, uint32_t val)
1301 float32 v1 = env->fregs[f1].l.upper;
1302 CPU_FloatU v2;
1303 v2.l = val;
1304 HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__,
1305 v1, f1, v2.f);
1306 env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status);
1309 /* 32-bit FP division RM */
1310 void HELPER(deb)(uint32_t f1, uint32_t val)
1312 float32 v1 = env->fregs[f1].l.upper;
1313 CPU_FloatU v2;
1314 v2.l = val;
1315 HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__,
1316 v1, f1, v2.f);
1317 env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status);
1320 /* 32-bit FP multiplication RM */
1321 void HELPER(meeb)(uint32_t f1, uint32_t val)
1323 float32 v1 = env->fregs[f1].l.upper;
1324 CPU_FloatU v2;
1325 v2.l = val;
1326 HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__,
1327 v1, f1, v2.f);
1328 env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
1331 /* 32-bit FP compare RR */
1332 uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2)
1334 float32 v1 = env->fregs[f1].l.upper;
1335 float32 v2 = env->fregs[f2].l.upper;;
1336 HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__,
1337 v1, f1, v2);
1338 return set_cc_f32(v1, v2);
1341 /* 64-bit FP compare RR */
1342 uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2)
1344 float64 v1 = env->fregs[f1].d;
1345 float64 v2 = env->fregs[f2].d;;
1346 HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__,
1347 v1, f1, v2);
1348 return set_cc_f64(v1, v2);
1351 /* 128-bit FP compare RR */
1352 uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2)
1354 CPU_QuadU v1;
1355 v1.ll.upper = env->fregs[f1].ll;
1356 v1.ll.lower = env->fregs[f1 + 2].ll;
1357 CPU_QuadU v2;
1358 v2.ll.upper = env->fregs[f2].ll;
1359 v2.ll.lower = env->fregs[f2 + 2].ll;
1361 return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q,
1362 &env->fpu_status));
1365 /* 64-bit FP compare RM */
1366 uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2)
1368 float64 v1 = env->fregs[f1].d;
1369 CPU_DoubleU v2;
1370 v2.ll = ldq(a2);
1371 HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1,
1372 f1, v2.d);
1373 return set_cc_f64(v1, v2.d);
1376 /* 64-bit FP addition RM */
1377 uint32_t HELPER(adb)(uint32_t f1, uint64_t a2)
1379 float64 v1 = env->fregs[f1].d;
1380 CPU_DoubleU v2;
1381 v2.ll = ldq(a2);
1382 HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__,
1383 v1, f1, v2.d);
1384 env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status);
1385 return set_cc_nz_f64(v1);
1388 /* 32-bit FP subtraction RM */
1389 void HELPER(seb)(uint32_t f1, uint32_t val)
1391 float32 v1 = env->fregs[f1].l.upper;
1392 CPU_FloatU v2;
1393 v2.l = val;
1394 env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status);
1397 /* 64-bit FP subtraction RM */
1398 uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2)
1400 float64 v1 = env->fregs[f1].d;
1401 CPU_DoubleU v2;
1402 v2.ll = ldq(a2);
1403 env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status);
1404 return set_cc_nz_f64(v1);
1407 /* 64-bit FP multiplication RM */
1408 void HELPER(mdb)(uint32_t f1, uint64_t a2)
1410 float64 v1 = env->fregs[f1].d;
1411 CPU_DoubleU v2;
1412 v2.ll = ldq(a2);
1413 HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__,
1414 v1, f1, v2.d);
1415 env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
1418 /* 64-bit FP division RM */
1419 void HELPER(ddb)(uint32_t f1, uint64_t a2)
1421 float64 v1 = env->fregs[f1].d;
1422 CPU_DoubleU v2;
1423 v2.ll = ldq(a2);
1424 HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__,
1425 v1, f1, v2.d);
1426 env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status);
1429 static void set_round_mode(int m3)
1431 switch (m3) {
1432 case 0:
1433 /* current mode */
1434 break;
1435 case 1:
1436 /* biased round no nearest */
1437 case 4:
1438 /* round to nearest */
1439 set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
1440 break;
1441 case 5:
1442 /* round to zero */
1443 set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
1444 break;
1445 case 6:
1446 /* round to +inf */
1447 set_float_rounding_mode(float_round_up, &env->fpu_status);
1448 break;
1449 case 7:
1450 /* round to -inf */
1451 set_float_rounding_mode(float_round_down, &env->fpu_status);
1452 break;
1456 /* convert 32-bit float to 64-bit int */
1457 uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3)
1459 float32 v2 = env->fregs[f2].l.upper;
1460 set_round_mode(m3);
1461 env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
1462 return set_cc_nz_f32(v2);
1465 /* convert 64-bit float to 64-bit int */
1466 uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1468 float64 v2 = env->fregs[f2].d;
1469 set_round_mode(m3);
1470 env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
1471 return set_cc_nz_f64(v2);
1474 /* convert 128-bit float to 64-bit int */
1475 uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1477 CPU_QuadU v2;
1478 v2.ll.upper = env->fregs[f2].ll;
1479 v2.ll.lower = env->fregs[f2 + 2].ll;
1480 set_round_mode(m3);
1481 env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
1482 if (float128_is_any_nan(v2.q)) {
1483 return 3;
1484 } else if (float128_is_zero(v2.q)) {
1485 return 0;
1486 } else if (float128_is_neg(v2.q)) {
1487 return 1;
1488 } else {
1489 return 2;
1493 /* convert 32-bit float to 32-bit int */
1494 uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3)
1496 float32 v2 = env->fregs[f2].l.upper;
1497 set_round_mode(m3);
1498 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1499 float32_to_int32(v2, &env->fpu_status);
1500 return set_cc_nz_f32(v2);
1503 /* convert 64-bit float to 32-bit int */
1504 uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1506 float64 v2 = env->fregs[f2].d;
1507 set_round_mode(m3);
1508 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1509 float64_to_int32(v2, &env->fpu_status);
1510 return set_cc_nz_f64(v2);
1513 /* convert 128-bit float to 32-bit int */
1514 uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3)
1516 CPU_QuadU v2;
1517 v2.ll.upper = env->fregs[f2].ll;
1518 v2.ll.lower = env->fregs[f2 + 2].ll;
1519 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1520 float128_to_int32(v2.q, &env->fpu_status);
1521 return set_cc_nz_f128(v2.q);
1524 /* load 32-bit FP zero */
1525 void HELPER(lzer)(uint32_t f1)
1527 env->fregs[f1].l.upper = float32_zero;
1530 /* load 64-bit FP zero */
1531 void HELPER(lzdr)(uint32_t f1)
1533 env->fregs[f1].d = float64_zero;
1536 /* load 128-bit FP zero */
1537 void HELPER(lzxr)(uint32_t f1)
1539 CPU_QuadU x;
1540 x.q = float64_to_float128(float64_zero, &env->fpu_status);
1541 env->fregs[f1].ll = x.ll.upper;
1542 env->fregs[f1 + 1].ll = x.ll.lower;
1545 /* 128-bit FP subtraction RR */
1546 uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2)
1548 CPU_QuadU v1;
1549 v1.ll.upper = env->fregs[f1].ll;
1550 v1.ll.lower = env->fregs[f1 + 2].ll;
1551 CPU_QuadU v2;
1552 v2.ll.upper = env->fregs[f2].ll;
1553 v2.ll.lower = env->fregs[f2 + 2].ll;
1554 CPU_QuadU res;
1555 res.q = float128_sub(v1.q, v2.q, &env->fpu_status);
1556 env->fregs[f1].ll = res.ll.upper;
1557 env->fregs[f1 + 2].ll = res.ll.lower;
1558 return set_cc_nz_f128(res.q);
1561 /* 128-bit FP addition RR */
1562 uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2)
1564 CPU_QuadU v1;
1565 v1.ll.upper = env->fregs[f1].ll;
1566 v1.ll.lower = env->fregs[f1 + 2].ll;
1567 CPU_QuadU v2;
1568 v2.ll.upper = env->fregs[f2].ll;
1569 v2.ll.lower = env->fregs[f2 + 2].ll;
1570 CPU_QuadU res;
1571 res.q = float128_add(v1.q, v2.q, &env->fpu_status);
1572 env->fregs[f1].ll = res.ll.upper;
1573 env->fregs[f1 + 2].ll = res.ll.lower;
1574 return set_cc_nz_f128(res.q);
1577 /* 32-bit FP multiplication RR */
1578 void HELPER(meebr)(uint32_t f1, uint32_t f2)
1580 env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
1581 env->fregs[f2].l.upper,
1582 &env->fpu_status);
1585 /* 64-bit FP division RR */
1586 void HELPER(ddbr)(uint32_t f1, uint32_t f2)
1588 env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d,
1589 &env->fpu_status);
1592 /* 64-bit FP multiply and add RM */
1593 void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3)
1595 HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3);
1596 CPU_DoubleU v2;
1597 v2.ll = ldq(a2);
1598 env->fregs[f1].d = float64_add(env->fregs[f1].d,
1599 float64_mul(v2.d, env->fregs[f3].d,
1600 &env->fpu_status),
1601 &env->fpu_status);
1604 /* 64-bit FP multiply and add RR */
1605 void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2)
1607 HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
1608 env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
1609 env->fregs[f3].d,
1610 &env->fpu_status),
1611 env->fregs[f1].d, &env->fpu_status);
1614 /* 64-bit FP multiply and subtract RR */
1615 void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2)
1617 HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3);
1618 env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
1619 env->fregs[f3].d,
1620 &env->fpu_status),
1621 env->fregs[f1].d, &env->fpu_status);
1624 /* 32-bit FP multiply and add RR */
1625 void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2)
1627 env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
1628 float32_mul(env->fregs[f2].l.upper,
1629 env->fregs[f3].l.upper,
1630 &env->fpu_status),
1631 &env->fpu_status);
1634 /* convert 64-bit float to 128-bit float */
1635 void HELPER(lxdb)(uint32_t f1, uint64_t a2)
1637 CPU_DoubleU v2;
1638 v2.ll = ldq(a2);
1639 CPU_QuadU v1;
1640 v1.q = float64_to_float128(v2.d, &env->fpu_status);
1641 env->fregs[f1].ll = v1.ll.upper;
1642 env->fregs[f1 + 2].ll = v1.ll.lower;
1645 /* test data class 32-bit */
1646 uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2)
1648 float32 v1 = env->fregs[f1].l.upper;
1649 int neg = float32_is_neg(v1);
1650 uint32_t cc = 0;
1652 HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg);
1653 if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
1654 (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
1655 (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
1656 (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
1657 cc = 1;
1658 } else if (m2 & (1 << (9-neg))) {
1659 /* assume normalized number */
1660 cc = 1;
1663 /* FIXME: denormalized? */
1664 return cc;
1667 /* test data class 64-bit */
1668 uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2)
1670 float64 v1 = env->fregs[f1].d;
1671 int neg = float64_is_neg(v1);
1672 uint32_t cc = 0;
1674 HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg);
1675 if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
1676 (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
1677 (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
1678 (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
1679 cc = 1;
1680 } else if (m2 & (1 << (9-neg))) {
1681 /* assume normalized number */
1682 cc = 1;
1684 /* FIXME: denormalized? */
1685 return cc;
1688 /* test data class 128-bit */
1689 uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2)
1691 CPU_QuadU v1;
1692 uint32_t cc = 0;
1693 v1.ll.upper = env->fregs[f1].ll;
1694 v1.ll.lower = env->fregs[f1 + 2].ll;
1696 int neg = float128_is_neg(v1.q);
1697 if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
1698 (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
1699 (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
1700 (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
1701 cc = 1;
1702 } else if (m2 & (1 << (9-neg))) {
1703 /* assume normalized number */
1704 cc = 1;
1706 /* FIXME: denormalized? */
1707 return cc;
1710 /* find leftmost one */
1711 uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2)
1713 uint64_t res = 0;
1714 uint64_t ov2 = v2;
1716 while (!(v2 & 0x8000000000000000ULL) && v2) {
1717 v2 <<= 1;
1718 res++;
1721 if (!v2) {
1722 env->regs[r1] = 64;
1723 env->regs[r1 + 1] = 0;
1724 return 0;
1725 } else {
1726 env->regs[r1] = res;
1727 env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res);
1728 return 2;
1732 /* square root 64-bit RR */
1733 void HELPER(sqdbr)(uint32_t f1, uint32_t f2)
1735 env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
1738 /* checksum */
1739 void HELPER(cksm)(uint32_t r1, uint32_t r2)
1741 uint64_t src = get_address_31fix(r2);
1742 uint64_t src_len = env->regs[(r2 + 1) & 15];
1743 uint64_t cksm = (uint32_t)env->regs[r1];
1745 while (src_len >= 4) {
1746 cksm += ldl(src);
1748 /* move to next word */
1749 src_len -= 4;
1750 src += 4;
1753 switch (src_len) {
1754 case 0:
1755 break;
1756 case 1:
1757 cksm += ldub(src) << 24;
1758 break;
1759 case 2:
1760 cksm += lduw(src) << 16;
1761 break;
1762 case 3:
1763 cksm += lduw(src) << 16;
1764 cksm += ldub(src + 2) << 8;
1765 break;
1768 /* indicate we've processed everything */
1769 env->regs[r2] = src + src_len;
1770 env->regs[(r2 + 1) & 15] = 0;
1772 /* store result */
1773 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1774 ((uint32_t)cksm + (cksm >> 32));
1777 static inline uint32_t cc_calc_ltgt_32(CPUState *env, int32_t src,
1778 int32_t dst)
1780 if (src == dst) {
1781 return 0;
1782 } else if (src < dst) {
1783 return 1;
1784 } else {
1785 return 2;
1789 static inline uint32_t cc_calc_ltgt0_32(CPUState *env, int32_t dst)
1791 return cc_calc_ltgt_32(env, dst, 0);
1794 static inline uint32_t cc_calc_ltgt_64(CPUState *env, int64_t src,
1795 int64_t dst)
1797 if (src == dst) {
1798 return 0;
1799 } else if (src < dst) {
1800 return 1;
1801 } else {
1802 return 2;
1806 static inline uint32_t cc_calc_ltgt0_64(CPUState *env, int64_t dst)
1808 return cc_calc_ltgt_64(env, dst, 0);
1811 static inline uint32_t cc_calc_ltugtu_32(CPUState *env, uint32_t src,
1812 uint32_t dst)
1814 if (src == dst) {
1815 return 0;
1816 } else if (src < dst) {
1817 return 1;
1818 } else {
1819 return 2;
1823 static inline uint32_t cc_calc_ltugtu_64(CPUState *env, uint64_t src,
1824 uint64_t dst)
1826 if (src == dst) {
1827 return 0;
1828 } else if (src < dst) {
1829 return 1;
1830 } else {
1831 return 2;
1835 static inline uint32_t cc_calc_tm_32(CPUState *env, uint32_t val, uint32_t mask)
1837 HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask);
1838 uint16_t r = val & mask;
1839 if (r == 0 || mask == 0) {
1840 return 0;
1841 } else if (r == mask) {
1842 return 3;
1843 } else {
1844 return 1;
1848 /* set condition code for test under mask */
1849 static inline uint32_t cc_calc_tm_64(CPUState *env, uint64_t val, uint32_t mask)
1851 uint16_t r = val & mask;
1852 HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r);
1853 if (r == 0 || mask == 0) {
1854 return 0;
1855 } else if (r == mask) {
1856 return 3;
1857 } else {
1858 while (!(mask & 0x8000)) {
1859 mask <<= 1;
1860 val <<= 1;
1862 if (val & 0x8000) {
1863 return 2;
1864 } else {
1865 return 1;
1870 static inline uint32_t cc_calc_nz(CPUState *env, uint64_t dst)
1872 return !!dst;
1875 static inline uint32_t cc_calc_add_64(CPUState *env, int64_t a1, int64_t a2,
1876 int64_t ar)
1878 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
1879 return 3; /* overflow */
1880 } else {
1881 if (ar < 0) {
1882 return 1;
1883 } else if (ar > 0) {
1884 return 2;
1885 } else {
1886 return 0;
1891 static inline uint32_t cc_calc_addu_64(CPUState *env, uint64_t a1, uint64_t a2,
1892 uint64_t ar)
1894 if (ar == 0) {
1895 if (a1) {
1896 return 2;
1897 } else {
1898 return 0;
1900 } else {
1901 if (ar < a1 || ar < a2) {
1902 return 3;
1903 } else {
1904 return 1;
1909 static inline uint32_t cc_calc_sub_64(CPUState *env, int64_t a1, int64_t a2,
1910 int64_t ar)
1912 if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
1913 return 3; /* overflow */
1914 } else {
1915 if (ar < 0) {
1916 return 1;
1917 } else if (ar > 0) {
1918 return 2;
1919 } else {
1920 return 0;
1925 static inline uint32_t cc_calc_subu_64(CPUState *env, uint64_t a1, uint64_t a2,
1926 uint64_t ar)
1928 if (ar == 0) {
1929 return 2;
1930 } else {
1931 if (a2 > a1) {
1932 return 1;
1933 } else {
1934 return 3;
1939 static inline uint32_t cc_calc_abs_64(CPUState *env, int64_t dst)
1941 if ((uint64_t)dst == 0x8000000000000000ULL) {
1942 return 3;
1943 } else if (dst) {
1944 return 1;
1945 } else {
1946 return 0;
1950 static inline uint32_t cc_calc_nabs_64(CPUState *env, int64_t dst)
1952 return !!dst;
1955 static inline uint32_t cc_calc_comp_64(CPUState *env, int64_t dst)
1957 if ((uint64_t)dst == 0x8000000000000000ULL) {
1958 return 3;
1959 } else if (dst < 0) {
1960 return 1;
1961 } else if (dst > 0) {
1962 return 2;
1963 } else {
1964 return 0;
1969 static inline uint32_t cc_calc_add_32(CPUState *env, int32_t a1, int32_t a2,
1970 int32_t ar)
1972 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
1973 return 3; /* overflow */
1974 } else {
1975 if (ar < 0) {
1976 return 1;
1977 } else if (ar > 0) {
1978 return 2;
1979 } else {
1980 return 0;
1985 static inline uint32_t cc_calc_addu_32(CPUState *env, uint32_t a1, uint32_t a2,
1986 uint32_t ar)
1988 if (ar == 0) {
1989 if (a1) {
1990 return 2;
1991 } else {
1992 return 0;
1994 } else {
1995 if (ar < a1 || ar < a2) {
1996 return 3;
1997 } else {
1998 return 1;
2003 static inline uint32_t cc_calc_sub_32(CPUState *env, int32_t a1, int32_t a2,
2004 int32_t ar)
2006 if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
2007 return 3; /* overflow */
2008 } else {
2009 if (ar < 0) {
2010 return 1;
2011 } else if (ar > 0) {
2012 return 2;
2013 } else {
2014 return 0;
2019 static inline uint32_t cc_calc_subu_32(CPUState *env, uint32_t a1, uint32_t a2,
2020 uint32_t ar)
2022 if (ar == 0) {
2023 return 2;
2024 } else {
2025 if (a2 > a1) {
2026 return 1;
2027 } else {
2028 return 3;
2033 static inline uint32_t cc_calc_abs_32(CPUState *env, int32_t dst)
2035 if ((uint32_t)dst == 0x80000000UL) {
2036 return 3;
2037 } else if (dst) {
2038 return 1;
2039 } else {
2040 return 0;
2044 static inline uint32_t cc_calc_nabs_32(CPUState *env, int32_t dst)
2046 return !!dst;
2049 static inline uint32_t cc_calc_comp_32(CPUState *env, int32_t dst)
2051 if ((uint32_t)dst == 0x80000000UL) {
2052 return 3;
2053 } else if (dst < 0) {
2054 return 1;
2055 } else if (dst > 0) {
2056 return 2;
2057 } else {
2058 return 0;
2062 /* calculate condition code for insert character under mask insn */
2063 static inline uint32_t cc_calc_icm_32(CPUState *env, uint32_t mask, uint32_t val)
2065 HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val);
2066 uint32_t cc;
2068 if (mask == 0xf) {
2069 if (!val) {
2070 return 0;
2071 } else if (val & 0x80000000) {
2072 return 1;
2073 } else {
2074 return 2;
2078 if (!val || !mask) {
2079 cc = 0;
2080 } else {
2081 while (mask != 1) {
2082 mask >>= 1;
2083 val >>= 8;
2085 if (val & 0x80) {
2086 cc = 1;
2087 } else {
2088 cc = 2;
2091 return cc;
2094 static inline uint32_t cc_calc_slag(CPUState *env, uint64_t src, uint64_t shift)
2096 uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
2097 uint64_t match, r;
2099 /* check if the sign bit stays the same */
2100 if (src & (1ULL << 63)) {
2101 match = mask;
2102 } else {
2103 match = 0;
2106 if ((src & mask) != match) {
2107 /* overflow */
2108 return 3;
2111 r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
2113 if ((int64_t)r == 0) {
2114 return 0;
2115 } else if ((int64_t)r < 0) {
2116 return 1;
2119 return 2;
2123 static inline uint32_t do_calc_cc(CPUState *env, uint32_t cc_op, uint64_t src,
2124 uint64_t dst, uint64_t vr)
2126 uint32_t r = 0;
2128 switch (cc_op) {
2129 case CC_OP_CONST0:
2130 case CC_OP_CONST1:
2131 case CC_OP_CONST2:
2132 case CC_OP_CONST3:
2133 /* cc_op value _is_ cc */
2134 r = cc_op;
2135 break;
2136 case CC_OP_LTGT0_32:
2137 r = cc_calc_ltgt0_32(env, dst);
2138 break;
2139 case CC_OP_LTGT0_64:
2140 r = cc_calc_ltgt0_64(env, dst);
2141 break;
2142 case CC_OP_LTGT_32:
2143 r = cc_calc_ltgt_32(env, src, dst);
2144 break;
2145 case CC_OP_LTGT_64:
2146 r = cc_calc_ltgt_64(env, src, dst);
2147 break;
2148 case CC_OP_LTUGTU_32:
2149 r = cc_calc_ltugtu_32(env, src, dst);
2150 break;
2151 case CC_OP_LTUGTU_64:
2152 r = cc_calc_ltugtu_64(env, src, dst);
2153 break;
2154 case CC_OP_TM_32:
2155 r = cc_calc_tm_32(env, src, dst);
2156 break;
2157 case CC_OP_TM_64:
2158 r = cc_calc_tm_64(env, src, dst);
2159 break;
2160 case CC_OP_NZ:
2161 r = cc_calc_nz(env, dst);
2162 break;
2163 case CC_OP_ADD_64:
2164 r = cc_calc_add_64(env, src, dst, vr);
2165 break;
2166 case CC_OP_ADDU_64:
2167 r = cc_calc_addu_64(env, src, dst, vr);
2168 break;
2169 case CC_OP_SUB_64:
2170 r = cc_calc_sub_64(env, src, dst, vr);
2171 break;
2172 case CC_OP_SUBU_64:
2173 r = cc_calc_subu_64(env, src, dst, vr);
2174 break;
2175 case CC_OP_ABS_64:
2176 r = cc_calc_abs_64(env, dst);
2177 break;
2178 case CC_OP_NABS_64:
2179 r = cc_calc_nabs_64(env, dst);
2180 break;
2181 case CC_OP_COMP_64:
2182 r = cc_calc_comp_64(env, dst);
2183 break;
2185 case CC_OP_ADD_32:
2186 r = cc_calc_add_32(env, src, dst, vr);
2187 break;
2188 case CC_OP_ADDU_32:
2189 r = cc_calc_addu_32(env, src, dst, vr);
2190 break;
2191 case CC_OP_SUB_32:
2192 r = cc_calc_sub_32(env, src, dst, vr);
2193 break;
2194 case CC_OP_SUBU_32:
2195 r = cc_calc_subu_32(env, src, dst, vr);
2196 break;
2197 case CC_OP_ABS_32:
2198 r = cc_calc_abs_64(env, dst);
2199 break;
2200 case CC_OP_NABS_32:
2201 r = cc_calc_nabs_64(env, dst);
2202 break;
2203 case CC_OP_COMP_32:
2204 r = cc_calc_comp_32(env, dst);
2205 break;
2207 case CC_OP_ICM:
2208 r = cc_calc_icm_32(env, src, dst);
2209 break;
2210 case CC_OP_SLAG:
2211 r = cc_calc_slag(env, src, dst);
2212 break;
2214 case CC_OP_LTGT_F32:
2215 r = set_cc_f32(src, dst);
2216 break;
2217 case CC_OP_LTGT_F64:
2218 r = set_cc_f64(src, dst);
2219 break;
2220 case CC_OP_NZ_F32:
2221 r = set_cc_nz_f32(dst);
2222 break;
2223 case CC_OP_NZ_F64:
2224 r = set_cc_nz_f64(dst);
2225 break;
2227 default:
2228 cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
2231 HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__,
2232 cc_name(cc_op), src, dst, vr, r);
2233 return r;
2236 uint32_t calc_cc(CPUState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
2237 uint64_t vr)
2239 return do_calc_cc(env, cc_op, src, dst, vr);
2242 uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst,
2243 uint64_t vr)
2245 return do_calc_cc(env, cc_op, src, dst, vr);
2248 uint64_t HELPER(cvd)(int32_t bin)
2250 /* positive 0 */
2251 uint64_t dec = 0x0c;
2252 int shift = 4;
2254 if (bin < 0) {
2255 bin = -bin;
2256 dec = 0x0d;
2259 for (shift = 4; (shift < 64) && bin; shift += 4) {
2260 int current_number = bin % 10;
2262 dec |= (current_number) << shift;
2263 bin /= 10;
2266 return dec;
2269 void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src)
2271 int len_dest = len >> 4;
2272 int len_src = len & 0xf;
2273 uint8_t b;
2274 int second_nibble = 0;
2276 dest += len_dest;
2277 src += len_src;
2279 /* last byte is special, it only flips the nibbles */
2280 b = ldub(src);
2281 stb(dest, (b << 4) | (b >> 4));
2282 src--;
2283 len_src--;
2285 /* now pad every nibble with 0xf0 */
2287 while (len_dest > 0) {
2288 uint8_t cur_byte = 0;
2290 if (len_src > 0) {
2291 cur_byte = ldub(src);
2294 len_dest--;
2295 dest--;
2297 /* only advance one nibble at a time */
2298 if (second_nibble) {
2299 cur_byte >>= 4;
2300 len_src--;
2301 src--;
2303 second_nibble = !second_nibble;
2305 /* digit */
2306 cur_byte = (cur_byte & 0xf);
2307 /* zone bits */
2308 cur_byte |= 0xf0;
2310 stb(dest, cur_byte);
2314 void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans)
2316 int i;
2318 for (i = 0; i <= len; i++) {
2319 uint8_t byte = ldub(array + i);
2320 uint8_t new_byte = ldub(trans + byte);
2321 stb(array + i, new_byte);
2325 #ifndef CONFIG_USER_ONLY
2327 void HELPER(load_psw)(uint64_t mask, uint64_t addr)
2329 load_psw(env, mask, addr);
2330 cpu_loop_exit(env);
2333 static void program_interrupt(CPUState *env, uint32_t code, int ilc)
2335 qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
2337 if (kvm_enabled()) {
2338 #ifdef CONFIG_KVM
2339 kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
2340 #endif
2341 } else {
2342 env->int_pgm_code = code;
2343 env->int_pgm_ilc = ilc;
2344 env->exception_index = EXCP_PGM;
2345 cpu_loop_exit(env);
2349 static void ext_interrupt(CPUState *env, int type, uint32_t param,
2350 uint64_t param64)
2352 cpu_inject_ext(env, type, param, param64);
2355 int sclp_service_call(CPUState *env, uint32_t sccb, uint64_t code)
2357 int r = 0;
2358 int shift = 0;
2360 #ifdef DEBUG_HELPER
2361 printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
2362 #endif
2364 if (sccb & ~0x7ffffff8ul) {
2365 fprintf(stderr, "KVM: invalid sccb address 0x%x\n", sccb);
2366 r = -1;
2367 goto out;
2370 switch(code) {
2371 case SCLP_CMDW_READ_SCP_INFO:
2372 case SCLP_CMDW_READ_SCP_INFO_FORCED:
2373 while ((ram_size >> (20 + shift)) > 65535) {
2374 shift++;
2376 stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
2377 stb_phys(sccb + SCP_INCREMENT, 1 << shift);
2378 stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
2380 if (kvm_enabled()) {
2381 #ifdef CONFIG_KVM
2382 kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
2383 sccb & ~3, 0, 1);
2384 #endif
2385 } else {
2386 env->psw.addr += 4;
2387 ext_interrupt(env, EXT_SERVICE, sccb & ~3, 0);
2389 break;
2390 default:
2391 #ifdef DEBUG_HELPER
2392 printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
2393 #endif
2394 r = -1;
2395 break;
2398 out:
2399 return r;
2402 /* SCLP service call */
2403 uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
2405 if (sclp_service_call(env, r1, r2)) {
2406 return 3;
2409 return 0;
2412 /* DIAG */
2413 uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code)
2415 uint64_t r;
2417 switch (num) {
2418 case 0x500:
2419 /* KVM hypercall */
2420 r = s390_virtio_hypercall(env, mem, code);
2421 break;
2422 case 0x44:
2423 /* yield */
2424 r = 0;
2425 break;
2426 case 0x308:
2427 /* ipl */
2428 r = 0;
2429 break;
2430 default:
2431 r = -1;
2432 break;
2435 if (r) {
2436 program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
2439 return r;
2442 /* Store CPU ID */
2443 void HELPER(stidp)(uint64_t a1)
2445 stq(a1, env->cpu_num);
2448 /* Set Prefix */
2449 void HELPER(spx)(uint64_t a1)
2451 uint32_t prefix;
2453 prefix = ldl(a1);
2454 env->psa = prefix & 0xfffff000;
2455 qemu_log("prefix: %#x\n", prefix);
2456 tlb_flush_page(env, 0);
2457 tlb_flush_page(env, TARGET_PAGE_SIZE);
2460 /* Set Clock */
2461 uint32_t HELPER(sck)(uint64_t a1)
2463 /* XXX not implemented - is it necessary? */
2465 return 0;
2468 static inline uint64_t clock_value(CPUState *env)
2470 uint64_t time;
2472 time = env->tod_offset +
2473 time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
2475 return time;
2478 /* Store Clock */
2479 uint32_t HELPER(stck)(uint64_t a1)
2481 stq(a1, clock_value(env));
2483 return 0;
2486 /* Store Clock Extended */
2487 uint32_t HELPER(stcke)(uint64_t a1)
2489 stb(a1, 0);
2490 /* basically the same value as stck */
2491 stq(a1 + 1, clock_value(env) | env->cpu_num);
2492 /* more fine grained than stck */
2493 stq(a1 + 9, 0);
2494 /* XXX programmable fields */
2495 stw(a1 + 17, 0);
2498 return 0;
2501 /* Set Clock Comparator */
2502 void HELPER(sckc)(uint64_t a1)
2504 uint64_t time = ldq(a1);
2506 if (time == -1ULL) {
2507 return;
2510 /* difference between now and then */
2511 time -= clock_value(env);
2512 /* nanoseconds */
2513 time = (time * 125) >> 9;
2515 qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
2518 /* Store Clock Comparator */
2519 void HELPER(stckc)(uint64_t a1)
2521 /* XXX implement */
2522 stq(a1, 0);
2525 /* Set CPU Timer */
2526 void HELPER(spt)(uint64_t a1)
2528 uint64_t time = ldq(a1);
2530 if (time == -1ULL) {
2531 return;
2534 /* nanoseconds */
2535 time = (time * 125) >> 9;
2537 qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
2540 /* Store CPU Timer */
2541 void HELPER(stpt)(uint64_t a1)
2543 /* XXX implement */
2544 stq(a1, 0);
2547 /* Store System Information */
2548 uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1)
2550 int cc = 0;
2551 int sel1, sel2;
2553 if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
2554 ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
2555 /* valid function code, invalid reserved bits */
2556 program_interrupt(env, PGM_SPECIFICATION, 2);
2559 sel1 = r0 & STSI_R0_SEL1_MASK;
2560 sel2 = r1 & STSI_R1_SEL2_MASK;
2562 /* XXX: spec exception if sysib is not 4k-aligned */
2564 switch (r0 & STSI_LEVEL_MASK) {
2565 case STSI_LEVEL_1:
2566 if ((sel1 == 1) && (sel2 == 1)) {
2567 /* Basic Machine Configuration */
2568 struct sysib_111 sysib;
2570 memset(&sysib, 0, sizeof(sysib));
2571 ebcdic_put(sysib.manuf, "QEMU ", 16);
2572 /* same as machine type number in STORE CPU ID */
2573 ebcdic_put(sysib.type, "QEMU", 4);
2574 /* same as model number in STORE CPU ID */
2575 ebcdic_put(sysib.model, "QEMU ", 16);
2576 ebcdic_put(sysib.sequence, "QEMU ", 16);
2577 ebcdic_put(sysib.plant, "QEMU", 4);
2578 cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2579 } else if ((sel1 == 2) && (sel2 == 1)) {
2580 /* Basic Machine CPU */
2581 struct sysib_121 sysib;
2583 memset(&sysib, 0, sizeof(sysib));
2584 /* XXX make different for different CPUs? */
2585 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
2586 ebcdic_put(sysib.plant, "QEMU", 4);
2587 stw_p(&sysib.cpu_addr, env->cpu_num);
2588 cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2589 } else if ((sel1 == 2) && (sel2 == 2)) {
2590 /* Basic Machine CPUs */
2591 struct sysib_122 sysib;
2593 memset(&sysib, 0, sizeof(sysib));
2594 stl_p(&sysib.capability, 0x443afc29);
2595 /* XXX change when SMP comes */
2596 stw_p(&sysib.total_cpus, 1);
2597 stw_p(&sysib.active_cpus, 1);
2598 stw_p(&sysib.standby_cpus, 0);
2599 stw_p(&sysib.reserved_cpus, 0);
2600 cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2601 } else {
2602 cc = 3;
2604 break;
2605 case STSI_LEVEL_2:
2607 if ((sel1 == 2) && (sel2 == 1)) {
2608 /* LPAR CPU */
2609 struct sysib_221 sysib;
2611 memset(&sysib, 0, sizeof(sysib));
2612 /* XXX make different for different CPUs? */
2613 ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
2614 ebcdic_put(sysib.plant, "QEMU", 4);
2615 stw_p(&sysib.cpu_addr, env->cpu_num);
2616 stw_p(&sysib.cpu_id, 0);
2617 cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2618 } else if ((sel1 == 2) && (sel2 == 2)) {
2619 /* LPAR CPUs */
2620 struct sysib_222 sysib;
2622 memset(&sysib, 0, sizeof(sysib));
2623 stw_p(&sysib.lpar_num, 0);
2624 sysib.lcpuc = 0;
2625 /* XXX change when SMP comes */
2626 stw_p(&sysib.total_cpus, 1);
2627 stw_p(&sysib.conf_cpus, 1);
2628 stw_p(&sysib.standby_cpus, 0);
2629 stw_p(&sysib.reserved_cpus, 0);
2630 ebcdic_put(sysib.name, "QEMU ", 8);
2631 stl_p(&sysib.caf, 1000);
2632 stw_p(&sysib.dedicated_cpus, 0);
2633 stw_p(&sysib.shared_cpus, 0);
2634 cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2635 } else {
2636 cc = 3;
2638 break;
2640 case STSI_LEVEL_3:
2642 if ((sel1 == 2) && (sel2 == 2)) {
2643 /* VM CPUs */
2644 struct sysib_322 sysib;
2646 memset(&sysib, 0, sizeof(sysib));
2647 sysib.count = 1;
2648 /* XXX change when SMP comes */
2649 stw_p(&sysib.vm[0].total_cpus, 1);
2650 stw_p(&sysib.vm[0].conf_cpus, 1);
2651 stw_p(&sysib.vm[0].standby_cpus, 0);
2652 stw_p(&sysib.vm[0].reserved_cpus, 0);
2653 ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
2654 stl_p(&sysib.vm[0].caf, 1000);
2655 ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16);
2656 cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1);
2657 } else {
2658 cc = 3;
2660 break;
2662 case STSI_LEVEL_CURRENT:
2663 env->regs[0] = STSI_LEVEL_3;
2664 break;
2665 default:
2666 cc = 3;
2667 break;
2670 return cc;
2673 void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3)
2675 int i;
2676 uint64_t src = a2;
2678 for (i = r1;; i = (i + 1) % 16) {
2679 env->cregs[i] = ldq(src);
2680 HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
2681 i, src, env->cregs[i]);
2682 src += sizeof(uint64_t);
2684 if (i == r3) {
2685 break;
2689 tlb_flush(env, 1);
2692 void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3)
2694 int i;
2695 uint64_t src = a2;
2697 for (i = r1;; i = (i + 1) % 16) {
2698 env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src);
2699 src += sizeof(uint32_t);
2701 if (i == r3) {
2702 break;
2706 tlb_flush(env, 1);
2709 void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3)
2711 int i;
2712 uint64_t dest = a2;
2714 for (i = r1;; i = (i + 1) % 16) {
2715 stq(dest, env->cregs[i]);
2716 dest += sizeof(uint64_t);
2718 if (i == r3) {
2719 break;
2724 void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3)
2726 int i;
2727 uint64_t dest = a2;
2729 for (i = r1;; i = (i + 1) % 16) {
2730 stl(dest, env->cregs[i]);
2731 dest += sizeof(uint32_t);
2733 if (i == r3) {
2734 break;
2739 uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
2741 /* XXX implement */
2743 return 0;
2746 /* insert storage key extended */
2747 uint64_t HELPER(iske)(uint64_t r2)
2749 uint64_t addr = get_address(0, 0, r2);
2751 if (addr > ram_size) {
2752 return 0;
2755 /* XXX maybe use qemu's internal keys? */
2756 return env->storage_keys[addr / TARGET_PAGE_SIZE];
2759 /* set storage key extended */
2760 void HELPER(sske)(uint32_t r1, uint64_t r2)
2762 uint64_t addr = get_address(0, 0, r2);
2764 if (addr > ram_size) {
2765 return;
2768 env->storage_keys[addr / TARGET_PAGE_SIZE] = r1;
2771 /* reset reference bit extended */
2772 uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
2774 if (r2 > ram_size) {
2775 return 0;
2778 /* XXX implement */
2779 #if 0
2780 env->storage_keys[r2 / TARGET_PAGE_SIZE] &= ~SK_REFERENCED;
2781 #endif
2784 * cc
2786 * 0 Reference bit zero; change bit zero
2787 * 1 Reference bit zero; change bit one
2788 * 2 Reference bit one; change bit zero
2789 * 3 Reference bit one; change bit one
2791 return 0;
2794 /* compare and swap and purge */
2795 uint32_t HELPER(csp)(uint32_t r1, uint32_t r2)
2797 uint32_t cc;
2798 uint32_t o1 = env->regs[r1];
2799 uint64_t a2 = get_address_31fix(r2) & ~3ULL;
2800 uint32_t o2 = ldl(a2);
2802 if (o1 == o2) {
2803 stl(a2, env->regs[(r1 + 1) & 15]);
2804 if (env->regs[r2] & 0x3) {
2805 /* flush TLB / ALB */
2806 tlb_flush(env, 1);
2808 cc = 0;
2809 } else {
2810 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2;
2811 cc = 1;
2814 return cc;
2817 static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2,
2818 uint64_t mode2)
2820 target_ulong src, dest;
2821 int flags, cc = 0, i;
2823 if (!l) {
2824 return 0;
2825 } else if (l > 256) {
2826 /* max 256 */
2827 l = 256;
2828 cc = 3;
2831 if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) {
2832 cpu_loop_exit(env);
2834 dest |= a1 & ~TARGET_PAGE_MASK;
2836 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
2837 cpu_loop_exit(env);
2839 src |= a2 & ~TARGET_PAGE_MASK;
2841 /* XXX replace w/ memcpy */
2842 for (i = 0; i < l; i++) {
2843 /* XXX be more clever */
2844 if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
2845 (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
2846 mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2);
2847 break;
2849 stb_phys(dest + i, ldub_phys(src + i));
2852 return cc;
2855 uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2)
2857 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2858 __FUNCTION__, l, a1, a2);
2860 return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
2863 uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2)
2865 HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
2866 __FUNCTION__, l, a1, a2);
2868 return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
2871 uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr)
2873 int cc = 0;
2875 HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
2876 __FUNCTION__, order_code, r1, cpu_addr);
2878 /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register"
2879 as parameter (input). Status (output) is always R1. */
2881 switch (order_code) {
2882 case SIGP_SET_ARCH:
2883 /* switch arch */
2884 break;
2885 case SIGP_SENSE:
2886 /* enumerate CPU status */
2887 if (cpu_addr) {
2888 /* XXX implement when SMP comes */
2889 return 3;
2891 env->regs[r1] &= 0xffffffff00000000ULL;
2892 cc = 1;
2893 break;
2894 default:
2895 /* unknown sigp */
2896 fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
2897 cc = 3;
2900 return cc;
2903 void HELPER(sacf)(uint64_t a1)
2905 HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1);
2907 switch (a1 & 0xf00) {
2908 case 0x000:
2909 env->psw.mask &= ~PSW_MASK_ASC;
2910 env->psw.mask |= PSW_ASC_PRIMARY;
2911 break;
2912 case 0x100:
2913 env->psw.mask &= ~PSW_MASK_ASC;
2914 env->psw.mask |= PSW_ASC_SECONDARY;
2915 break;
2916 case 0x300:
2917 env->psw.mask &= ~PSW_MASK_ASC;
2918 env->psw.mask |= PSW_ASC_HOME;
2919 break;
2920 default:
2921 qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
2922 program_interrupt(env, PGM_SPECIFICATION, 2);
2923 break;
2927 /* invalidate pte */
2928 void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr)
2930 uint64_t page = vaddr & TARGET_PAGE_MASK;
2931 uint64_t pte = 0;
2933 /* XXX broadcast to other CPUs */
2935 /* XXX Linux is nice enough to give us the exact pte address.
2936 According to spec we'd have to find it out ourselves */
2937 /* XXX Linux is fine with overwriting the pte, the spec requires
2938 us to only set the invalid bit */
2939 stq_phys(pte_addr, pte | _PAGE_INVALID);
2941 /* XXX we exploit the fact that Linux passes the exact virtual
2942 address here - it's not obliged to! */
2943 tlb_flush_page(env, page);
2946 /* flush local tlb */
2947 void HELPER(ptlb)(void)
2949 tlb_flush(env, 1);
2952 /* store using real address */
2953 void HELPER(stura)(uint64_t addr, uint32_t v1)
2955 stw_phys(get_address(0, 0, addr), v1);
2958 /* load real address */
2959 uint32_t HELPER(lra)(uint64_t addr, uint32_t r1)
2961 uint32_t cc = 0;
2962 int old_exc = env->exception_index;
2963 uint64_t asc = env->psw.mask & PSW_MASK_ASC;
2964 uint64_t ret;
2965 int flags;
2967 /* XXX incomplete - has more corner cases */
2968 if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) {
2969 program_interrupt(env, PGM_SPECIAL_OP, 2);
2972 env->exception_index = old_exc;
2973 if (mmu_translate(env, addr, 0, asc, &ret, &flags)) {
2974 cc = 3;
2976 if (env->exception_index == EXCP_PGM) {
2977 ret = env->int_pgm_code | 0x80000000;
2978 } else {
2979 ret |= addr & ~TARGET_PAGE_MASK;
2981 env->exception_index = old_exc;
2983 if (!(env->psw.mask & PSW_MASK_64)) {
2984 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL);
2985 } else {
2986 env->regs[r1] = ret;
2989 return cc;
2992 #endif