PPC: E500: Implement msgclr
[qemu.git] / target-ppc / op_helper.c
1 /*
2 * PowerPC emulation helpers for qemu.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <string.h>
20 #include "cpu.h"
21 #include "dyngen-exec.h"
22 #include "host-utils.h"
23 #include "helper.h"
24
25 #include "helper_regs.h"
26
27 #if !defined(CONFIG_USER_ONLY)
28 #include "softmmu_exec.h"
29 #endif /* !defined(CONFIG_USER_ONLY) */
30
31 //#define DEBUG_OP
32 //#define DEBUG_EXCEPTIONS
33 //#define DEBUG_SOFTWARE_TLB
34
35 #ifdef DEBUG_SOFTWARE_TLB
36 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
37 #else
38 # define LOG_SWTLB(...) do { } while (0)
39 #endif
40
41
42 /*****************************************************************************/
43 /* Exceptions processing helpers */
44
45 void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
46 {
47 #if 0
48 printf("Raise exception %3x code : %d\n", exception, error_code);
49 #endif
50 env->exception_index = exception;
51 env->error_code = error_code;
52 cpu_loop_exit(env);
53 }
54
55 void helper_raise_exception (uint32_t exception)
56 {
57 helper_raise_exception_err(exception, 0);
58 }
59
60 /*****************************************************************************/
61 /* SPR accesses */
62 void helper_load_dump_spr (uint32_t sprn)
63 {
64 qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
65 env->spr[sprn]);
66 }
67
68 void helper_store_dump_spr (uint32_t sprn)
69 {
70 qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
71 env->spr[sprn]);
72 }
73
74 target_ulong helper_load_tbl (void)
75 {
76 return (target_ulong)cpu_ppc_load_tbl(env);
77 }
78
79 target_ulong helper_load_tbu (void)
80 {
81 return cpu_ppc_load_tbu(env);
82 }
83
84 target_ulong helper_load_atbl (void)
85 {
86 return (target_ulong)cpu_ppc_load_atbl(env);
87 }
88
89 target_ulong helper_load_atbu (void)
90 {
91 return cpu_ppc_load_atbu(env);
92 }
93
94 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
95 target_ulong helper_load_purr (void)
96 {
97 return (target_ulong)cpu_ppc_load_purr(env);
98 }
99 #endif
100
101 target_ulong helper_load_601_rtcl (void)
102 {
103 return cpu_ppc601_load_rtcl(env);
104 }
105
106 target_ulong helper_load_601_rtcu (void)
107 {
108 return cpu_ppc601_load_rtcu(env);
109 }
110
111 #if !defined(CONFIG_USER_ONLY)
112 #if defined (TARGET_PPC64)
113 void helper_store_asr (target_ulong val)
114 {
115 ppc_store_asr(env, val);
116 }
117 #endif
118
119 void helper_store_sdr1 (target_ulong val)
120 {
121 ppc_store_sdr1(env, val);
122 }
123
124 void helper_store_tbl (target_ulong val)
125 {
126 cpu_ppc_store_tbl(env, val);
127 }
128
129 void helper_store_tbu (target_ulong val)
130 {
131 cpu_ppc_store_tbu(env, val);
132 }
133
134 void helper_store_atbl (target_ulong val)
135 {
136 cpu_ppc_store_atbl(env, val);
137 }
138
139 void helper_store_atbu (target_ulong val)
140 {
141 cpu_ppc_store_atbu(env, val);
142 }
143
144 void helper_store_601_rtcl (target_ulong val)
145 {
146 cpu_ppc601_store_rtcl(env, val);
147 }
148
149 void helper_store_601_rtcu (target_ulong val)
150 {
151 cpu_ppc601_store_rtcu(env, val);
152 }
153
154 target_ulong helper_load_decr (void)
155 {
156 return cpu_ppc_load_decr(env);
157 }
158
159 void helper_store_decr (target_ulong val)
160 {
161 cpu_ppc_store_decr(env, val);
162 }
163
164 void helper_store_hid0_601 (target_ulong val)
165 {
166 target_ulong hid0;
167
168 hid0 = env->spr[SPR_HID0];
169 if ((val ^ hid0) & 0x00000008) {
170 /* Change current endianness */
171 env->hflags &= ~(1 << MSR_LE);
172 env->hflags_nmsr &= ~(1 << MSR_LE);
173 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
174 env->hflags |= env->hflags_nmsr;
175 qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
176 val & 0x8 ? 'l' : 'b', env->hflags);
177 }
178 env->spr[SPR_HID0] = (uint32_t)val;
179 }
180
181 void helper_store_403_pbr (uint32_t num, target_ulong value)
182 {
183 if (likely(env->pb[num] != value)) {
184 env->pb[num] = value;
185 /* Should be optimized */
186 tlb_flush(env, 1);
187 }
188 }
189
190 target_ulong helper_load_40x_pit (void)
191 {
192 return load_40x_pit(env);
193 }
194
195 void helper_store_40x_pit (target_ulong val)
196 {
197 store_40x_pit(env, val);
198 }
199
200 void helper_store_40x_dbcr0 (target_ulong val)
201 {
202 store_40x_dbcr0(env, val);
203 }
204
205 void helper_store_40x_sler (target_ulong val)
206 {
207 store_40x_sler(env, val);
208 }
209
210 void helper_store_booke_tcr (target_ulong val)
211 {
212 store_booke_tcr(env, val);
213 }
214
215 void helper_store_booke_tsr (target_ulong val)
216 {
217 store_booke_tsr(env, val);
218 }
219
220 void helper_store_ibatu (uint32_t nr, target_ulong val)
221 {
222 ppc_store_ibatu(env, nr, val);
223 }
224
225 void helper_store_ibatl (uint32_t nr, target_ulong val)
226 {
227 ppc_store_ibatl(env, nr, val);
228 }
229
230 void helper_store_dbatu (uint32_t nr, target_ulong val)
231 {
232 ppc_store_dbatu(env, nr, val);
233 }
234
235 void helper_store_dbatl (uint32_t nr, target_ulong val)
236 {
237 ppc_store_dbatl(env, nr, val);
238 }
239
240 void helper_store_601_batl (uint32_t nr, target_ulong val)
241 {
242 ppc_store_ibatl_601(env, nr, val);
243 }
244
245 void helper_store_601_batu (uint32_t nr, target_ulong val)
246 {
247 ppc_store_ibatu_601(env, nr, val);
248 }
249 #endif
250
251 /*****************************************************************************/
252 /* Memory load and stores */
253
254 static inline target_ulong addr_add(target_ulong addr, target_long arg)
255 {
256 #if defined(TARGET_PPC64)
257 if (!msr_sf)
258 return (uint32_t)(addr + arg);
259 else
260 #endif
261 return addr + arg;
262 }
263
264 void helper_lmw (target_ulong addr, uint32_t reg)
265 {
266 for (; reg < 32; reg++) {
267 if (msr_le)
268 env->gpr[reg] = bswap32(ldl(addr));
269 else
270 env->gpr[reg] = ldl(addr);
271 addr = addr_add(addr, 4);
272 }
273 }
274
275 void helper_stmw (target_ulong addr, uint32_t reg)
276 {
277 for (; reg < 32; reg++) {
278 if (msr_le)
279 stl(addr, bswap32((uint32_t)env->gpr[reg]));
280 else
281 stl(addr, (uint32_t)env->gpr[reg]);
282 addr = addr_add(addr, 4);
283 }
284 }
285
286 void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
287 {
288 int sh;
289 for (; nb > 3; nb -= 4) {
290 env->gpr[reg] = ldl(addr);
291 reg = (reg + 1) % 32;
292 addr = addr_add(addr, 4);
293 }
294 if (unlikely(nb > 0)) {
295 env->gpr[reg] = 0;
296 for (sh = 24; nb > 0; nb--, sh -= 8) {
297 env->gpr[reg] |= ldub(addr) << sh;
298 addr = addr_add(addr, 1);
299 }
300 }
301 }
302 /* PPC32 specification says we must generate an exception if
303 * rA is in the range of registers to be loaded.
304 * In an other hand, IBM says this is valid, but rA won't be loaded.
305 * For now, I'll follow the spec...
306 */
307 void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
308 {
309 if (likely(xer_bc != 0)) {
310 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
311 (reg < rb && (reg + xer_bc) > rb))) {
312 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
313 POWERPC_EXCP_INVAL |
314 POWERPC_EXCP_INVAL_LSWX);
315 } else {
316 helper_lsw(addr, xer_bc, reg);
317 }
318 }
319 }
320
321 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
322 {
323 int sh;
324 for (; nb > 3; nb -= 4) {
325 stl(addr, env->gpr[reg]);
326 reg = (reg + 1) % 32;
327 addr = addr_add(addr, 4);
328 }
329 if (unlikely(nb > 0)) {
330 for (sh = 24; nb > 0; nb--, sh -= 8) {
331 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
332 addr = addr_add(addr, 1);
333 }
334 }
335 }
336
337 static void do_dcbz(target_ulong addr, int dcache_line_size)
338 {
339 addr &= ~(dcache_line_size - 1);
340 int i;
341 for (i = 0 ; i < dcache_line_size ; i += 4) {
342 stl(addr + i , 0);
343 }
344 if (env->reserve_addr == addr)
345 env->reserve_addr = (target_ulong)-1ULL;
346 }
347
348 void helper_dcbz(target_ulong addr)
349 {
350 do_dcbz(addr, env->dcache_line_size);
351 }
352
353 void helper_dcbz_970(target_ulong addr)
354 {
355 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
356 do_dcbz(addr, 32);
357 else
358 do_dcbz(addr, env->dcache_line_size);
359 }
360
361 void helper_icbi(target_ulong addr)
362 {
363 addr &= ~(env->dcache_line_size - 1);
364 /* Invalidate one cache line :
365 * PowerPC specification says this is to be treated like a load
366 * (not a fetch) by the MMU. To be sure it will be so,
367 * do the load "by hand".
368 */
369 ldl(addr);
370 }
371
372 // XXX: to be tested
373 target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
374 {
375 int i, c, d;
376 d = 24;
377 for (i = 0; i < xer_bc; i++) {
378 c = ldub(addr);
379 addr = addr_add(addr, 1);
380 /* ra (if not 0) and rb are never modified */
381 if (likely(reg != rb && (ra == 0 || reg != ra))) {
382 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
383 }
384 if (unlikely(c == xer_cmp))
385 break;
386 if (likely(d != 0)) {
387 d -= 8;
388 } else {
389 d = 24;
390 reg++;
391 reg = reg & 0x1F;
392 }
393 }
394 return i;
395 }
396
397 /*****************************************************************************/
398 /* Fixed point operations helpers */
399 #if defined(TARGET_PPC64)
400
401 /* multiply high word */
402 uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
403 {
404 uint64_t tl, th;
405
406 muls64(&tl, &th, arg1, arg2);
407 return th;
408 }
409
410 /* multiply high word unsigned */
411 uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
412 {
413 uint64_t tl, th;
414
415 mulu64(&tl, &th, arg1, arg2);
416 return th;
417 }
418
419 uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
420 {
421 int64_t th;
422 uint64_t tl;
423
424 muls64(&tl, (uint64_t *)&th, arg1, arg2);
425 /* If th != 0 && th != -1, then we had an overflow */
426 if (likely((uint64_t)(th + 1) <= 1)) {
427 env->xer &= ~(1 << XER_OV);
428 } else {
429 env->xer |= (1 << XER_OV) | (1 << XER_SO);
430 }
431 return (int64_t)tl;
432 }
433 #endif
434
435 target_ulong helper_cntlzw (target_ulong t)
436 {
437 return clz32(t);
438 }
439
440 #if defined(TARGET_PPC64)
441 target_ulong helper_cntlzd (target_ulong t)
442 {
443 return clz64(t);
444 }
445 #endif
446
447 /* shift right arithmetic helper */
448 target_ulong helper_sraw (target_ulong value, target_ulong shift)
449 {
450 int32_t ret;
451
452 if (likely(!(shift & 0x20))) {
453 if (likely((uint32_t)shift != 0)) {
454 shift &= 0x1f;
455 ret = (int32_t)value >> shift;
456 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
457 env->xer &= ~(1 << XER_CA);
458 } else {
459 env->xer |= (1 << XER_CA);
460 }
461 } else {
462 ret = (int32_t)value;
463 env->xer &= ~(1 << XER_CA);
464 }
465 } else {
466 ret = (int32_t)value >> 31;
467 if (ret) {
468 env->xer |= (1 << XER_CA);
469 } else {
470 env->xer &= ~(1 << XER_CA);
471 }
472 }
473 return (target_long)ret;
474 }
475
476 #if defined(TARGET_PPC64)
477 target_ulong helper_srad (target_ulong value, target_ulong shift)
478 {
479 int64_t ret;
480
481 if (likely(!(shift & 0x40))) {
482 if (likely((uint64_t)shift != 0)) {
483 shift &= 0x3f;
484 ret = (int64_t)value >> shift;
485 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
486 env->xer &= ~(1 << XER_CA);
487 } else {
488 env->xer |= (1 << XER_CA);
489 }
490 } else {
491 ret = (int64_t)value;
492 env->xer &= ~(1 << XER_CA);
493 }
494 } else {
495 ret = (int64_t)value >> 63;
496 if (ret) {
497 env->xer |= (1 << XER_CA);
498 } else {
499 env->xer &= ~(1 << XER_CA);
500 }
501 }
502 return ret;
503 }
504 #endif
505
506 #if defined(TARGET_PPC64)
507 target_ulong helper_popcntb (target_ulong val)
508 {
509 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
510 0x5555555555555555ULL);
511 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
512 0x3333333333333333ULL);
513 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
514 0x0f0f0f0f0f0f0f0fULL);
515 return val;
516 }
517
518 target_ulong helper_popcntw (target_ulong val)
519 {
520 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
521 0x5555555555555555ULL);
522 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
523 0x3333333333333333ULL);
524 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
525 0x0f0f0f0f0f0f0f0fULL);
526 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
527 0x00ff00ff00ff00ffULL);
528 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
529 0x0000ffff0000ffffULL);
530 return val;
531 }
532
533 target_ulong helper_popcntd (target_ulong val)
534 {
535 return ctpop64(val);
536 }
537 #else
538 target_ulong helper_popcntb (target_ulong val)
539 {
540 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
541 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
542 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
543 return val;
544 }
545
546 target_ulong helper_popcntw (target_ulong val)
547 {
548 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
549 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
550 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
551 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
552 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
553 return val;
554 }
555 #endif
556
557 /*****************************************************************************/
558 /* Floating point operations helpers */
559 uint64_t helper_float32_to_float64(uint32_t arg)
560 {
561 CPU_FloatU f;
562 CPU_DoubleU d;
563 f.l = arg;
564 d.d = float32_to_float64(f.f, &env->fp_status);
565 return d.ll;
566 }
567
568 uint32_t helper_float64_to_float32(uint64_t arg)
569 {
570 CPU_FloatU f;
571 CPU_DoubleU d;
572 d.ll = arg;
573 f.f = float64_to_float32(d.d, &env->fp_status);
574 return f.l;
575 }
576
577 static inline int isden(float64 d)
578 {
579 CPU_DoubleU u;
580
581 u.d = d;
582
583 return ((u.ll >> 52) & 0x7FF) == 0;
584 }
585
586 uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
587 {
588 CPU_DoubleU farg;
589 int isneg;
590 int ret;
591 farg.ll = arg;
592 isneg = float64_is_neg(farg.d);
593 if (unlikely(float64_is_any_nan(farg.d))) {
594 if (float64_is_signaling_nan(farg.d)) {
595 /* Signaling NaN: flags are undefined */
596 ret = 0x00;
597 } else {
598 /* Quiet NaN */
599 ret = 0x11;
600 }
601 } else if (unlikely(float64_is_infinity(farg.d))) {
602 /* +/- infinity */
603 if (isneg)
604 ret = 0x09;
605 else
606 ret = 0x05;
607 } else {
608 if (float64_is_zero(farg.d)) {
609 /* +/- zero */
610 if (isneg)
611 ret = 0x12;
612 else
613 ret = 0x02;
614 } else {
615 if (isden(farg.d)) {
616 /* Denormalized numbers */
617 ret = 0x10;
618 } else {
619 /* Normalized numbers */
620 ret = 0x00;
621 }
622 if (isneg) {
623 ret |= 0x08;
624 } else {
625 ret |= 0x04;
626 }
627 }
628 }
629 if (set_fprf) {
630 /* We update FPSCR_FPRF */
631 env->fpscr &= ~(0x1F << FPSCR_FPRF);
632 env->fpscr |= ret << FPSCR_FPRF;
633 }
634 /* We just need fpcc to update Rc1 */
635 return ret & 0xF;
636 }
637
638 /* Floating-point invalid operations exception */
639 static inline uint64_t fload_invalid_op_excp(int op)
640 {
641 uint64_t ret = 0;
642 int ve;
643
644 ve = fpscr_ve;
645 switch (op) {
646 case POWERPC_EXCP_FP_VXSNAN:
647 env->fpscr |= 1 << FPSCR_VXSNAN;
648 break;
649 case POWERPC_EXCP_FP_VXSOFT:
650 env->fpscr |= 1 << FPSCR_VXSOFT;
651 break;
652 case POWERPC_EXCP_FP_VXISI:
653 /* Magnitude subtraction of infinities */
654 env->fpscr |= 1 << FPSCR_VXISI;
655 goto update_arith;
656 case POWERPC_EXCP_FP_VXIDI:
657 /* Division of infinity by infinity */
658 env->fpscr |= 1 << FPSCR_VXIDI;
659 goto update_arith;
660 case POWERPC_EXCP_FP_VXZDZ:
661 /* Division of zero by zero */
662 env->fpscr |= 1 << FPSCR_VXZDZ;
663 goto update_arith;
664 case POWERPC_EXCP_FP_VXIMZ:
665 /* Multiplication of zero by infinity */
666 env->fpscr |= 1 << FPSCR_VXIMZ;
667 goto update_arith;
668 case POWERPC_EXCP_FP_VXVC:
669 /* Ordered comparison of NaN */
670 env->fpscr |= 1 << FPSCR_VXVC;
671 env->fpscr &= ~(0xF << FPSCR_FPCC);
672 env->fpscr |= 0x11 << FPSCR_FPCC;
673 /* We must update the target FPR before raising the exception */
674 if (ve != 0) {
675 env->exception_index = POWERPC_EXCP_PROGRAM;
676 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
677 /* Update the floating-point enabled exception summary */
678 env->fpscr |= 1 << FPSCR_FEX;
679 /* Exception is differed */
680 ve = 0;
681 }
682 break;
683 case POWERPC_EXCP_FP_VXSQRT:
684 /* Square root of a negative number */
685 env->fpscr |= 1 << FPSCR_VXSQRT;
686 update_arith:
687 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
688 if (ve == 0) {
689 /* Set the result to quiet NaN */
690 ret = 0x7FF8000000000000ULL;
691 env->fpscr &= ~(0xF << FPSCR_FPCC);
692 env->fpscr |= 0x11 << FPSCR_FPCC;
693 }
694 break;
695 case POWERPC_EXCP_FP_VXCVI:
696 /* Invalid conversion */
697 env->fpscr |= 1 << FPSCR_VXCVI;
698 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
699 if (ve == 0) {
700 /* Set the result to quiet NaN */
701 ret = 0x7FF8000000000000ULL;
702 env->fpscr &= ~(0xF << FPSCR_FPCC);
703 env->fpscr |= 0x11 << FPSCR_FPCC;
704 }
705 break;
706 }
707 /* Update the floating-point invalid operation summary */
708 env->fpscr |= 1 << FPSCR_VX;
709 /* Update the floating-point exception summary */
710 env->fpscr |= 1 << FPSCR_FX;
711 if (ve != 0) {
712 /* Update the floating-point enabled exception summary */
713 env->fpscr |= 1 << FPSCR_FEX;
714 if (msr_fe0 != 0 || msr_fe1 != 0)
715 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
716 }
717 return ret;
718 }
719
720 static inline void float_zero_divide_excp(void)
721 {
722 env->fpscr |= 1 << FPSCR_ZX;
723 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
724 /* Update the floating-point exception summary */
725 env->fpscr |= 1 << FPSCR_FX;
726 if (fpscr_ze != 0) {
727 /* Update the floating-point enabled exception summary */
728 env->fpscr |= 1 << FPSCR_FEX;
729 if (msr_fe0 != 0 || msr_fe1 != 0) {
730 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
731 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
732 }
733 }
734 }
735
736 static inline void float_overflow_excp(void)
737 {
738 env->fpscr |= 1 << FPSCR_OX;
739 /* Update the floating-point exception summary */
740 env->fpscr |= 1 << FPSCR_FX;
741 if (fpscr_oe != 0) {
742 /* XXX: should adjust the result */
743 /* Update the floating-point enabled exception summary */
744 env->fpscr |= 1 << FPSCR_FEX;
745 /* We must update the target FPR before raising the exception */
746 env->exception_index = POWERPC_EXCP_PROGRAM;
747 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
748 } else {
749 env->fpscr |= 1 << FPSCR_XX;
750 env->fpscr |= 1 << FPSCR_FI;
751 }
752 }
753
754 static inline void float_underflow_excp(void)
755 {
756 env->fpscr |= 1 << FPSCR_UX;
757 /* Update the floating-point exception summary */
758 env->fpscr |= 1 << FPSCR_FX;
759 if (fpscr_ue != 0) {
760 /* XXX: should adjust the result */
761 /* Update the floating-point enabled exception summary */
762 env->fpscr |= 1 << FPSCR_FEX;
763 /* We must update the target FPR before raising the exception */
764 env->exception_index = POWERPC_EXCP_PROGRAM;
765 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
766 }
767 }
768
769 static inline void float_inexact_excp(void)
770 {
771 env->fpscr |= 1 << FPSCR_XX;
772 /* Update the floating-point exception summary */
773 env->fpscr |= 1 << FPSCR_FX;
774 if (fpscr_xe != 0) {
775 /* Update the floating-point enabled exception summary */
776 env->fpscr |= 1 << FPSCR_FEX;
777 /* We must update the target FPR before raising the exception */
778 env->exception_index = POWERPC_EXCP_PROGRAM;
779 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
780 }
781 }
782
783 static inline void fpscr_set_rounding_mode(void)
784 {
785 int rnd_type;
786
787 /* Set rounding mode */
788 switch (fpscr_rn) {
789 case 0:
790 /* Best approximation (round to nearest) */
791 rnd_type = float_round_nearest_even;
792 break;
793 case 1:
794 /* Smaller magnitude (round toward zero) */
795 rnd_type = float_round_to_zero;
796 break;
797 case 2:
798 /* Round toward +infinite */
799 rnd_type = float_round_up;
800 break;
801 default:
802 case 3:
803 /* Round toward -infinite */
804 rnd_type = float_round_down;
805 break;
806 }
807 set_float_rounding_mode(rnd_type, &env->fp_status);
808 }
809
810 void helper_fpscr_clrbit (uint32_t bit)
811 {
812 int prev;
813
814 prev = (env->fpscr >> bit) & 1;
815 env->fpscr &= ~(1 << bit);
816 if (prev == 1) {
817 switch (bit) {
818 case FPSCR_RN1:
819 case FPSCR_RN:
820 fpscr_set_rounding_mode();
821 break;
822 default:
823 break;
824 }
825 }
826 }
827
828 void helper_fpscr_setbit (uint32_t bit)
829 {
830 int prev;
831
832 prev = (env->fpscr >> bit) & 1;
833 env->fpscr |= 1 << bit;
834 if (prev == 0) {
835 switch (bit) {
836 case FPSCR_VX:
837 env->fpscr |= 1 << FPSCR_FX;
838 if (fpscr_ve)
839 goto raise_ve;
840 case FPSCR_OX:
841 env->fpscr |= 1 << FPSCR_FX;
842 if (fpscr_oe)
843 goto raise_oe;
844 break;
845 case FPSCR_UX:
846 env->fpscr |= 1 << FPSCR_FX;
847 if (fpscr_ue)
848 goto raise_ue;
849 break;
850 case FPSCR_ZX:
851 env->fpscr |= 1 << FPSCR_FX;
852 if (fpscr_ze)
853 goto raise_ze;
854 break;
855 case FPSCR_XX:
856 env->fpscr |= 1 << FPSCR_FX;
857 if (fpscr_xe)
858 goto raise_xe;
859 break;
860 case FPSCR_VXSNAN:
861 case FPSCR_VXISI:
862 case FPSCR_VXIDI:
863 case FPSCR_VXZDZ:
864 case FPSCR_VXIMZ:
865 case FPSCR_VXVC:
866 case FPSCR_VXSOFT:
867 case FPSCR_VXSQRT:
868 case FPSCR_VXCVI:
869 env->fpscr |= 1 << FPSCR_VX;
870 env->fpscr |= 1 << FPSCR_FX;
871 if (fpscr_ve != 0)
872 goto raise_ve;
873 break;
874 case FPSCR_VE:
875 if (fpscr_vx != 0) {
876 raise_ve:
877 env->error_code = POWERPC_EXCP_FP;
878 if (fpscr_vxsnan)
879 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
880 if (fpscr_vxisi)
881 env->error_code |= POWERPC_EXCP_FP_VXISI;
882 if (fpscr_vxidi)
883 env->error_code |= POWERPC_EXCP_FP_VXIDI;
884 if (fpscr_vxzdz)
885 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
886 if (fpscr_vximz)
887 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
888 if (fpscr_vxvc)
889 env->error_code |= POWERPC_EXCP_FP_VXVC;
890 if (fpscr_vxsoft)
891 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
892 if (fpscr_vxsqrt)
893 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
894 if (fpscr_vxcvi)
895 env->error_code |= POWERPC_EXCP_FP_VXCVI;
896 goto raise_excp;
897 }
898 break;
899 case FPSCR_OE:
900 if (fpscr_ox != 0) {
901 raise_oe:
902 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
903 goto raise_excp;
904 }
905 break;
906 case FPSCR_UE:
907 if (fpscr_ux != 0) {
908 raise_ue:
909 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
910 goto raise_excp;
911 }
912 break;
913 case FPSCR_ZE:
914 if (fpscr_zx != 0) {
915 raise_ze:
916 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
917 goto raise_excp;
918 }
919 break;
920 case FPSCR_XE:
921 if (fpscr_xx != 0) {
922 raise_xe:
923 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
924 goto raise_excp;
925 }
926 break;
927 case FPSCR_RN1:
928 case FPSCR_RN:
929 fpscr_set_rounding_mode();
930 break;
931 default:
932 break;
933 raise_excp:
934 /* Update the floating-point enabled exception summary */
935 env->fpscr |= 1 << FPSCR_FEX;
936 /* We have to update Rc1 before raising the exception */
937 env->exception_index = POWERPC_EXCP_PROGRAM;
938 break;
939 }
940 }
941 }
942
943 void helper_store_fpscr (uint64_t arg, uint32_t mask)
944 {
945 /*
946 * We use only the 32 LSB of the incoming fpr
947 */
948 uint32_t prev, new;
949 int i;
950
951 prev = env->fpscr;
952 new = (uint32_t)arg;
953 new &= ~0x60000000;
954 new |= prev & 0x60000000;
955 for (i = 0; i < 8; i++) {
956 if (mask & (1 << i)) {
957 env->fpscr &= ~(0xF << (4 * i));
958 env->fpscr |= new & (0xF << (4 * i));
959 }
960 }
961 /* Update VX and FEX */
962 if (fpscr_ix != 0)
963 env->fpscr |= 1 << FPSCR_VX;
964 else
965 env->fpscr &= ~(1 << FPSCR_VX);
966 if ((fpscr_ex & fpscr_eex) != 0) {
967 env->fpscr |= 1 << FPSCR_FEX;
968 env->exception_index = POWERPC_EXCP_PROGRAM;
969 /* XXX: we should compute it properly */
970 env->error_code = POWERPC_EXCP_FP;
971 }
972 else
973 env->fpscr &= ~(1 << FPSCR_FEX);
974 fpscr_set_rounding_mode();
975 }
976
977 void helper_float_check_status (void)
978 {
979 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
980 (env->error_code & POWERPC_EXCP_FP)) {
981 /* Differred floating-point exception after target FPR update */
982 if (msr_fe0 != 0 || msr_fe1 != 0)
983 helper_raise_exception_err(env->exception_index, env->error_code);
984 } else {
985 int status = get_float_exception_flags(&env->fp_status);
986 if (status & float_flag_divbyzero) {
987 float_zero_divide_excp();
988 } else if (status & float_flag_overflow) {
989 float_overflow_excp();
990 } else if (status & float_flag_underflow) {
991 float_underflow_excp();
992 } else if (status & float_flag_inexact) {
993 float_inexact_excp();
994 }
995 }
996 }
997
998 void helper_reset_fpstatus (void)
999 {
1000 set_float_exception_flags(0, &env->fp_status);
1001 }
1002
1003 /* fadd - fadd. */
1004 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
1005 {
1006 CPU_DoubleU farg1, farg2;
1007
1008 farg1.ll = arg1;
1009 farg2.ll = arg2;
1010
1011 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1012 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1013 /* Magnitude subtraction of infinities */
1014 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1015 } else {
1016 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1017 float64_is_signaling_nan(farg2.d))) {
1018 /* sNaN addition */
1019 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1020 }
1021 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1022 }
1023
1024 return farg1.ll;
1025 }
1026
1027 /* fsub - fsub. */
1028 uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1029 {
1030 CPU_DoubleU farg1, farg2;
1031
1032 farg1.ll = arg1;
1033 farg2.ll = arg2;
1034
1035 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1036 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1037 /* Magnitude subtraction of infinities */
1038 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1039 } else {
1040 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1041 float64_is_signaling_nan(farg2.d))) {
1042 /* sNaN subtraction */
1043 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1044 }
1045 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1046 }
1047
1048 return farg1.ll;
1049 }
1050
1051 /* fmul - fmul. */
1052 uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1053 {
1054 CPU_DoubleU farg1, farg2;
1055
1056 farg1.ll = arg1;
1057 farg2.ll = arg2;
1058
1059 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1060 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1061 /* Multiplication of zero by infinity */
1062 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1063 } else {
1064 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1065 float64_is_signaling_nan(farg2.d))) {
1066 /* sNaN multiplication */
1067 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1068 }
1069 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1070 }
1071
1072 return farg1.ll;
1073 }
1074
1075 /* fdiv - fdiv. */
1076 uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1077 {
1078 CPU_DoubleU farg1, farg2;
1079
1080 farg1.ll = arg1;
1081 farg2.ll = arg2;
1082
1083 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
1084 /* Division of infinity by infinity */
1085 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1086 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1087 /* Division of zero by zero */
1088 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1089 } else {
1090 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1091 float64_is_signaling_nan(farg2.d))) {
1092 /* sNaN division */
1093 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1094 }
1095 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1096 }
1097
1098 return farg1.ll;
1099 }
1100
1101 /* fabs */
1102 uint64_t helper_fabs (uint64_t arg)
1103 {
1104 CPU_DoubleU farg;
1105
1106 farg.ll = arg;
1107 farg.d = float64_abs(farg.d);
1108 return farg.ll;
1109 }
1110
1111 /* fnabs */
1112 uint64_t helper_fnabs (uint64_t arg)
1113 {
1114 CPU_DoubleU farg;
1115
1116 farg.ll = arg;
1117 farg.d = float64_abs(farg.d);
1118 farg.d = float64_chs(farg.d);
1119 return farg.ll;
1120 }
1121
1122 /* fneg */
1123 uint64_t helper_fneg (uint64_t arg)
1124 {
1125 CPU_DoubleU farg;
1126
1127 farg.ll = arg;
1128 farg.d = float64_chs(farg.d);
1129 return farg.ll;
1130 }
1131
1132 /* fctiw - fctiw. */
1133 uint64_t helper_fctiw (uint64_t arg)
1134 {
1135 CPU_DoubleU farg;
1136 farg.ll = arg;
1137
1138 if (unlikely(float64_is_signaling_nan(farg.d))) {
1139 /* sNaN conversion */
1140 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1141 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1142 /* qNan / infinity conversion */
1143 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1144 } else {
1145 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1146 /* XXX: higher bits are not supposed to be significant.
1147 * to make tests easier, return the same as a real PowerPC 750
1148 */
1149 farg.ll |= 0xFFF80000ULL << 32;
1150 }
1151 return farg.ll;
1152 }
1153
1154 /* fctiwz - fctiwz. */
1155 uint64_t helper_fctiwz (uint64_t arg)
1156 {
1157 CPU_DoubleU farg;
1158 farg.ll = arg;
1159
1160 if (unlikely(float64_is_signaling_nan(farg.d))) {
1161 /* sNaN conversion */
1162 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1163 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1164 /* qNan / infinity conversion */
1165 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1166 } else {
1167 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1168 /* XXX: higher bits are not supposed to be significant.
1169 * to make tests easier, return the same as a real PowerPC 750
1170 */
1171 farg.ll |= 0xFFF80000ULL << 32;
1172 }
1173 return farg.ll;
1174 }
1175
1176 #if defined(TARGET_PPC64)
1177 /* fcfid - fcfid. */
1178 uint64_t helper_fcfid (uint64_t arg)
1179 {
1180 CPU_DoubleU farg;
1181 farg.d = int64_to_float64(arg, &env->fp_status);
1182 return farg.ll;
1183 }
1184
1185 /* fctid - fctid. */
1186 uint64_t helper_fctid (uint64_t arg)
1187 {
1188 CPU_DoubleU farg;
1189 farg.ll = arg;
1190
1191 if (unlikely(float64_is_signaling_nan(farg.d))) {
1192 /* sNaN conversion */
1193 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1194 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1195 /* qNan / infinity conversion */
1196 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1197 } else {
1198 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1199 }
1200 return farg.ll;
1201 }
1202
1203 /* fctidz - fctidz. */
1204 uint64_t helper_fctidz (uint64_t arg)
1205 {
1206 CPU_DoubleU farg;
1207 farg.ll = arg;
1208
1209 if (unlikely(float64_is_signaling_nan(farg.d))) {
1210 /* sNaN conversion */
1211 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1212 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1213 /* qNan / infinity conversion */
1214 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1215 } else {
1216 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1217 }
1218 return farg.ll;
1219 }
1220
1221 #endif
1222
1223 static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
1224 {
1225 CPU_DoubleU farg;
1226 farg.ll = arg;
1227
1228 if (unlikely(float64_is_signaling_nan(farg.d))) {
1229 /* sNaN round */
1230 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1231 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1232 /* qNan / infinity round */
1233 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1234 } else {
1235 set_float_rounding_mode(rounding_mode, &env->fp_status);
1236 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1237 /* Restore rounding mode from FPSCR */
1238 fpscr_set_rounding_mode();
1239 }
1240 return farg.ll;
1241 }
1242
1243 uint64_t helper_frin (uint64_t arg)
1244 {
1245 return do_fri(arg, float_round_nearest_even);
1246 }
1247
1248 uint64_t helper_friz (uint64_t arg)
1249 {
1250 return do_fri(arg, float_round_to_zero);
1251 }
1252
1253 uint64_t helper_frip (uint64_t arg)
1254 {
1255 return do_fri(arg, float_round_up);
1256 }
1257
1258 uint64_t helper_frim (uint64_t arg)
1259 {
1260 return do_fri(arg, float_round_down);
1261 }
1262
1263 /* fmadd - fmadd. */
1264 uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1265 {
1266 CPU_DoubleU farg1, farg2, farg3;
1267
1268 farg1.ll = arg1;
1269 farg2.ll = arg2;
1270 farg3.ll = arg3;
1271
1272 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1273 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1274 /* Multiplication of zero by infinity */
1275 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1276 } else {
1277 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1278 float64_is_signaling_nan(farg2.d) ||
1279 float64_is_signaling_nan(farg3.d))) {
1280 /* sNaN operation */
1281 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1282 }
1283 /* This is the way the PowerPC specification defines it */
1284 float128 ft0_128, ft1_128;
1285
1286 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1287 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1288 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1289 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1290 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1291 /* Magnitude subtraction of infinities */
1292 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1293 } else {
1294 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1295 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1296 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1297 }
1298 }
1299
1300 return farg1.ll;
1301 }
1302
1303 /* fmsub - fmsub. */
1304 uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1305 {
1306 CPU_DoubleU farg1, farg2, farg3;
1307
1308 farg1.ll = arg1;
1309 farg2.ll = arg2;
1310 farg3.ll = arg3;
1311
1312 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1313 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1314 /* Multiplication of zero by infinity */
1315 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1316 } else {
1317 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1318 float64_is_signaling_nan(farg2.d) ||
1319 float64_is_signaling_nan(farg3.d))) {
1320 /* sNaN operation */
1321 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1322 }
1323 /* This is the way the PowerPC specification defines it */
1324 float128 ft0_128, ft1_128;
1325
1326 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1327 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1328 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1329 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1330 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1331 /* Magnitude subtraction of infinities */
1332 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1333 } else {
1334 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1335 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1336 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1337 }
1338 }
1339 return farg1.ll;
1340 }
1341
1342 /* fnmadd - fnmadd. */
1343 uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1344 {
1345 CPU_DoubleU farg1, farg2, farg3;
1346
1347 farg1.ll = arg1;
1348 farg2.ll = arg2;
1349 farg3.ll = arg3;
1350
1351 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1352 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1353 /* Multiplication of zero by infinity */
1354 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1355 } else {
1356 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1357 float64_is_signaling_nan(farg2.d) ||
1358 float64_is_signaling_nan(farg3.d))) {
1359 /* sNaN operation */
1360 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1361 }
1362 /* This is the way the PowerPC specification defines it */
1363 float128 ft0_128, ft1_128;
1364
1365 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1366 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1367 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1368 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1369 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1370 /* Magnitude subtraction of infinities */
1371 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1372 } else {
1373 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1374 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1375 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1376 }
1377 if (likely(!float64_is_any_nan(farg1.d))) {
1378 farg1.d = float64_chs(farg1.d);
1379 }
1380 }
1381 return farg1.ll;
1382 }
1383
1384 /* fnmsub - fnmsub. */
1385 uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1386 {
1387 CPU_DoubleU farg1, farg2, farg3;
1388
1389 farg1.ll = arg1;
1390 farg2.ll = arg2;
1391 farg3.ll = arg3;
1392
1393 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1394 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1395 /* Multiplication of zero by infinity */
1396 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1397 } else {
1398 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1399 float64_is_signaling_nan(farg2.d) ||
1400 float64_is_signaling_nan(farg3.d))) {
1401 /* sNaN operation */
1402 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1403 }
1404 /* This is the way the PowerPC specification defines it */
1405 float128 ft0_128, ft1_128;
1406
1407 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1408 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1409 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1410 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1411 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1412 /* Magnitude subtraction of infinities */
1413 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1414 } else {
1415 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1416 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1417 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1418 }
1419 if (likely(!float64_is_any_nan(farg1.d))) {
1420 farg1.d = float64_chs(farg1.d);
1421 }
1422 }
1423 return farg1.ll;
1424 }
1425
1426 /* frsp - frsp. */
1427 uint64_t helper_frsp (uint64_t arg)
1428 {
1429 CPU_DoubleU farg;
1430 float32 f32;
1431 farg.ll = arg;
1432
1433 if (unlikely(float64_is_signaling_nan(farg.d))) {
1434 /* sNaN square root */
1435 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1436 }
1437 f32 = float64_to_float32(farg.d, &env->fp_status);
1438 farg.d = float32_to_float64(f32, &env->fp_status);
1439
1440 return farg.ll;
1441 }
1442
1443 /* fsqrt - fsqrt. */
1444 uint64_t helper_fsqrt (uint64_t arg)
1445 {
1446 CPU_DoubleU farg;
1447 farg.ll = arg;
1448
1449 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1450 /* Square root of a negative nonzero number */
1451 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1452 } else {
1453 if (unlikely(float64_is_signaling_nan(farg.d))) {
1454 /* sNaN square root */
1455 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1456 }
1457 farg.d = float64_sqrt(farg.d, &env->fp_status);
1458 }
1459 return farg.ll;
1460 }
1461
1462 /* fre - fre. */
1463 uint64_t helper_fre (uint64_t arg)
1464 {
1465 CPU_DoubleU farg;
1466 farg.ll = arg;
1467
1468 if (unlikely(float64_is_signaling_nan(farg.d))) {
1469 /* sNaN reciprocal */
1470 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1471 }
1472 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1473 return farg.d;
1474 }
1475
1476 /* fres - fres. */
1477 uint64_t helper_fres (uint64_t arg)
1478 {
1479 CPU_DoubleU farg;
1480 float32 f32;
1481 farg.ll = arg;
1482
1483 if (unlikely(float64_is_signaling_nan(farg.d))) {
1484 /* sNaN reciprocal */
1485 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1486 }
1487 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1488 f32 = float64_to_float32(farg.d, &env->fp_status);
1489 farg.d = float32_to_float64(f32, &env->fp_status);
1490
1491 return farg.ll;
1492 }
1493
1494 /* frsqrte - frsqrte. */
1495 uint64_t helper_frsqrte (uint64_t arg)
1496 {
1497 CPU_DoubleU farg;
1498 float32 f32;
1499 farg.ll = arg;
1500
1501 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1502 /* Reciprocal square root of a negative nonzero number */
1503 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1504 } else {
1505 if (unlikely(float64_is_signaling_nan(farg.d))) {
1506 /* sNaN reciprocal square root */
1507 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1508 }
1509 farg.d = float64_sqrt(farg.d, &env->fp_status);
1510 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1511 f32 = float64_to_float32(farg.d, &env->fp_status);
1512 farg.d = float32_to_float64(f32, &env->fp_status);
1513 }
1514 return farg.ll;
1515 }
1516
1517 /* fsel - fsel. */
1518 uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1519 {
1520 CPU_DoubleU farg1;
1521
1522 farg1.ll = arg1;
1523
1524 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
1525 return arg2;
1526 } else {
1527 return arg3;
1528 }
1529 }
1530
1531 void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1532 {
1533 CPU_DoubleU farg1, farg2;
1534 uint32_t ret = 0;
1535 farg1.ll = arg1;
1536 farg2.ll = arg2;
1537
1538 if (unlikely(float64_is_any_nan(farg1.d) ||
1539 float64_is_any_nan(farg2.d))) {
1540 ret = 0x01UL;
1541 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1542 ret = 0x08UL;
1543 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1544 ret = 0x04UL;
1545 } else {
1546 ret = 0x02UL;
1547 }
1548
1549 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1550 env->fpscr |= ret << FPSCR_FPRF;
1551 env->crf[crfD] = ret;
1552 if (unlikely(ret == 0x01UL
1553 && (float64_is_signaling_nan(farg1.d) ||
1554 float64_is_signaling_nan(farg2.d)))) {
1555 /* sNaN comparison */
1556 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1557 }
1558 }
1559
1560 void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1561 {
1562 CPU_DoubleU farg1, farg2;
1563 uint32_t ret = 0;
1564 farg1.ll = arg1;
1565 farg2.ll = arg2;
1566
1567 if (unlikely(float64_is_any_nan(farg1.d) ||
1568 float64_is_any_nan(farg2.d))) {
1569 ret = 0x01UL;
1570 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1571 ret = 0x08UL;
1572 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1573 ret = 0x04UL;
1574 } else {
1575 ret = 0x02UL;
1576 }
1577
1578 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1579 env->fpscr |= ret << FPSCR_FPRF;
1580 env->crf[crfD] = ret;
1581 if (unlikely (ret == 0x01UL)) {
1582 if (float64_is_signaling_nan(farg1.d) ||
1583 float64_is_signaling_nan(farg2.d)) {
1584 /* sNaN comparison */
1585 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1586 POWERPC_EXCP_FP_VXVC);
1587 } else {
1588 /* qNaN comparison */
1589 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1590 }
1591 }
1592 }
1593
1594 #if !defined (CONFIG_USER_ONLY)
1595 void helper_store_msr (target_ulong val)
1596 {
1597 val = hreg_store_msr(env, val, 0);
1598 if (val != 0) {
1599 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1600 helper_raise_exception(val);
1601 }
1602 }
1603
1604 static inline void do_rfi(target_ulong nip, target_ulong msr,
1605 target_ulong msrm, int keep_msrh)
1606 {
1607 #if defined(TARGET_PPC64)
1608 if (msr & (1ULL << MSR_SF)) {
1609 nip = (uint64_t)nip;
1610 msr &= (uint64_t)msrm;
1611 } else {
1612 nip = (uint32_t)nip;
1613 msr = (uint32_t)(msr & msrm);
1614 if (keep_msrh)
1615 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1616 }
1617 #else
1618 nip = (uint32_t)nip;
1619 msr &= (uint32_t)msrm;
1620 #endif
1621 /* XXX: beware: this is false if VLE is supported */
1622 env->nip = nip & ~((target_ulong)0x00000003);
1623 hreg_store_msr(env, msr, 1);
1624 #if defined (DEBUG_OP)
1625 cpu_dump_rfi(env->nip, env->msr);
1626 #endif
1627 /* No need to raise an exception here,
1628 * as rfi is always the last insn of a TB
1629 */
1630 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1631 }
1632
1633 void helper_rfi (void)
1634 {
1635 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1636 ~((target_ulong)0x783F0000), 1);
1637 }
1638
1639 #if defined(TARGET_PPC64)
1640 void helper_rfid (void)
1641 {
1642 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1643 ~((target_ulong)0x783F0000), 0);
1644 }
1645
1646 void helper_hrfid (void)
1647 {
1648 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1649 ~((target_ulong)0x783F0000), 0);
1650 }
1651 #endif
1652 #endif
1653
1654 void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1655 {
1656 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1657 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1658 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1659 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1660 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1661 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1662 }
1663 }
1664
1665 #if defined(TARGET_PPC64)
1666 void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1667 {
1668 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1669 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1670 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1671 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1672 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1673 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1674 }
1675 #endif
1676
1677 /*****************************************************************************/
1678 /* PowerPC 601 specific instructions (POWER bridge) */
1679
1680 target_ulong helper_clcs (uint32_t arg)
1681 {
1682 switch (arg) {
1683 case 0x0CUL:
1684 /* Instruction cache line size */
1685 return env->icache_line_size;
1686 break;
1687 case 0x0DUL:
1688 /* Data cache line size */
1689 return env->dcache_line_size;
1690 break;
1691 case 0x0EUL:
1692 /* Minimum cache line size */
1693 return (env->icache_line_size < env->dcache_line_size) ?
1694 env->icache_line_size : env->dcache_line_size;
1695 break;
1696 case 0x0FUL:
1697 /* Maximum cache line size */
1698 return (env->icache_line_size > env->dcache_line_size) ?
1699 env->icache_line_size : env->dcache_line_size;
1700 break;
1701 default:
1702 /* Undefined */
1703 return 0;
1704 break;
1705 }
1706 }
1707
1708 target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1709 {
1710 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1711
1712 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1713 (int32_t)arg2 == 0) {
1714 env->spr[SPR_MQ] = 0;
1715 return INT32_MIN;
1716 } else {
1717 env->spr[SPR_MQ] = tmp % arg2;
1718 return tmp / (int32_t)arg2;
1719 }
1720 }
1721
1722 target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1723 {
1724 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1725
1726 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1727 (int32_t)arg2 == 0) {
1728 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1729 env->spr[SPR_MQ] = 0;
1730 return INT32_MIN;
1731 } else {
1732 env->spr[SPR_MQ] = tmp % arg2;
1733 tmp /= (int32_t)arg2;
1734 if ((int32_t)tmp != tmp) {
1735 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1736 } else {
1737 env->xer &= ~(1 << XER_OV);
1738 }
1739 return tmp;
1740 }
1741 }
1742
1743 target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1744 {
1745 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1746 (int32_t)arg2 == 0) {
1747 env->spr[SPR_MQ] = 0;
1748 return INT32_MIN;
1749 } else {
1750 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1751 return (int32_t)arg1 / (int32_t)arg2;
1752 }
1753 }
1754
1755 target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1756 {
1757 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1758 (int32_t)arg2 == 0) {
1759 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1760 env->spr[SPR_MQ] = 0;
1761 return INT32_MIN;
1762 } else {
1763 env->xer &= ~(1 << XER_OV);
1764 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1765 return (int32_t)arg1 / (int32_t)arg2;
1766 }
1767 }
1768
1769 #if !defined (CONFIG_USER_ONLY)
1770 target_ulong helper_rac (target_ulong addr)
1771 {
1772 mmu_ctx_t ctx;
1773 int nb_BATs;
1774 target_ulong ret = 0;
1775
1776 /* We don't have to generate many instances of this instruction,
1777 * as rac is supervisor only.
1778 */
1779 /* XXX: FIX THIS: Pretend we have no BAT */
1780 nb_BATs = env->nb_BATs;
1781 env->nb_BATs = 0;
1782 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1783 ret = ctx.raddr;
1784 env->nb_BATs = nb_BATs;
1785 return ret;
1786 }
1787
1788 void helper_rfsvc (void)
1789 {
1790 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1791 }
1792 #endif
1793
1794 /*****************************************************************************/
1795 /* 602 specific instructions */
1796 /* mfrom is the most crazy instruction ever seen, imho ! */
1797 /* Real implementation uses a ROM table. Do the same */
1798 /* Extremely decomposed:
1799 * -arg / 256
1800 * return 256 * log10(10 + 1.0) + 0.5
1801 */
1802 #if !defined (CONFIG_USER_ONLY)
1803 target_ulong helper_602_mfrom (target_ulong arg)
1804 {
1805 if (likely(arg < 602)) {
1806 #include "mfrom_table.c"
1807 return mfrom_ROM_table[arg];
1808 } else {
1809 return 0;
1810 }
1811 }
1812 #endif
1813
1814 /*****************************************************************************/
1815 /* Embedded PowerPC specific helpers */
1816
1817 /* XXX: to be improved to check access rights when in user-mode */
1818 target_ulong helper_load_dcr (target_ulong dcrn)
1819 {
1820 uint32_t val = 0;
1821
1822 if (unlikely(env->dcr_env == NULL)) {
1823 qemu_log("No DCR environment\n");
1824 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1825 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1826 } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1827 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1828 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1829 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1830 }
1831 return val;
1832 }
1833
1834 void helper_store_dcr (target_ulong dcrn, target_ulong val)
1835 {
1836 if (unlikely(env->dcr_env == NULL)) {
1837 qemu_log("No DCR environment\n");
1838 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1839 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1840 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1841 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1842 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1843 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1844 }
1845 }
1846
1847 #if !defined(CONFIG_USER_ONLY)
1848 void helper_40x_rfci (void)
1849 {
1850 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1851 ~((target_ulong)0xFFFF0000), 0);
1852 }
1853
1854 void helper_rfci (void)
1855 {
1856 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1857 ~((target_ulong)0x3FFF0000), 0);
1858 }
1859
1860 void helper_rfdi (void)
1861 {
1862 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1863 ~((target_ulong)0x3FFF0000), 0);
1864 }
1865
1866 void helper_rfmci (void)
1867 {
1868 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1869 ~((target_ulong)0x3FFF0000), 0);
1870 }
1871 #endif
1872
1873 /* 440 specific */
1874 target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1875 {
1876 target_ulong mask;
1877 int i;
1878
1879 i = 1;
1880 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1881 if ((high & mask) == 0) {
1882 if (update_Rc) {
1883 env->crf[0] = 0x4;
1884 }
1885 goto done;
1886 }
1887 i++;
1888 }
1889 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1890 if ((low & mask) == 0) {
1891 if (update_Rc) {
1892 env->crf[0] = 0x8;
1893 }
1894 goto done;
1895 }
1896 i++;
1897 }
1898 if (update_Rc) {
1899 env->crf[0] = 0x2;
1900 }
1901 done:
1902 env->xer = (env->xer & ~0x7F) | i;
1903 if (update_Rc) {
1904 env->crf[0] |= xer_so;
1905 }
1906 return i;
1907 }
1908
1909 /*****************************************************************************/
1910 /* Altivec extension helpers */
1911 #if defined(HOST_WORDS_BIGENDIAN)
1912 #define HI_IDX 0
1913 #define LO_IDX 1
1914 #else
1915 #define HI_IDX 1
1916 #define LO_IDX 0
1917 #endif
1918
1919 #if defined(HOST_WORDS_BIGENDIAN)
1920 #define VECTOR_FOR_INORDER_I(index, element) \
1921 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1922 #else
1923 #define VECTOR_FOR_INORDER_I(index, element) \
1924 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1925 #endif
1926
1927 /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1928 * execute the following block. */
1929 #define DO_HANDLE_NAN(result, x) \
1930 if (float32_is_any_nan(x)) { \
1931 CPU_FloatU __f; \
1932 __f.f = x; \
1933 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1934 result = __f.f; \
1935 } else
1936
1937 #define HANDLE_NAN1(result, x) \
1938 DO_HANDLE_NAN(result, x)
1939 #define HANDLE_NAN2(result, x, y) \
1940 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1941 #define HANDLE_NAN3(result, x, y, z) \
1942 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1943
1944 /* Saturating arithmetic helpers. */
1945 #define SATCVT(from, to, from_type, to_type, min, max) \
1946 static inline to_type cvt##from##to(from_type x, int *sat) \
1947 { \
1948 to_type r; \
1949 if (x < (from_type)min) { \
1950 r = min; \
1951 *sat = 1; \
1952 } else if (x > (from_type)max) { \
1953 r = max; \
1954 *sat = 1; \
1955 } else { \
1956 r = x; \
1957 } \
1958 return r; \
1959 }
1960 #define SATCVTU(from, to, from_type, to_type, min, max) \
1961 static inline to_type cvt##from##to(from_type x, int *sat) \
1962 { \
1963 to_type r; \
1964 if (x > (from_type)max) { \
1965 r = max; \
1966 *sat = 1; \
1967 } else { \
1968 r = x; \
1969 } \
1970 return r; \
1971 }
1972 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1973 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1974 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1975
1976 SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1977 SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1978 SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1979 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1980 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1981 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
1982 #undef SATCVT
1983 #undef SATCVTU
1984
1985 #define LVE(name, access, swap, element) \
1986 void helper_##name (ppc_avr_t *r, target_ulong addr) \
1987 { \
1988 size_t n_elems = ARRAY_SIZE(r->element); \
1989 int adjust = HI_IDX*(n_elems-1); \
1990 int sh = sizeof(r->element[0]) >> 1; \
1991 int index = (addr & 0xf) >> sh; \
1992 if(msr_le) { \
1993 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
1994 } else { \
1995 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
1996 } \
1997 }
1998 #define I(x) (x)
1999 LVE(lvebx, ldub, I, u8)
2000 LVE(lvehx, lduw, bswap16, u16)
2001 LVE(lvewx, ldl, bswap32, u32)
2002 #undef I
2003 #undef LVE
2004
2005 void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2006 {
2007 int i, j = (sh & 0xf);
2008
2009 VECTOR_FOR_INORDER_I (i, u8) {
2010 r->u8[i] = j++;
2011 }
2012 }
2013
2014 void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2015 {
2016 int i, j = 0x10 - (sh & 0xf);
2017
2018 VECTOR_FOR_INORDER_I (i, u8) {
2019 r->u8[i] = j++;
2020 }
2021 }
2022
2023 #define STVE(name, access, swap, element) \
2024 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2025 { \
2026 size_t n_elems = ARRAY_SIZE(r->element); \
2027 int adjust = HI_IDX*(n_elems-1); \
2028 int sh = sizeof(r->element[0]) >> 1; \
2029 int index = (addr & 0xf) >> sh; \
2030 if(msr_le) { \
2031 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2032 } else { \
2033 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2034 } \
2035 }
2036 #define I(x) (x)
2037 STVE(stvebx, stb, I, u8)
2038 STVE(stvehx, stw, bswap16, u16)
2039 STVE(stvewx, stl, bswap32, u32)
2040 #undef I
2041 #undef LVE
2042
2043 void helper_mtvscr (ppc_avr_t *r)
2044 {
2045 #if defined(HOST_WORDS_BIGENDIAN)
2046 env->vscr = r->u32[3];
2047 #else
2048 env->vscr = r->u32[0];
2049 #endif
2050 set_flush_to_zero(vscr_nj, &env->vec_status);
2051 }
2052
2053 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2054 {
2055 int i;
2056 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2057 r->u32[i] = ~a->u32[i] < b->u32[i];
2058 }
2059 }
2060
2061 #define VARITH_DO(name, op, element) \
2062 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2063 { \
2064 int i; \
2065 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2066 r->element[i] = a->element[i] op b->element[i]; \
2067 } \
2068 }
2069 #define VARITH(suffix, element) \
2070 VARITH_DO(add##suffix, +, element) \
2071 VARITH_DO(sub##suffix, -, element)
2072 VARITH(ubm, u8)
2073 VARITH(uhm, u16)
2074 VARITH(uwm, u32)
2075 #undef VARITH_DO
2076 #undef VARITH
2077
2078 #define VARITHFP(suffix, func) \
2079 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2080 { \
2081 int i; \
2082 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2083 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2084 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2085 } \
2086 } \
2087 }
2088 VARITHFP(addfp, float32_add)
2089 VARITHFP(subfp, float32_sub)
2090 #undef VARITHFP
2091
2092 #define VARITHSAT_CASE(type, op, cvt, element) \
2093 { \
2094 type result = (type)a->element[i] op (type)b->element[i]; \
2095 r->element[i] = cvt(result, &sat); \
2096 }
2097
2098 #define VARITHSAT_DO(name, op, optype, cvt, element) \
2099 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2100 { \
2101 int sat = 0; \
2102 int i; \
2103 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2104 switch (sizeof(r->element[0])) { \
2105 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2106 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2107 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2108 } \
2109 } \
2110 if (sat) { \
2111 env->vscr |= (1 << VSCR_SAT); \
2112 } \
2113 }
2114 #define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2115 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2116 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2117 #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2118 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2119 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2120 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2121 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2122 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2123 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2124 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2125 VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2126 #undef VARITHSAT_CASE
2127 #undef VARITHSAT_DO
2128 #undef VARITHSAT_SIGNED
2129 #undef VARITHSAT_UNSIGNED
2130
2131 #define VAVG_DO(name, element, etype) \
2132 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2133 { \
2134 int i; \
2135 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2136 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2137 r->element[i] = x >> 1; \
2138 } \
2139 }
2140
2141 #define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2142 VAVG_DO(avgs##type, signed_element, signed_type) \
2143 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2144 VAVG(b, s8, int16_t, u8, uint16_t)
2145 VAVG(h, s16, int32_t, u16, uint32_t)
2146 VAVG(w, s32, int64_t, u32, uint64_t)
2147 #undef VAVG_DO
2148 #undef VAVG
2149
2150 #define VCF(suffix, cvt, element) \
2151 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2152 { \
2153 int i; \
2154 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2155 float32 t = cvt(b->element[i], &env->vec_status); \
2156 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2157 } \
2158 }
2159 VCF(ux, uint32_to_float32, u32)
2160 VCF(sx, int32_to_float32, s32)
2161 #undef VCF
2162
2163 #define VCMP_DO(suffix, compare, element, record) \
2164 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2165 { \
2166 uint32_t ones = (uint32_t)-1; \
2167 uint32_t all = ones; \
2168 uint32_t none = 0; \
2169 int i; \
2170 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2171 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2172 switch (sizeof (a->element[0])) { \
2173 case 4: r->u32[i] = result; break; \
2174 case 2: r->u16[i] = result; break; \
2175 case 1: r->u8[i] = result; break; \
2176 } \
2177 all &= result; \
2178 none |= result; \
2179 } \
2180 if (record) { \
2181 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2182 } \
2183 }
2184 #define VCMP(suffix, compare, element) \
2185 VCMP_DO(suffix, compare, element, 0) \
2186 VCMP_DO(suffix##_dot, compare, element, 1)
2187 VCMP(equb, ==, u8)
2188 VCMP(equh, ==, u16)
2189 VCMP(equw, ==, u32)
2190 VCMP(gtub, >, u8)
2191 VCMP(gtuh, >, u16)
2192 VCMP(gtuw, >, u32)
2193 VCMP(gtsb, >, s8)
2194 VCMP(gtsh, >, s16)
2195 VCMP(gtsw, >, s32)
2196 #undef VCMP_DO
2197 #undef VCMP
2198
2199 #define VCMPFP_DO(suffix, compare, order, record) \
2200 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2201 { \
2202 uint32_t ones = (uint32_t)-1; \
2203 uint32_t all = ones; \
2204 uint32_t none = 0; \
2205 int i; \
2206 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2207 uint32_t result; \
2208 int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2209 if (rel == float_relation_unordered) { \
2210 result = 0; \
2211 } else if (rel compare order) { \
2212 result = ones; \
2213 } else { \
2214 result = 0; \
2215 } \
2216 r->u32[i] = result; \
2217 all &= result; \
2218 none |= result; \
2219 } \
2220 if (record) { \
2221 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2222 } \
2223 }
2224 #define VCMPFP(suffix, compare, order) \
2225 VCMPFP_DO(suffix, compare, order, 0) \
2226 VCMPFP_DO(suffix##_dot, compare, order, 1)
2227 VCMPFP(eqfp, ==, float_relation_equal)
2228 VCMPFP(gefp, !=, float_relation_less)
2229 VCMPFP(gtfp, ==, float_relation_greater)
2230 #undef VCMPFP_DO
2231 #undef VCMPFP
2232
2233 static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
2234 int record)
2235 {
2236 int i;
2237 int all_in = 0;
2238 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2239 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2240 if (le_rel == float_relation_unordered) {
2241 r->u32[i] = 0xc0000000;
2242 /* ALL_IN does not need to be updated here. */
2243 } else {
2244 float32 bneg = float32_chs(b->f[i]);
2245 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2246 int le = le_rel != float_relation_greater;
2247 int ge = ge_rel != float_relation_less;
2248 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2249 all_in |= (!le | !ge);
2250 }
2251 }
2252 if (record) {
2253 env->crf[6] = (all_in == 0) << 1;
2254 }
2255 }
2256
2257 void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2258 {
2259 vcmpbfp_internal(r, a, b, 0);
2260 }
2261
2262 void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2263 {
2264 vcmpbfp_internal(r, a, b, 1);
2265 }
2266
2267 #define VCT(suffix, satcvt, element) \
2268 void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2269 { \
2270 int i; \
2271 int sat = 0; \
2272 float_status s = env->vec_status; \
2273 set_float_rounding_mode(float_round_to_zero, &s); \
2274 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2275 if (float32_is_any_nan(b->f[i])) { \
2276 r->element[i] = 0; \
2277 } else { \
2278 float64 t = float32_to_float64(b->f[i], &s); \
2279 int64_t j; \
2280 t = float64_scalbn(t, uim, &s); \
2281 j = float64_to_int64(t, &s); \
2282 r->element[i] = satcvt(j, &sat); \
2283 } \
2284 } \
2285 if (sat) { \
2286 env->vscr |= (1 << VSCR_SAT); \
2287 } \
2288 }
2289 VCT(uxs, cvtsduw, u32)
2290 VCT(sxs, cvtsdsw, s32)
2291 #undef VCT
2292
2293 void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2294 {
2295 int i;
2296 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2297 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2298 /* Need to do the computation in higher precision and round
2299 * once at the end. */
2300 float64 af, bf, cf, t;
2301 af = float32_to_float64(a->f[i], &env->vec_status);
2302 bf = float32_to_float64(b->f[i], &env->vec_status);
2303 cf = float32_to_float64(c->f[i], &env->vec_status);
2304 t = float64_mul(af, cf, &env->vec_status);
2305 t = float64_add(t, bf, &env->vec_status);
2306 r->f[i] = float64_to_float32(t, &env->vec_status);
2307 }
2308 }
2309 }
2310
2311 void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2312 {
2313 int sat = 0;
2314 int i;
2315
2316 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2317 int32_t prod = a->s16[i] * b->s16[i];
2318 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2319 r->s16[i] = cvtswsh (t, &sat);
2320 }
2321
2322 if (sat) {
2323 env->vscr |= (1 << VSCR_SAT);
2324 }
2325 }
2326
2327 void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2328 {
2329 int sat = 0;
2330 int i;
2331
2332 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2333 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2334 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2335 r->s16[i] = cvtswsh (t, &sat);
2336 }
2337
2338 if (sat) {
2339 env->vscr |= (1 << VSCR_SAT);
2340 }
2341 }
2342
2343 #define VMINMAX_DO(name, compare, element) \
2344 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2345 { \
2346 int i; \
2347 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2348 if (a->element[i] compare b->element[i]) { \
2349 r->element[i] = b->element[i]; \
2350 } else { \
2351 r->element[i] = a->element[i]; \
2352 } \
2353 } \
2354 }
2355 #define VMINMAX(suffix, element) \
2356 VMINMAX_DO(min##suffix, >, element) \
2357 VMINMAX_DO(max##suffix, <, element)
2358 VMINMAX(sb, s8)
2359 VMINMAX(sh, s16)
2360 VMINMAX(sw, s32)
2361 VMINMAX(ub, u8)
2362 VMINMAX(uh, u16)
2363 VMINMAX(uw, u32)
2364 #undef VMINMAX_DO
2365 #undef VMINMAX
2366
2367 #define VMINMAXFP(suffix, rT, rF) \
2368 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2369 { \
2370 int i; \
2371 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2372 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2373 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2374 r->f[i] = rT->f[i]; \
2375 } else { \
2376 r->f[i] = rF->f[i]; \
2377 } \
2378 } \
2379 } \
2380 }
2381 VMINMAXFP(minfp, a, b)
2382 VMINMAXFP(maxfp, b, a)
2383 #undef VMINMAXFP
2384
2385 void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2386 {
2387 int i;
2388 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2389 int32_t prod = a->s16[i] * b->s16[i];
2390 r->s16[i] = (int16_t) (prod + c->s16[i]);
2391 }
2392 }
2393
2394 #define VMRG_DO(name, element, highp) \
2395 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2396 { \
2397 ppc_avr_t result; \
2398 int i; \
2399 size_t n_elems = ARRAY_SIZE(r->element); \
2400 for (i = 0; i < n_elems/2; i++) { \
2401 if (highp) { \
2402 result.element[i*2+HI_IDX] = a->element[i]; \
2403 result.element[i*2+LO_IDX] = b->element[i]; \
2404 } else { \
2405 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2406 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2407 } \
2408 } \
2409 *r = result; \
2410 }
2411 #if defined(HOST_WORDS_BIGENDIAN)
2412 #define MRGHI 0
2413 #define MRGLO 1
2414 #else
2415 #define MRGHI 1
2416 #define MRGLO 0
2417 #endif
2418 #define VMRG(suffix, element) \
2419 VMRG_DO(mrgl##suffix, element, MRGHI) \
2420 VMRG_DO(mrgh##suffix, element, MRGLO)
2421 VMRG(b, u8)
2422 VMRG(h, u16)
2423 VMRG(w, u32)
2424 #undef VMRG_DO
2425 #undef VMRG
2426 #undef MRGHI
2427 #undef MRGLO
2428
2429 void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2430 {
2431 int32_t prod[16];
2432 int i;
2433
2434 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2435 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2436 }
2437
2438 VECTOR_FOR_INORDER_I(i, s32) {
2439 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2440 }
2441 }
2442
2443 void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2444 {
2445 int32_t prod[8];
2446 int i;
2447
2448 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2449 prod[i] = a->s16[i] * b->s16[i];
2450 }
2451
2452 VECTOR_FOR_INORDER_I(i, s32) {
2453 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2454 }
2455 }
2456
2457 void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2458 {
2459 int32_t prod[8];
2460 int i;
2461 int sat = 0;
2462
2463 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2464 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2465 }
2466
2467 VECTOR_FOR_INORDER_I (i, s32) {
2468 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2469 r->u32[i] = cvtsdsw(t, &sat);
2470 }
2471
2472 if (sat) {
2473 env->vscr |= (1 << VSCR_SAT);
2474 }
2475 }
2476
2477 void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2478 {
2479 uint16_t prod[16];
2480 int i;
2481
2482 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2483 prod[i] = a->u8[i] * b->u8[i];
2484 }
2485
2486 VECTOR_FOR_INORDER_I(i, u32) {
2487 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2488 }
2489 }
2490
2491 void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2492 {
2493 uint32_t prod[8];
2494 int i;
2495
2496 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2497 prod[i] = a->u16[i] * b->u16[i];
2498 }
2499
2500 VECTOR_FOR_INORDER_I(i, u32) {
2501 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2502 }
2503 }
2504
2505 void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2506 {
2507 uint32_t prod[8];
2508 int i;
2509 int sat = 0;
2510
2511 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2512 prod[i] = a->u16[i] * b->u16[i];
2513 }
2514
2515 VECTOR_FOR_INORDER_I (i, s32) {
2516 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2517 r->u32[i] = cvtuduw(t, &sat);
2518 }
2519
2520 if (sat) {
2521 env->vscr |= (1 << VSCR_SAT);
2522 }
2523 }
2524
2525 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2526 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2527 { \
2528 int i; \
2529 VECTOR_FOR_INORDER_I(i, prod_element) { \
2530 if (evenp) { \
2531 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2532 } else { \
2533 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2534 } \
2535 } \
2536 }
2537 #define VMUL(suffix, mul_element, prod_element) \
2538 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2539 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2540 VMUL(sb, s8, s16)
2541 VMUL(sh, s16, s32)
2542 VMUL(ub, u8, u16)
2543 VMUL(uh, u16, u32)
2544 #undef VMUL_DO
2545 #undef VMUL
2546
2547 void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2548 {
2549 int i;
2550 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2551 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2552 /* Need to do the computation is higher precision and round
2553 * once at the end. */
2554 float64 af, bf, cf, t;
2555 af = float32_to_float64(a->f[i], &env->vec_status);
2556 bf = float32_to_float64(b->f[i], &env->vec_status);
2557 cf = float32_to_float64(c->f[i], &env->vec_status);
2558 t = float64_mul(af, cf, &env->vec_status);
2559 t = float64_sub(t, bf, &env->vec_status);
2560 t = float64_chs(t);
2561 r->f[i] = float64_to_float32(t, &env->vec_status);
2562 }
2563 }
2564 }
2565
2566 void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2567 {
2568 ppc_avr_t result;
2569 int i;
2570 VECTOR_FOR_INORDER_I (i, u8) {
2571 int s = c->u8[i] & 0x1f;
2572 #if defined(HOST_WORDS_BIGENDIAN)
2573 int index = s & 0xf;
2574 #else
2575 int index = 15 - (s & 0xf);
2576 #endif
2577 if (s & 0x10) {
2578 result.u8[i] = b->u8[index];
2579 } else {
2580 result.u8[i] = a->u8[index];
2581 }
2582 }
2583 *r = result;
2584 }
2585
2586 #if defined(HOST_WORDS_BIGENDIAN)
2587 #define PKBIG 1
2588 #else
2589 #define PKBIG 0
2590 #endif
2591 void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2592 {
2593 int i, j;
2594 ppc_avr_t result;
2595 #if defined(HOST_WORDS_BIGENDIAN)
2596 const ppc_avr_t *x[2] = { a, b };
2597 #else
2598 const ppc_avr_t *x[2] = { b, a };
2599 #endif
2600
2601 VECTOR_FOR_INORDER_I (i, u64) {
2602 VECTOR_FOR_INORDER_I (j, u32){
2603 uint32_t e = x[i]->u32[j];
2604 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2605 ((e >> 6) & 0x3e0) |
2606 ((e >> 3) & 0x1f));
2607 }
2608 }
2609 *r = result;
2610 }
2611
2612 #define VPK(suffix, from, to, cvt, dosat) \
2613 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2614 { \
2615 int i; \
2616 int sat = 0; \
2617 ppc_avr_t result; \
2618 ppc_avr_t *a0 = PKBIG ? a : b; \
2619 ppc_avr_t *a1 = PKBIG ? b : a; \
2620 VECTOR_FOR_INORDER_I (i, from) { \
2621 result.to[i] = cvt(a0->from[i], &sat); \
2622 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2623 } \
2624 *r = result; \
2625 if (dosat && sat) { \
2626 env->vscr |= (1 << VSCR_SAT); \
2627 } \
2628 }
2629 #define I(x, y) (x)
2630 VPK(shss, s16, s8, cvtshsb, 1)
2631 VPK(shus, s16, u8, cvtshub, 1)
2632 VPK(swss, s32, s16, cvtswsh, 1)
2633 VPK(swus, s32, u16, cvtswuh, 1)
2634 VPK(uhus, u16, u8, cvtuhub, 1)
2635 VPK(uwus, u32, u16, cvtuwuh, 1)
2636 VPK(uhum, u16, u8, I, 0)
2637 VPK(uwum, u32, u16, I, 0)
2638 #undef I
2639 #undef VPK
2640 #undef PKBIG
2641
2642 void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
2643 {
2644 int i;
2645 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2646 HANDLE_NAN1(r->f[i], b->f[i]) {
2647 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2648 }
2649 }
2650 }
2651
2652 #define VRFI(suffix, rounding) \
2653 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2654 { \
2655 int i; \
2656 float_status s = env->vec_status; \
2657 set_float_rounding_mode(rounding, &s); \
2658 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2659 HANDLE_NAN1(r->f[i], b->f[i]) { \
2660 r->f[i] = float32_round_to_int (b->f[i], &s); \
2661 } \
2662 } \
2663 }
2664 VRFI(n, float_round_nearest_even)
2665 VRFI(m, float_round_down)
2666 VRFI(p, float_round_up)
2667 VRFI(z, float_round_to_zero)
2668 #undef VRFI
2669
2670 #define VROTATE(suffix, element) \
2671 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2672 { \
2673 int i; \
2674 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2675 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2676 unsigned int shift = b->element[i] & mask; \
2677 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2678 } \
2679 }
2680 VROTATE(b, u8)
2681 VROTATE(h, u16)
2682 VROTATE(w, u32)
2683 #undef VROTATE
2684
2685 void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
2686 {
2687 int i;
2688 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2689 HANDLE_NAN1(r->f[i], b->f[i]) {
2690 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2691 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2692 }
2693 }
2694 }
2695
2696 void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2697 {
2698 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2699 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2700 }
2701
2702 void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2703 {
2704 int i;
2705 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2706 HANDLE_NAN1(r->f[i], b->f[i]) {
2707 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2708 }
2709 }
2710 }
2711
2712 void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2713 {
2714 int i;
2715 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2716 HANDLE_NAN1(r->f[i], b->f[i]) {
2717 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2718 }
2719 }
2720 }
2721
2722 #if defined(HOST_WORDS_BIGENDIAN)
2723 #define LEFT 0
2724 #define RIGHT 1
2725 #else
2726 #define LEFT 1
2727 #define RIGHT 0
2728 #endif
2729 /* The specification says that the results are undefined if all of the
2730 * shift counts are not identical. We check to make sure that they are
2731 * to conform to what real hardware appears to do. */
2732 #define VSHIFT(suffix, leftp) \
2733 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2734 { \
2735 int shift = b->u8[LO_IDX*15] & 0x7; \
2736 int doit = 1; \
2737 int i; \
2738 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2739 doit = doit && ((b->u8[i] & 0x7) == shift); \
2740 } \
2741 if (doit) { \
2742 if (shift == 0) { \
2743 *r = *a; \
2744 } else if (leftp) { \
2745 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2746 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2747 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2748 } else { \
2749 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2750 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2751 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2752 } \
2753 } \
2754 }
2755 VSHIFT(l, LEFT)
2756 VSHIFT(r, RIGHT)
2757 #undef VSHIFT
2758 #undef LEFT
2759 #undef RIGHT
2760
2761 #define VSL(suffix, element) \
2762 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2763 { \
2764 int i; \
2765 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2766 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2767 unsigned int shift = b->element[i] & mask; \
2768 r->element[i] = a->element[i] << shift; \
2769 } \
2770 }
2771 VSL(b, u8)
2772 VSL(h, u16)
2773 VSL(w, u32)
2774 #undef VSL
2775
2776 void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2777 {
2778 int sh = shift & 0xf;
2779 int i;
2780 ppc_avr_t result;
2781
2782 #if defined(HOST_WORDS_BIGENDIAN)
2783 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2784 int index = sh + i;
2785 if (index > 0xf) {
2786 result.u8[i] = b->u8[index-0x10];
2787 } else {
2788 result.u8[i] = a->u8[index];
2789 }
2790 }
2791 #else
2792 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2793 int index = (16 - sh) + i;
2794 if (index > 0xf) {
2795 result.u8[i] = a->u8[index-0x10];
2796 } else {
2797 result.u8[i] = b->u8[index];
2798 }
2799 }
2800 #endif
2801 *r = result;
2802 }
2803
2804 void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2805 {
2806 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2807
2808 #if defined (HOST_WORDS_BIGENDIAN)
2809 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2810 memset (&r->u8[16-sh], 0, sh);
2811 #else
2812 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2813 memset (&r->u8[0], 0, sh);
2814 #endif
2815 }
2816
2817 /* Experimental testing shows that hardware masks the immediate. */
2818 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2819 #if defined(HOST_WORDS_BIGENDIAN)
2820 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2821 #else
2822 #define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2823 #endif
2824 #define VSPLT(suffix, element) \
2825 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2826 { \
2827 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2828 int i; \
2829 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2830 r->element[i] = s; \
2831 } \
2832 }
2833 VSPLT(b, u8)
2834 VSPLT(h, u16)
2835 VSPLT(w, u32)
2836 #undef VSPLT
2837 #undef SPLAT_ELEMENT
2838 #undef _SPLAT_MASKED
2839
2840 #define VSPLTI(suffix, element, splat_type) \
2841 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2842 { \
2843 splat_type x = (int8_t)(splat << 3) >> 3; \
2844 int i; \
2845 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2846 r->element[i] = x; \
2847 } \
2848 }
2849 VSPLTI(b, s8, int8_t)
2850 VSPLTI(h, s16, int16_t)
2851 VSPLTI(w, s32, int32_t)
2852 #undef VSPLTI
2853
2854 #define VSR(suffix, element) \
2855 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2856 { \
2857 int i; \
2858 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2859 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2860 unsigned int shift = b->element[i] & mask; \
2861 r->element[i] = a->element[i] >> shift; \
2862 } \
2863 }
2864 VSR(ab, s8)
2865 VSR(ah, s16)
2866 VSR(aw, s32)
2867 VSR(b, u8)
2868 VSR(h, u16)
2869 VSR(w, u32)
2870 #undef VSR
2871
2872 void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2873 {
2874 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2875
2876 #if defined (HOST_WORDS_BIGENDIAN)
2877 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2878 memset (&r->u8[0], 0, sh);
2879 #else
2880 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2881 memset (&r->u8[16-sh], 0, sh);
2882 #endif
2883 }
2884
2885 void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2886 {
2887 int i;
2888 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2889 r->u32[i] = a->u32[i] >= b->u32[i];
2890 }
2891 }
2892
2893 void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2894 {
2895 int64_t t;
2896 int i, upper;
2897 ppc_avr_t result;
2898 int sat = 0;
2899
2900 #if defined(HOST_WORDS_BIGENDIAN)
2901 upper = ARRAY_SIZE(r->s32)-1;
2902 #else
2903 upper = 0;
2904 #endif
2905 t = (int64_t)b->s32[upper];
2906 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2907 t += a->s32[i];
2908 result.s32[i] = 0;
2909 }
2910 result.s32[upper] = cvtsdsw(t, &sat);
2911 *r = result;
2912
2913 if (sat) {
2914 env->vscr |= (1 << VSCR_SAT);
2915 }
2916 }
2917
2918 void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2919 {
2920 int i, j, upper;
2921 ppc_avr_t result;
2922 int sat = 0;
2923
2924 #if defined(HOST_WORDS_BIGENDIAN)
2925 upper = 1;
2926 #else
2927 upper = 0;
2928 #endif
2929 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2930 int64_t t = (int64_t)b->s32[upper+i*2];
2931 result.u64[i] = 0;
2932 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2933 t += a->s32[2*i+j];
2934 }
2935 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2936 }
2937
2938 *r = result;
2939 if (sat) {
2940 env->vscr |= (1 << VSCR_SAT);
2941 }
2942 }
2943
2944 void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2945 {
2946 int i, j;
2947 int sat = 0;
2948
2949 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2950 int64_t t = (int64_t)b->s32[i];
2951 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2952 t += a->s8[4*i+j];
2953 }
2954 r->s32[i] = cvtsdsw(t, &sat);
2955 }
2956
2957 if (sat) {
2958 env->vscr |= (1 << VSCR_SAT);
2959 }
2960 }
2961
2962 void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2963 {
2964 int sat = 0;
2965 int i;
2966
2967 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2968 int64_t t = (int64_t)b->s32[i];
2969 t += a->s16[2*i] + a->s16[2*i+1];
2970 r->s32[i] = cvtsdsw(t, &sat);
2971 }
2972
2973 if (sat) {
2974 env->vscr |= (1 << VSCR_SAT);
2975 }
2976 }
2977
2978 void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2979 {
2980 int i, j;
2981 int sat = 0;
2982
2983 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2984 uint64_t t = (uint64_t)b->u32[i];
2985 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2986 t += a->u8[4*i+j];
2987 }
2988 r->u32[i] = cvtuduw(t, &sat);
2989 }
2990
2991 if (sat) {
2992 env->vscr |= (1 << VSCR_SAT);
2993 }
2994 }
2995
2996 #if defined(HOST_WORDS_BIGENDIAN)
2997 #define UPKHI 1
2998 #define UPKLO 0
2999 #else
3000 #define UPKHI 0
3001 #define UPKLO 1
3002 #endif
3003 #define VUPKPX(suffix, hi) \
3004 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
3005 { \
3006 int i; \
3007 ppc_avr_t result; \
3008 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
3009 uint16_t e = b->u16[hi ? i : i+4]; \
3010 uint8_t a = (e >> 15) ? 0xff : 0; \
3011 uint8_t r = (e >> 10) & 0x1f; \
3012 uint8_t g = (e >> 5) & 0x1f; \
3013 uint8_t b = e & 0x1f; \
3014 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3015 } \
3016 *r = result; \
3017 }
3018 VUPKPX(lpx, UPKLO)
3019 VUPKPX(hpx, UPKHI)
3020 #undef VUPKPX
3021
3022 #define VUPK(suffix, unpacked, packee, hi) \
3023 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
3024 { \
3025 int i; \
3026 ppc_avr_t result; \
3027 if (hi) { \
3028 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3029 result.unpacked[i] = b->packee[i]; \
3030 } \
3031 } else { \
3032 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3033 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3034 } \
3035 } \
3036 *r = result; \
3037 }
3038 VUPK(hsb, s16, s8, UPKHI)
3039 VUPK(hsh, s32, s16, UPKHI)
3040 VUPK(lsb, s16, s8, UPKLO)
3041 VUPK(lsh, s32, s16, UPKLO)
3042 #undef VUPK
3043 #undef UPKHI
3044 #undef UPKLO
3045
3046 #undef DO_HANDLE_NAN
3047 #undef HANDLE_NAN1
3048 #undef HANDLE_NAN2
3049 #undef HANDLE_NAN3
3050 #undef VECTOR_FOR_INORDER_I
3051 #undef HI_IDX
3052 #undef LO_IDX
3053
3054 /*****************************************************************************/
3055 /* SPE extension helpers */
3056 /* Use a table to make this quicker */
3057 static uint8_t hbrev[16] = {
3058 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3059 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3060 };
3061
3062 static inline uint8_t byte_reverse(uint8_t val)
3063 {
3064 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3065 }
3066
3067 static inline uint32_t word_reverse(uint32_t val)
3068 {
3069 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3070 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3071 }
3072
3073 #define MASKBITS 16 // Random value - to be fixed (implementation dependent)
3074 target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
3075 {
3076 uint32_t a, b, d, mask;
3077
3078 mask = UINT32_MAX >> (32 - MASKBITS);
3079 a = arg1 & mask;
3080 b = arg2 & mask;
3081 d = word_reverse(1 + word_reverse(a | ~b));
3082 return (arg1 & ~mask) | (d & b);
3083 }
3084
3085 uint32_t helper_cntlsw32 (uint32_t val)
3086 {
3087 if (val & 0x80000000)
3088 return clz32(~val);
3089 else
3090 return clz32(val);
3091 }
3092
3093 uint32_t helper_cntlzw32 (uint32_t val)
3094 {
3095 return clz32(val);
3096 }
3097
3098 /* Single-precision floating-point conversions */
3099 static inline uint32_t efscfsi(uint32_t val)
3100 {
3101 CPU_FloatU u;
3102
3103 u.f = int32_to_float32(val, &env->vec_status);
3104
3105 return u.l;
3106 }
3107
3108 static inline uint32_t efscfui(uint32_t val)
3109 {
3110 CPU_FloatU u;
3111
3112 u.f = uint32_to_float32(val, &env->vec_status);
3113
3114 return u.l;
3115 }
3116
3117 static inline int32_t efsctsi(uint32_t val)
3118 {
3119 CPU_FloatU u;
3120
3121 u.l = val;
3122 /* NaN are not treated the same way IEEE 754 does */
3123 if (unlikely(float32_is_quiet_nan(u.f)))
3124 return 0;
3125
3126 return float32_to_int32(u.f, &env->vec_status);
3127 }
3128
3129 static inline uint32_t efsctui(uint32_t val)
3130 {
3131 CPU_FloatU u;
3132
3133 u.l = val;
3134 /* NaN are not treated the same way IEEE 754 does */
3135 if (unlikely(float32_is_quiet_nan(u.f)))
3136 return 0;
3137
3138 return float32_to_uint32(u.f, &env->vec_status);
3139 }
3140
3141 static inline uint32_t efsctsiz(uint32_t val)
3142 {
3143 CPU_FloatU u;
3144
3145 u.l = val;
3146 /* NaN are not treated the same way IEEE 754 does */
3147 if (unlikely(float32_is_quiet_nan(u.f)))
3148 return 0;
3149
3150 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3151 }
3152
3153 static inline uint32_t efsctuiz(uint32_t val)
3154 {
3155 CPU_FloatU u;
3156
3157 u.l = val;
3158 /* NaN are not treated the same way IEEE 754 does */
3159 if (unlikely(float32_is_quiet_nan(u.f)))
3160 return 0;
3161
3162 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3163 }
3164
3165 static inline uint32_t efscfsf(uint32_t val)
3166 {
3167 CPU_FloatU u;
3168 float32 tmp;
3169
3170 u.f = int32_to_float32(val, &env->vec_status);
3171 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3172 u.f = float32_div(u.f, tmp, &env->vec_status);
3173
3174 return u.l;
3175 }
3176
3177 static inline uint32_t efscfuf(uint32_t val)
3178 {
3179 CPU_FloatU u;
3180 float32 tmp;
3181
3182 u.f = uint32_to_float32(val, &env->vec_status);
3183 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3184 u.f = float32_div(u.f, tmp, &env->vec_status);
3185
3186 return u.l;
3187 }
3188
3189 static inline uint32_t efsctsf(uint32_t val)
3190 {
3191 CPU_FloatU u;
3192 float32 tmp;
3193
3194 u.l = val;
3195 /* NaN are not treated the same way IEEE 754 does */
3196 if (unlikely(float32_is_quiet_nan(u.f)))
3197 return 0;
3198 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3199 u.f = float32_mul(u.f, tmp, &env->vec_status);
3200
3201 return float32_to_int32(u.f, &env->vec_status);
3202 }
3203
3204 static inline uint32_t efsctuf(uint32_t val)
3205 {
3206 CPU_FloatU u;
3207 float32 tmp;
3208
3209 u.l = val;
3210 /* NaN are not treated the same way IEEE 754 does */
3211 if (unlikely(float32_is_quiet_nan(u.f)))
3212 return 0;
3213 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3214 u.f = float32_mul(u.f, tmp, &env->vec_status);
3215
3216 return float32_to_uint32(u.f, &env->vec_status);
3217 }
3218
3219 #define HELPER_SPE_SINGLE_CONV(name) \
3220 uint32_t helper_e##name (uint32_t val) \
3221 { \
3222 return e##name(val); \
3223 }
3224 /* efscfsi */
3225 HELPER_SPE_SINGLE_CONV(fscfsi);
3226 /* efscfui */
3227 HELPER_SPE_SINGLE_CONV(fscfui);
3228 /* efscfuf */
3229 HELPER_SPE_SINGLE_CONV(fscfuf);
3230 /* efscfsf */
3231 HELPER_SPE_SINGLE_CONV(fscfsf);
3232 /* efsctsi */
3233 HELPER_SPE_SINGLE_CONV(fsctsi);
3234 /* efsctui */
3235 HELPER_SPE_SINGLE_CONV(fsctui);
3236 /* efsctsiz */
3237 HELPER_SPE_SINGLE_CONV(fsctsiz);
3238 /* efsctuiz */
3239 HELPER_SPE_SINGLE_CONV(fsctuiz);
3240 /* efsctsf */
3241 HELPER_SPE_SINGLE_CONV(fsctsf);
3242 /* efsctuf */
3243 HELPER_SPE_SINGLE_CONV(fsctuf);
3244
3245 #define HELPER_SPE_VECTOR_CONV(name) \
3246 uint64_t helper_ev##name (uint64_t val) \
3247 { \
3248 return ((uint64_t)e##name(val >> 32) << 32) | \
3249 (uint64_t)e##name(val); \
3250 }
3251 /* evfscfsi */
3252 HELPER_SPE_VECTOR_CONV