]> git.proxmox.com Git - qemu.git/blame - target-s390x/op_helper.c
Merge remote-tracking branch 'origin/master' into staging
[qemu.git] / target-s390x / op_helper.c
CommitLineData
10ec5117
AG
1/*
2 * S/390 helper routines
3 *
defb0e31 4 * Copyright (c) 2009 Ulrich Hecht
10ec5117
AG
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
70539e18 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
10ec5117
AG
19 */
20
3e457172
BS
21#include "cpu.h"
22#include "dyngen-exec.h"
defb0e31 23#include "host-utils.h"
3208afbe 24#include "helper.h"
defb0e31
AG
25#include <string.h>
26#include "kvm.h"
27#include "qemu-timer.h"
af2be207
JK
28#ifdef CONFIG_KVM
29#include <linux/kvm.h>
30#endif
10ec5117 31
1864b94a
AG
32#if !defined (CONFIG_USER_ONLY)
33#include "sysemu.h"
34#endif
35
10ec5117
AG
36/*****************************************************************************/
37/* Softmmu support */
38#if !defined (CONFIG_USER_ONLY)
3e457172 39#include "softmmu_exec.h"
10ec5117
AG
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 */
a4e3ad19 59void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx,
20503968 60 uintptr_t retaddr)
10ec5117
AG
61{
62 TranslationBlock *tb;
a4e3ad19 63 CPUS390XState *saved_env;
10ec5117
AG
64 int ret;
65
10ec5117 66 saved_env = env;
bccd9ec5 67 env = env1;
97b348e7 68 ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx);
10ec5117
AG
69 if (unlikely(ret != 0)) {
70 if (likely(retaddr)) {
71 /* now we have a real cpu fault */
20503968 72 tb = tb_find_pc(retaddr);
10ec5117
AG
73 if (likely(tb)) {
74 /* the PC is inside the translated code. It means that we have
75 a virtual CPU fault */
20503968 76 cpu_restore_state(tb, env, retaddr);
10ec5117
AG
77 }
78 }
1162c041 79 cpu_loop_exit(env);
10ec5117
AG
80 }
81 env = saved_env;
82}
83
84#endif
d5a43964 85
defb0e31
AG
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 */
94void HELPER(exception)(uint32_t excp)
95{
96 HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp);
97 env->exception_index = excp;
1162c041 98 cpu_loop_exit(env);
defb0e31
AG
99}
100
101#ifndef CONFIG_USER_ONLY
a4e3ad19 102static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest,
defb0e31
AG
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
a4e3ad19 124static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest,
defb0e31
AG
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 */
158uint32_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 */
177uint32_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 */
211uint32_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 */
230void 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 */
276uint32_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;
296done:
297 HELPER_LOG("\n");
298 return cc;
299}
300
301/* compare logical under mask */
302uint32_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 */
332void 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 */
351void 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 */
365void 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
392static 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
412static 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) */
425uint32_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) */
447uint32_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 */
482void 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) */
497void 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 */
522uint32_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 */
538uint32_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 */
561uint32_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
577static 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 */
614uint32_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;
7d77793d
AG
637 case 0xc00:
638 helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2));
639 break;
defb0e31
AG
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 {
660abort:
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 */
668uint32_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 */
678int32_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 */
688uint64_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 */
700int64_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 */
710uint32_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 */
723void 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 */
739uint32_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 */
770void 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 */
782void 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 */
797void 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 */
812uint32_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 */
853uint32_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 */
902uint32_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 */
939uint32_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 */
954uint32_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
967static 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 */
984static 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
989static 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 */
995static 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
1008static 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
1021static 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 */
1035void 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 */
1042void 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 */
1051void 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 */
1058void 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 */
1065void 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 */
1076void 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 */
1084uint32_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 */
1096uint32_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 */
1107uint32_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 */
1119uint32_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 */
1130void 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 */
1138void 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 */
1153void 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 */
1160void 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 */
1175void 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 */
1182void 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 */
1192void 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 */
1201void 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 */
1208void 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 */
1218uint32_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 */
1228uint32_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 */
1238uint32_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 */
1251uint32_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 */
1258uint32_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 */
1265uint32_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 */
1276uint32_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 */
1284uint32_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 */
1292uint32_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 */
1304void 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 */
1315void 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 */
1326void 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 */
1337uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2)
1338{
1339 float32 v1 = env->fregs[f1].l.upper;
3a93113a 1340 float32 v2 = env->fregs[f2].l.upper;
defb0e31
AG
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 */
1347uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2)
1348{
1349 float64 v1 = env->fregs[f1].d;
3a93113a 1350 float64 v2 = env->fregs[f2].d;
defb0e31
AG
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 */
1357uint32_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 */
1371uint32_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 */
1382uint32_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 */
1394void 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 */
1403uint32_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 */
1413void 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 */
1424void 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
1434static 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 */
1462uint32_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 */
1471uint32_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 */
1480uint32_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 */
1499uint32_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 */
1509uint32_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 */
1519uint32_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 */
1530void HELPER(lzer)(uint32_t f1)
1531{
1532 env->fregs[f1].l.upper = float32_zero;
1533}
1534
1535/* load 64-bit FP zero */
1536void HELPER(lzdr)(uint32_t f1)
1537{
1538 env->fregs[f1].d = float64_zero;
1539}
1540
1541/* load 128-bit FP zero */
1542void 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 */
1551uint32_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 */
1567uint32_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 */
1583void 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 */
1591void 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 */
1598void 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 */
1610void 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 */
1620void 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 */
1630void 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
27b5979d
AG
1639/* convert 32-bit float to 64-bit float */
1640void 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
defb0e31
AG
1648/* convert 64-bit float to 128-bit float */
1649void 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 */
1660uint32_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 */
1682uint32_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 */
1703uint32_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 */
1725uint32_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 */
1747void 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
defb0e31
AG
1752/* checksum */
1753void 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];
5b185639 1757 uint64_t cksm = (uint32_t)env->regs[r1];
defb0e31
AG
1758
1759 while (src_len >= 4) {
1760 cksm += ldl(src);
defb0e31
AG
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:
5b185639 1771 cksm += ldub(src) << 24;
defb0e31
AG
1772 break;
1773 case 2:
5b185639 1774 cksm += lduw(src) << 16;
defb0e31
AG
1775 break;
1776 case 3:
5b185639
AG
1777 cksm += lduw(src) << 16;
1778 cksm += ldub(src + 2) << 8;
defb0e31
AG
1779 break;
1780 }
1781
1782 /* indicate we've processed everything */
5b185639 1783 env->regs[r2] = src + src_len;
defb0e31
AG
1784 env->regs[(r2 + 1) & 15] = 0;
1785
1786 /* store result */
5b185639
AG
1787 env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
1788 ((uint32_t)cksm + (cksm >> 32));
defb0e31
AG
1789}
1790
a4e3ad19 1791static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
defb0e31
AG
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
a4e3ad19 1803static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
1804{
1805 return cc_calc_ltgt_32(env, dst, 0);
1806}
1807
a4e3ad19 1808static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
defb0e31
AG
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
a4e3ad19 1820static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
1821{
1822 return cc_calc_ltgt_64(env, dst, 0);
1823}
1824
a4e3ad19 1825static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
defb0e31
AG
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
a4e3ad19 1837static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
defb0e31
AG
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
a4e3ad19 1849static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask)
defb0e31
AG
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 */
a4e3ad19 1863static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint32_t mask)
defb0e31
AG
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
a4e3ad19 1884static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
defb0e31
AG
1885{
1886 return !!dst;
1887}
1888
a4e3ad19 1889static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2,
defb0e31
AG
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
a4e3ad19 1905static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t a2,
defb0e31
AG
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
a4e3ad19 1923static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2,
defb0e31
AG
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
a4e3ad19 1939static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, uint64_t a2,
defb0e31
AG
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
a4e3ad19 1953static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
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
a4e3ad19 1964static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
1965{
1966 return !!dst;
1967}
1968
a4e3ad19 1969static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
defb0e31
AG
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
a4e3ad19 1983static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2,
defb0e31
AG
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
a4e3ad19 1999static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, uint32_t a2,
defb0e31
AG
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
a4e3ad19 2017static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2,
defb0e31
AG
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
a4e3ad19 2033static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, uint32_t a2,
defb0e31
AG
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
a4e3ad19 2047static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
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
a4e3ad19 2058static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
2059{
2060 return !!dst;
2061}
2062
a4e3ad19 2063static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
defb0e31
AG
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 */
a4e3ad19 2077static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_t val)
defb0e31
AG
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
a4e3ad19 2108static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t shift)
defb0e31
AG
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
a4e3ad19 2137static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src,
defb0e31
AG
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
a4e3ad19 2250uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
d5a43964
AG
2251 uint64_t vr)
2252{
defb0e31
AG
2253 return do_calc_cc(env, cc_op, src, dst, vr);
2254}
2255
2256uint32_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
2262uint64_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
2283void 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
2328void 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
2341void HELPER(load_psw)(uint64_t mask, uint64_t addr)
2342{
2343 load_psw(env, mask, addr);
1162c041 2344 cpu_loop_exit(env);
defb0e31
AG
2345}
2346
a4e3ad19 2347static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
defb0e31
AG
2348{
2349 qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr);
2350
2351 if (kvm_enabled()) {
af2be207 2352#ifdef CONFIG_KVM
defb0e31 2353 kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
af2be207 2354#endif
defb0e31
AG
2355 } else {
2356 env->int_pgm_code = code;
2357 env->int_pgm_ilc = ilc;
2358 env->exception_index = EXCP_PGM;
1162c041 2359 cpu_loop_exit(env);
defb0e31
AG
2360 }
2361}
2362
a4e3ad19 2363static void ext_interrupt(CPUS390XState *env, int type, uint32_t param,
defb0e31
AG
2364 uint64_t param64)
2365{
2366 cpu_inject_ext(env, type, param, param64);
2367}
2368
a4e3ad19 2369int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
defb0e31
AG
2370{
2371 int r = 0;
22486aa0 2372 int shift = 0;
defb0e31
AG
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:
22486aa0
CB
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);
defb0e31
AG
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
2412out:
2413 return r;
2414}
2415
2416/* SCLP service call */
2417uint32_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 */
2427uint64_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 */
2457void HELPER(stidp)(uint64_t a1)
2458{
2459 stq(a1, env->cpu_num);
2460}
2461
2462/* Set Prefix */
2463void 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 */
2475uint32_t HELPER(sck)(uint64_t a1)
2476{
2477 /* XXX not implemented - is it necessary? */
2478
2479 return 0;
2480}
2481
a4e3ad19 2482static inline uint64_t clock_value(CPUS390XState *env)
defb0e31
AG
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 */
2493uint32_t HELPER(stck)(uint64_t a1)
2494{
2495 stq(a1, clock_value(env));
2496
2497 return 0;
2498}
2499
2500/* Store Clock Extended */
2501uint32_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 */
2516void 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 */
2533void HELPER(stckc)(uint64_t a1)
2534{
2535 /* XXX implement */
2536 stq(a1, 0);
2537}
2538
2539/* Set CPU Timer */
2540void 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 */
2555void HELPER(stpt)(uint64_t a1)
2556{
2557 /* XXX implement */
2558 stq(a1, 0);
2559}
2560
2561/* Store System Information */
2562uint32_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
2687void 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
2706void 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
2723void 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
2738void 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
2753uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2)
2754{
2755 /* XXX implement */
2756
2757 return 0;
2758}
2759
2760/* insert storage key extended */
2761uint64_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
defb0e31
AG
2769 return env->storage_keys[addr / TARGET_PAGE_SIZE];
2770}
2771
2772/* set storage key extended */
2773void 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 */
2785uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2)
2786{
17bb18ce
AG
2787 uint8_t re;
2788 uint8_t key;
defb0e31
AG
2789 if (r2 > ram_size) {
2790 return 0;
2791 }
2792
17bb18ce
AG
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);
defb0e31
AG
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 */
17bb18ce
AG
2805
2806 return re >> 1;
d5a43964 2807}
defb0e31
AG
2808
2809/* compare and swap and purge */
2810uint32_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
2832static 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)) {
1162c041 2847 cpu_loop_exit(env);
defb0e31
AG
2848 }
2849 dest |= a1 & ~TARGET_PAGE_MASK;
2850
2851 if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) {
1162c041 2852 cpu_loop_exit(env);
defb0e31
AG
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
2870uint32_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
2878uint32_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
2886uint32_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;
1864b94a
AG
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
defb0e31
AG
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
2928void 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 */
2953void 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);
09ed75f7
AG
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 }
defb0e31
AG
2976}
2977
2978/* flush local tlb */
2979void HELPER(ptlb)(void)
2980{
2981 tlb_flush(env, 1);
2982}
2983
2984/* store using real address */
2985void HELPER(stura)(uint64_t addr, uint32_t v1)
2986{
2987 stw_phys(get_address(0, 0, addr), v1);
2988}
2989
2990/* load real address */
2991uint32_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