]> git.proxmox.com Git - qemu.git/blob - target-ppc/op_helper.c
Use existing helper function to implement popcntd instruction
[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 "exec.h"
21 #include "host-utils.h"
22 #include "helper.h"
23
24 #include "helper_regs.h"
25
26 //#define DEBUG_OP
27 //#define DEBUG_EXCEPTIONS
28 //#define DEBUG_SOFTWARE_TLB
29
30 #ifdef DEBUG_SOFTWARE_TLB
31 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
32 #else
33 # define LOG_SWTLB(...) do { } while (0)
34 #endif
35
36
37 /*****************************************************************************/
38 /* Exceptions processing helpers */
39
40 void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
41 {
42 #if 0
43 printf("Raise exception %3x code : %d\n", exception, error_code);
44 #endif
45 env->exception_index = exception;
46 env->error_code = error_code;
47 cpu_loop_exit();
48 }
49
50 void helper_raise_exception (uint32_t exception)
51 {
52 helper_raise_exception_err(exception, 0);
53 }
54
55 /*****************************************************************************/
56 /* SPR accesses */
57 void helper_load_dump_spr (uint32_t sprn)
58 {
59 qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
60 env->spr[sprn]);
61 }
62
63 void helper_store_dump_spr (uint32_t sprn)
64 {
65 qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
66 env->spr[sprn]);
67 }
68
69 target_ulong helper_load_tbl (void)
70 {
71 return (target_ulong)cpu_ppc_load_tbl(env);
72 }
73
74 target_ulong helper_load_tbu (void)
75 {
76 return cpu_ppc_load_tbu(env);
77 }
78
79 target_ulong helper_load_atbl (void)
80 {
81 return (target_ulong)cpu_ppc_load_atbl(env);
82 }
83
84 target_ulong helper_load_atbu (void)
85 {
86 return cpu_ppc_load_atbu(env);
87 }
88
89 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
90 target_ulong helper_load_purr (void)
91 {
92 return (target_ulong)cpu_ppc_load_purr(env);
93 }
94 #endif
95
96 target_ulong helper_load_601_rtcl (void)
97 {
98 return cpu_ppc601_load_rtcl(env);
99 }
100
101 target_ulong helper_load_601_rtcu (void)
102 {
103 return cpu_ppc601_load_rtcu(env);
104 }
105
106 #if !defined(CONFIG_USER_ONLY)
107 #if defined (TARGET_PPC64)
108 void helper_store_asr (target_ulong val)
109 {
110 ppc_store_asr(env, val);
111 }
112 #endif
113
114 void helper_store_sdr1 (target_ulong val)
115 {
116 ppc_store_sdr1(env, val);
117 }
118
119 void helper_store_tbl (target_ulong val)
120 {
121 cpu_ppc_store_tbl(env, val);
122 }
123
124 void helper_store_tbu (target_ulong val)
125 {
126 cpu_ppc_store_tbu(env, val);
127 }
128
129 void helper_store_atbl (target_ulong val)
130 {
131 cpu_ppc_store_atbl(env, val);
132 }
133
134 void helper_store_atbu (target_ulong val)
135 {
136 cpu_ppc_store_atbu(env, val);
137 }
138
139 void helper_store_601_rtcl (target_ulong val)
140 {
141 cpu_ppc601_store_rtcl(env, val);
142 }
143
144 void helper_store_601_rtcu (target_ulong val)
145 {
146 cpu_ppc601_store_rtcu(env, val);
147 }
148
149 target_ulong helper_load_decr (void)
150 {
151 return cpu_ppc_load_decr(env);
152 }
153
154 void helper_store_decr (target_ulong val)
155 {
156 cpu_ppc_store_decr(env, val);
157 }
158
159 void helper_store_hid0_601 (target_ulong val)
160 {
161 target_ulong hid0;
162
163 hid0 = env->spr[SPR_HID0];
164 if ((val ^ hid0) & 0x00000008) {
165 /* Change current endianness */
166 env->hflags &= ~(1 << MSR_LE);
167 env->hflags_nmsr &= ~(1 << MSR_LE);
168 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
169 env->hflags |= env->hflags_nmsr;
170 qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
171 val & 0x8 ? 'l' : 'b', env->hflags);
172 }
173 env->spr[SPR_HID0] = (uint32_t)val;
174 }
175
176 void helper_store_403_pbr (uint32_t num, target_ulong value)
177 {
178 if (likely(env->pb[num] != value)) {
179 env->pb[num] = value;
180 /* Should be optimized */
181 tlb_flush(env, 1);
182 }
183 }
184
185 target_ulong helper_load_40x_pit (void)
186 {
187 return load_40x_pit(env);
188 }
189
190 void helper_store_40x_pit (target_ulong val)
191 {
192 store_40x_pit(env, val);
193 }
194
195 void helper_store_40x_dbcr0 (target_ulong val)
196 {
197 store_40x_dbcr0(env, val);
198 }
199
200 void helper_store_40x_sler (target_ulong val)
201 {
202 store_40x_sler(env, val);
203 }
204
205 void helper_store_booke_tcr (target_ulong val)
206 {
207 store_booke_tcr(env, val);
208 }
209
210 void helper_store_booke_tsr (target_ulong val)
211 {
212 store_booke_tsr(env, val);
213 }
214
215 void helper_store_ibatu (uint32_t nr, target_ulong val)
216 {
217 ppc_store_ibatu(env, nr, val);
218 }
219
220 void helper_store_ibatl (uint32_t nr, target_ulong val)
221 {
222 ppc_store_ibatl(env, nr, val);
223 }
224
225 void helper_store_dbatu (uint32_t nr, target_ulong val)
226 {
227 ppc_store_dbatu(env, nr, val);
228 }
229
230 void helper_store_dbatl (uint32_t nr, target_ulong val)
231 {
232 ppc_store_dbatl(env, nr, val);
233 }
234
235 void helper_store_601_batl (uint32_t nr, target_ulong val)
236 {
237 ppc_store_ibatl_601(env, nr, val);
238 }
239
240 void helper_store_601_batu (uint32_t nr, target_ulong val)
241 {
242 ppc_store_ibatu_601(env, nr, val);
243 }
244 #endif
245
246 /*****************************************************************************/
247 /* Memory load and stores */
248
249 static inline target_ulong addr_add(target_ulong addr, target_long arg)
250 {
251 #if defined(TARGET_PPC64)
252 if (!msr_sf)
253 return (uint32_t)(addr + arg);
254 else
255 #endif
256 return addr + arg;
257 }
258
259 void helper_lmw (target_ulong addr, uint32_t reg)
260 {
261 for (; reg < 32; reg++) {
262 if (msr_le)
263 env->gpr[reg] = bswap32(ldl(addr));
264 else
265 env->gpr[reg] = ldl(addr);
266 addr = addr_add(addr, 4);
267 }
268 }
269
270 void helper_stmw (target_ulong addr, uint32_t reg)
271 {
272 for (; reg < 32; reg++) {
273 if (msr_le)
274 stl(addr, bswap32((uint32_t)env->gpr[reg]));
275 else
276 stl(addr, (uint32_t)env->gpr[reg]);
277 addr = addr_add(addr, 4);
278 }
279 }
280
281 void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
282 {
283 int sh;
284 for (; nb > 3; nb -= 4) {
285 env->gpr[reg] = ldl(addr);
286 reg = (reg + 1) % 32;
287 addr = addr_add(addr, 4);
288 }
289 if (unlikely(nb > 0)) {
290 env->gpr[reg] = 0;
291 for (sh = 24; nb > 0; nb--, sh -= 8) {
292 env->gpr[reg] |= ldub(addr) << sh;
293 addr = addr_add(addr, 1);
294 }
295 }
296 }
297 /* PPC32 specification says we must generate an exception if
298 * rA is in the range of registers to be loaded.
299 * In an other hand, IBM says this is valid, but rA won't be loaded.
300 * For now, I'll follow the spec...
301 */
302 void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
303 {
304 if (likely(xer_bc != 0)) {
305 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
306 (reg < rb && (reg + xer_bc) > rb))) {
307 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
308 POWERPC_EXCP_INVAL |
309 POWERPC_EXCP_INVAL_LSWX);
310 } else {
311 helper_lsw(addr, xer_bc, reg);
312 }
313 }
314 }
315
316 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
317 {
318 int sh;
319 for (; nb > 3; nb -= 4) {
320 stl(addr, env->gpr[reg]);
321 reg = (reg + 1) % 32;
322 addr = addr_add(addr, 4);
323 }
324 if (unlikely(nb > 0)) {
325 for (sh = 24; nb > 0; nb--, sh -= 8) {
326 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
327 addr = addr_add(addr, 1);
328 }
329 }
330 }
331
332 static void do_dcbz(target_ulong addr, int dcache_line_size)
333 {
334 addr &= ~(dcache_line_size - 1);
335 int i;
336 for (i = 0 ; i < dcache_line_size ; i += 4) {
337 stl(addr + i , 0);
338 }
339 if (env->reserve_addr == addr)
340 env->reserve_addr = (target_ulong)-1ULL;
341 }
342
343 void helper_dcbz(target_ulong addr)
344 {
345 do_dcbz(addr, env->dcache_line_size);
346 }
347
348 void helper_dcbz_970(target_ulong addr)
349 {
350 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
351 do_dcbz(addr, 32);
352 else
353 do_dcbz(addr, env->dcache_line_size);
354 }
355
356 void helper_icbi(target_ulong addr)
357 {
358 addr &= ~(env->dcache_line_size - 1);
359 /* Invalidate one cache line :
360 * PowerPC specification says this is to be treated like a load
361 * (not a fetch) by the MMU. To be sure it will be so,
362 * do the load "by hand".
363 */
364 ldl(addr);
365 tb_invalidate_page_range(addr, addr + env->icache_line_size);
366 }
367
368 // XXX: to be tested
369 target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
370 {
371 int i, c, d;
372 d = 24;
373 for (i = 0; i < xer_bc; i++) {
374 c = ldub(addr);
375 addr = addr_add(addr, 1);
376 /* ra (if not 0) and rb are never modified */
377 if (likely(reg != rb && (ra == 0 || reg != ra))) {
378 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
379 }
380 if (unlikely(c == xer_cmp))
381 break;
382 if (likely(d != 0)) {
383 d -= 8;
384 } else {
385 d = 24;
386 reg++;
387 reg = reg & 0x1F;
388 }
389 }
390 return i;
391 }
392
393 /*****************************************************************************/
394 /* Fixed point operations helpers */
395 #if defined(TARGET_PPC64)
396
397 /* multiply high word */
398 uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
399 {
400 uint64_t tl, th;
401
402 muls64(&tl, &th, arg1, arg2);
403 return th;
404 }
405
406 /* multiply high word unsigned */
407 uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
408 {
409 uint64_t tl, th;
410
411 mulu64(&tl, &th, arg1, arg2);
412 return th;
413 }
414
415 uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
416 {
417 int64_t th;
418 uint64_t tl;
419
420 muls64(&tl, (uint64_t *)&th, arg1, arg2);
421 /* If th != 0 && th != -1, then we had an overflow */
422 if (likely((uint64_t)(th + 1) <= 1)) {
423 env->xer &= ~(1 << XER_OV);
424 } else {
425 env->xer |= (1 << XER_OV) | (1 << XER_SO);
426 }
427 return (int64_t)tl;
428 }
429 #endif
430
431 target_ulong helper_cntlzw (target_ulong t)
432 {
433 return clz32(t);
434 }
435
436 #if defined(TARGET_PPC64)
437 target_ulong helper_cntlzd (target_ulong t)
438 {
439 return clz64(t);
440 }
441 #endif
442
443 /* shift right arithmetic helper */
444 target_ulong helper_sraw (target_ulong value, target_ulong shift)
445 {
446 int32_t ret;
447
448 if (likely(!(shift & 0x20))) {
449 if (likely((uint32_t)shift != 0)) {
450 shift &= 0x1f;
451 ret = (int32_t)value >> shift;
452 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
453 env->xer &= ~(1 << XER_CA);
454 } else {
455 env->xer |= (1 << XER_CA);
456 }
457 } else {
458 ret = (int32_t)value;
459 env->xer &= ~(1 << XER_CA);
460 }
461 } else {
462 ret = (int32_t)value >> 31;
463 if (ret) {
464 env->xer |= (1 << XER_CA);
465 } else {
466 env->xer &= ~(1 << XER_CA);
467 }
468 }
469 return (target_long)ret;
470 }
471
472 #if defined(TARGET_PPC64)
473 target_ulong helper_srad (target_ulong value, target_ulong shift)
474 {
475 int64_t ret;
476
477 if (likely(!(shift & 0x40))) {
478 if (likely((uint64_t)shift != 0)) {
479 shift &= 0x3f;
480 ret = (int64_t)value >> shift;
481 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
482 env->xer &= ~(1 << XER_CA);
483 } else {
484 env->xer |= (1 << XER_CA);
485 }
486 } else {
487 ret = (int64_t)value;
488 env->xer &= ~(1 << XER_CA);
489 }
490 } else {
491 ret = (int64_t)value >> 63;
492 if (ret) {
493 env->xer |= (1 << XER_CA);
494 } else {
495 env->xer &= ~(1 << XER_CA);
496 }
497 }
498 return ret;
499 }
500 #endif
501
502 #if defined(TARGET_PPC64)
503 target_ulong helper_popcntb (target_ulong val)
504 {
505 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
506 0x5555555555555555ULL);
507 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
508 0x3333333333333333ULL);
509 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
510 0x0f0f0f0f0f0f0f0fULL);
511 return val;
512 }
513
514 target_ulong helper_popcntw (target_ulong val)
515 {
516 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
517 0x5555555555555555ULL);
518 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
519 0x3333333333333333ULL);
520 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
521 0x0f0f0f0f0f0f0f0fULL);
522 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
523 0x00ff00ff00ff00ffULL);
524 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
525 0x0000ffff0000ffffULL);
526 return val;
527 }
528
529 target_ulong helper_popcntd (target_ulong val)
530 {
531 return ctpop64(val);
532 }
533 #else
534 target_ulong helper_popcntb (target_ulong val)
535 {
536 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
537 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
538 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
539 return val;
540 }
541
542 target_ulong helper_popcntw (target_ulong val)
543 {
544 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
545 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
546 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
547 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
548 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
549 return val;
550 }
551 #endif
552
553 /*****************************************************************************/
554 /* Floating point operations helpers */
555 uint64_t helper_float32_to_float64(uint32_t arg)
556 {
557 CPU_FloatU f;
558 CPU_DoubleU d;
559 f.l = arg;
560 d.d = float32_to_float64(f.f, &env->fp_status);
561 return d.ll;
562 }
563
564 uint32_t helper_float64_to_float32(uint64_t arg)
565 {
566 CPU_FloatU f;
567 CPU_DoubleU d;
568 d.ll = arg;
569 f.f = float64_to_float32(d.d, &env->fp_status);
570 return f.l;
571 }
572
573 static inline int isden(float64 d)
574 {
575 CPU_DoubleU u;
576
577 u.d = d;
578
579 return ((u.ll >> 52) & 0x7FF) == 0;
580 }
581
582 uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
583 {
584 CPU_DoubleU farg;
585 int isneg;
586 int ret;
587 farg.ll = arg;
588 isneg = float64_is_neg(farg.d);
589 if (unlikely(float64_is_any_nan(farg.d))) {
590 if (float64_is_signaling_nan(farg.d)) {
591 /* Signaling NaN: flags are undefined */
592 ret = 0x00;
593 } else {
594 /* Quiet NaN */
595 ret = 0x11;
596 }
597 } else if (unlikely(float64_is_infinity(farg.d))) {
598 /* +/- infinity */
599 if (isneg)
600 ret = 0x09;
601 else
602 ret = 0x05;
603 } else {
604 if (float64_is_zero(farg.d)) {
605 /* +/- zero */
606 if (isneg)
607 ret = 0x12;
608 else
609 ret = 0x02;
610 } else {
611 if (isden(farg.d)) {
612 /* Denormalized numbers */
613 ret = 0x10;
614 } else {
615 /* Normalized numbers */
616 ret = 0x00;
617 }
618 if (isneg) {
619 ret |= 0x08;
620 } else {
621 ret |= 0x04;
622 }
623 }
624 }
625 if (set_fprf) {
626 /* We update FPSCR_FPRF */
627 env->fpscr &= ~(0x1F << FPSCR_FPRF);
628 env->fpscr |= ret << FPSCR_FPRF;
629 }
630 /* We just need fpcc to update Rc1 */
631 return ret & 0xF;
632 }
633
634 /* Floating-point invalid operations exception */
635 static inline uint64_t fload_invalid_op_excp(int op)
636 {
637 uint64_t ret = 0;
638 int ve;
639
640 ve = fpscr_ve;
641 switch (op) {
642 case POWERPC_EXCP_FP_VXSNAN:
643 env->fpscr |= 1 << FPSCR_VXSNAN;
644 break;
645 case POWERPC_EXCP_FP_VXSOFT:
646 env->fpscr |= 1 << FPSCR_VXSOFT;
647 break;
648 case POWERPC_EXCP_FP_VXISI:
649 /* Magnitude subtraction of infinities */
650 env->fpscr |= 1 << FPSCR_VXISI;
651 goto update_arith;
652 case POWERPC_EXCP_FP_VXIDI:
653 /* Division of infinity by infinity */
654 env->fpscr |= 1 << FPSCR_VXIDI;
655 goto update_arith;
656 case POWERPC_EXCP_FP_VXZDZ:
657 /* Division of zero by zero */
658 env->fpscr |= 1 << FPSCR_VXZDZ;
659 goto update_arith;
660 case POWERPC_EXCP_FP_VXIMZ:
661 /* Multiplication of zero by infinity */
662 env->fpscr |= 1 << FPSCR_VXIMZ;
663 goto update_arith;
664 case POWERPC_EXCP_FP_VXVC:
665 /* Ordered comparison of NaN */
666 env->fpscr |= 1 << FPSCR_VXVC;
667 env->fpscr &= ~(0xF << FPSCR_FPCC);
668 env->fpscr |= 0x11 << FPSCR_FPCC;
669 /* We must update the target FPR before raising the exception */
670 if (ve != 0) {
671 env->exception_index = POWERPC_EXCP_PROGRAM;
672 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
673 /* Update the floating-point enabled exception summary */
674 env->fpscr |= 1 << FPSCR_FEX;
675 /* Exception is differed */
676 ve = 0;
677 }
678 break;
679 case POWERPC_EXCP_FP_VXSQRT:
680 /* Square root of a negative number */
681 env->fpscr |= 1 << FPSCR_VXSQRT;
682 update_arith:
683 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
684 if (ve == 0) {
685 /* Set the result to quiet NaN */
686 ret = 0x7FF8000000000000ULL;
687 env->fpscr &= ~(0xF << FPSCR_FPCC);
688 env->fpscr |= 0x11 << FPSCR_FPCC;
689 }
690 break;
691 case POWERPC_EXCP_FP_VXCVI:
692 /* Invalid conversion */
693 env->fpscr |= 1 << FPSCR_VXCVI;
694 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
695 if (ve == 0) {
696 /* Set the result to quiet NaN */
697 ret = 0x7FF8000000000000ULL;
698 env->fpscr &= ~(0xF << FPSCR_FPCC);
699 env->fpscr |= 0x11 << FPSCR_FPCC;
700 }
701 break;
702 }
703 /* Update the floating-point invalid operation summary */
704 env->fpscr |= 1 << FPSCR_VX;
705 /* Update the floating-point exception summary */
706 env->fpscr |= 1 << FPSCR_FX;
707 if (ve != 0) {
708 /* Update the floating-point enabled exception summary */
709 env->fpscr |= 1 << FPSCR_FEX;
710 if (msr_fe0 != 0 || msr_fe1 != 0)
711 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
712 }
713 return ret;
714 }
715
716 static inline void float_zero_divide_excp(void)
717 {
718 env->fpscr |= 1 << FPSCR_ZX;
719 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
720 /* Update the floating-point exception summary */
721 env->fpscr |= 1 << FPSCR_FX;
722 if (fpscr_ze != 0) {
723 /* Update the floating-point enabled exception summary */
724 env->fpscr |= 1 << FPSCR_FEX;
725 if (msr_fe0 != 0 || msr_fe1 != 0) {
726 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
727 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
728 }
729 }
730 }
731
732 static inline void float_overflow_excp(void)
733 {
734 env->fpscr |= 1 << FPSCR_OX;
735 /* Update the floating-point exception summary */
736 env->fpscr |= 1 << FPSCR_FX;
737 if (fpscr_oe != 0) {
738 /* XXX: should adjust the result */
739 /* Update the floating-point enabled exception summary */
740 env->fpscr |= 1 << FPSCR_FEX;
741 /* We must update the target FPR before raising the exception */
742 env->exception_index = POWERPC_EXCP_PROGRAM;
743 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
744 } else {
745 env->fpscr |= 1 << FPSCR_XX;
746 env->fpscr |= 1 << FPSCR_FI;
747 }
748 }
749
750 static inline void float_underflow_excp(void)
751 {
752 env->fpscr |= 1 << FPSCR_UX;
753 /* Update the floating-point exception summary */
754 env->fpscr |= 1 << FPSCR_FX;
755 if (fpscr_ue != 0) {
756 /* XXX: should adjust the result */
757 /* Update the floating-point enabled exception summary */
758 env->fpscr |= 1 << FPSCR_FEX;
759 /* We must update the target FPR before raising the exception */
760 env->exception_index = POWERPC_EXCP_PROGRAM;
761 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
762 }
763 }
764
765 static inline void float_inexact_excp(void)
766 {
767 env->fpscr |= 1 << FPSCR_XX;
768 /* Update the floating-point exception summary */
769 env->fpscr |= 1 << FPSCR_FX;
770 if (fpscr_xe != 0) {
771 /* Update the floating-point enabled exception summary */
772 env->fpscr |= 1 << FPSCR_FEX;
773 /* We must update the target FPR before raising the exception */
774 env->exception_index = POWERPC_EXCP_PROGRAM;
775 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
776 }
777 }
778
779 static inline void fpscr_set_rounding_mode(void)
780 {
781 int rnd_type;
782
783 /* Set rounding mode */
784 switch (fpscr_rn) {
785 case 0:
786 /* Best approximation (round to nearest) */
787 rnd_type = float_round_nearest_even;
788 break;
789 case 1:
790 /* Smaller magnitude (round toward zero) */
791 rnd_type = float_round_to_zero;
792 break;
793 case 2:
794 /* Round toward +infinite */
795 rnd_type = float_round_up;
796 break;
797 default:
798 case 3:
799 /* Round toward -infinite */
800 rnd_type = float_round_down;
801 break;
802 }
803 set_float_rounding_mode(rnd_type, &env->fp_status);
804 }
805
806 void helper_fpscr_clrbit (uint32_t bit)
807 {
808 int prev;
809
810 prev = (env->fpscr >> bit) & 1;
811 env->fpscr &= ~(1 << bit);
812 if (prev == 1) {
813 switch (bit) {
814 case FPSCR_RN1:
815 case FPSCR_RN:
816 fpscr_set_rounding_mode();
817 break;
818 default:
819 break;
820 }
821 }
822 }
823
824 void helper_fpscr_setbit (uint32_t bit)
825 {
826 int prev;
827
828 prev = (env->fpscr >> bit) & 1;
829 env->fpscr |= 1 << bit;
830 if (prev == 0) {
831 switch (bit) {
832 case FPSCR_VX:
833 env->fpscr |= 1 << FPSCR_FX;
834 if (fpscr_ve)
835 goto raise_ve;
836 case FPSCR_OX:
837 env->fpscr |= 1 << FPSCR_FX;
838 if (fpscr_oe)
839 goto raise_oe;
840 break;
841 case FPSCR_UX:
842 env->fpscr |= 1 << FPSCR_FX;
843 if (fpscr_ue)
844 goto raise_ue;
845 break;
846 case FPSCR_ZX:
847 env->fpscr |= 1 << FPSCR_FX;
848 if (fpscr_ze)
849 goto raise_ze;
850 break;
851 case FPSCR_XX:
852 env->fpscr |= 1 << FPSCR_FX;
853 if (fpscr_xe)
854 goto raise_xe;
855 break;
856 case FPSCR_VXSNAN:
857 case FPSCR_VXISI:
858 case FPSCR_VXIDI:
859 case FPSCR_VXZDZ:
860 case FPSCR_VXIMZ:
861 case FPSCR_VXVC:
862 case FPSCR_VXSOFT:
863 case FPSCR_VXSQRT:
864 case FPSCR_VXCVI:
865 env->fpscr |= 1 << FPSCR_VX;
866 env->fpscr |= 1 << FPSCR_FX;
867 if (fpscr_ve != 0)
868 goto raise_ve;
869 break;
870 case FPSCR_VE:
871 if (fpscr_vx != 0) {
872 raise_ve:
873 env->error_code = POWERPC_EXCP_FP;
874 if (fpscr_vxsnan)
875 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
876 if (fpscr_vxisi)
877 env->error_code |= POWERPC_EXCP_FP_VXISI;
878 if (fpscr_vxidi)
879 env->error_code |= POWERPC_EXCP_FP_VXIDI;
880 if (fpscr_vxzdz)
881 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
882 if (fpscr_vximz)
883 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
884 if (fpscr_vxvc)
885 env->error_code |= POWERPC_EXCP_FP_VXVC;
886 if (fpscr_vxsoft)
887 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
888 if (fpscr_vxsqrt)
889 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
890 if (fpscr_vxcvi)
891 env->error_code |= POWERPC_EXCP_FP_VXCVI;
892 goto raise_excp;
893 }
894 break;
895 case FPSCR_OE:
896 if (fpscr_ox != 0) {
897 raise_oe:
898 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
899 goto raise_excp;
900 }
901 break;
902 case FPSCR_UE:
903 if (fpscr_ux != 0) {
904 raise_ue:
905 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
906 goto raise_excp;
907 }
908 break;
909 case FPSCR_ZE:
910 if (fpscr_zx != 0) {
911 raise_ze:
912 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
913 goto raise_excp;
914 }
915 break;
916 case FPSCR_XE:
917 if (fpscr_xx != 0) {
918 raise_xe:
919 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
920 goto raise_excp;
921 }
922 break;
923 case FPSCR_RN1:
924 case FPSCR_RN:
925 fpscr_set_rounding_mode();
926 break;
927 default:
928 break;
929 raise_excp:
930 /* Update the floating-point enabled exception summary */
931 env->fpscr |= 1 << FPSCR_FEX;
932 /* We have to update Rc1 before raising the exception */
933 env->exception_index = POWERPC_EXCP_PROGRAM;
934 break;
935 }
936 }
937 }
938
939 void helper_store_fpscr (uint64_t arg, uint32_t mask)
940 {
941 /*
942 * We use only the 32 LSB of the incoming fpr
943 */
944 uint32_t prev, new;
945 int i;
946
947 prev = env->fpscr;
948 new = (uint32_t)arg;
949 new &= ~0x60000000;
950 new |= prev & 0x60000000;
951 for (i = 0; i < 8; i++) {
952 if (mask & (1 << i)) {
953 env->fpscr &= ~(0xF << (4 * i));
954 env->fpscr |= new & (0xF << (4 * i));
955 }
956 }
957 /* Update VX and FEX */
958 if (fpscr_ix != 0)
959 env->fpscr |= 1 << FPSCR_VX;
960 else
961 env->fpscr &= ~(1 << FPSCR_VX);
962 if ((fpscr_ex & fpscr_eex) != 0) {
963 env->fpscr |= 1 << FPSCR_FEX;
964 env->exception_index = POWERPC_EXCP_PROGRAM;
965 /* XXX: we should compute it properly */
966 env->error_code = POWERPC_EXCP_FP;
967 }
968 else
969 env->fpscr &= ~(1 << FPSCR_FEX);
970 fpscr_set_rounding_mode();
971 }
972
973 void helper_float_check_status (void)
974 {
975 #ifdef CONFIG_SOFTFLOAT
976 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
977 (env->error_code & POWERPC_EXCP_FP)) {
978 /* Differred floating-point exception after target FPR update */
979 if (msr_fe0 != 0 || msr_fe1 != 0)
980 helper_raise_exception_err(env->exception_index, env->error_code);
981 } else {
982 int status = get_float_exception_flags(&env->fp_status);
983 if (status & float_flag_divbyzero) {
984 float_zero_divide_excp();
985 } else if (status & float_flag_overflow) {
986 float_overflow_excp();
987 } else if (status & float_flag_underflow) {
988 float_underflow_excp();
989 } else if (status & float_flag_inexact) {
990 float_inexact_excp();
991 }
992 }
993 #else
994 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
995 (env->error_code & POWERPC_EXCP_FP)) {
996 /* Differred floating-point exception after target FPR update */
997 if (msr_fe0 != 0 || msr_fe1 != 0)
998 helper_raise_exception_err(env->exception_index, env->error_code);
999 }
1000 #endif
1001 }
1002
1003 #ifdef CONFIG_SOFTFLOAT
1004 void helper_reset_fpstatus (void)
1005 {
1006 set_float_exception_flags(0, &env->fp_status);
1007 }
1008 #endif
1009
1010 /* fadd - fadd. */
1011 uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
1012 {
1013 CPU_DoubleU farg1, farg2;
1014
1015 farg1.ll = arg1;
1016 farg2.ll = arg2;
1017
1018 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1019 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1020 /* Magnitude subtraction of infinities */
1021 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1022 } else {
1023 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1024 float64_is_signaling_nan(farg2.d))) {
1025 /* sNaN addition */
1026 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1027 }
1028 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1029 }
1030
1031 return farg1.ll;
1032 }
1033
1034 /* fsub - fsub. */
1035 uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1036 {
1037 CPU_DoubleU farg1, farg2;
1038
1039 farg1.ll = arg1;
1040 farg2.ll = arg2;
1041
1042 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1043 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1044 /* Magnitude subtraction of infinities */
1045 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1046 } else {
1047 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1048 float64_is_signaling_nan(farg2.d))) {
1049 /* sNaN subtraction */
1050 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1051 }
1052 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1053 }
1054
1055 return farg1.ll;
1056 }
1057
1058 /* fmul - fmul. */
1059 uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
1060 {
1061 CPU_DoubleU farg1, farg2;
1062
1063 farg1.ll = arg1;
1064 farg2.ll = arg2;
1065
1066 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1067 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1068 /* Multiplication of zero by infinity */
1069 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1070 } else {
1071 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1072 float64_is_signaling_nan(farg2.d))) {
1073 /* sNaN multiplication */
1074 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1075 }
1076 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1077 }
1078
1079 return farg1.ll;
1080 }
1081
1082 /* fdiv - fdiv. */
1083 uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
1084 {
1085 CPU_DoubleU farg1, farg2;
1086
1087 farg1.ll = arg1;
1088 farg2.ll = arg2;
1089
1090 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
1091 /* Division of infinity by infinity */
1092 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1093 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1094 /* Division of zero by zero */
1095 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1096 } else {
1097 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1098 float64_is_signaling_nan(farg2.d))) {
1099 /* sNaN division */
1100 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1101 }
1102 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1103 }
1104
1105 return farg1.ll;
1106 }
1107
1108 /* fabs */
1109 uint64_t helper_fabs (uint64_t arg)
1110 {
1111 CPU_DoubleU farg;
1112
1113 farg.ll = arg;
1114 farg.d = float64_abs(farg.d);
1115 return farg.ll;
1116 }
1117
1118 /* fnabs */
1119 uint64_t helper_fnabs (uint64_t arg)
1120 {
1121 CPU_DoubleU farg;
1122
1123 farg.ll = arg;
1124 farg.d = float64_abs(farg.d);
1125 farg.d = float64_chs(farg.d);
1126 return farg.ll;
1127 }
1128
1129 /* fneg */
1130 uint64_t helper_fneg (uint64_t arg)
1131 {
1132 CPU_DoubleU farg;
1133
1134 farg.ll = arg;
1135 farg.d = float64_chs(farg.d);
1136 return farg.ll;
1137 }
1138
1139 /* fctiw - fctiw. */
1140 uint64_t helper_fctiw (uint64_t arg)
1141 {
1142 CPU_DoubleU farg;
1143 farg.ll = arg;
1144
1145 if (unlikely(float64_is_signaling_nan(farg.d))) {
1146 /* sNaN conversion */
1147 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1148 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1149 /* qNan / infinity conversion */
1150 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1151 } else {
1152 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1153 /* XXX: higher bits are not supposed to be significant.
1154 * to make tests easier, return the same as a real PowerPC 750
1155 */
1156 farg.ll |= 0xFFF80000ULL << 32;
1157 }
1158 return farg.ll;
1159 }
1160
1161 /* fctiwz - fctiwz. */
1162 uint64_t helper_fctiwz (uint64_t arg)
1163 {
1164 CPU_DoubleU farg;
1165 farg.ll = arg;
1166
1167 if (unlikely(float64_is_signaling_nan(farg.d))) {
1168 /* sNaN conversion */
1169 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1170 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1171 /* qNan / infinity conversion */
1172 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1173 } else {
1174 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1175 /* XXX: higher bits are not supposed to be significant.
1176 * to make tests easier, return the same as a real PowerPC 750
1177 */
1178 farg.ll |= 0xFFF80000ULL << 32;
1179 }
1180 return farg.ll;
1181 }
1182
1183 #if defined(TARGET_PPC64)
1184 /* fcfid - fcfid. */
1185 uint64_t helper_fcfid (uint64_t arg)
1186 {
1187 CPU_DoubleU farg;
1188 farg.d = int64_to_float64(arg, &env->fp_status);
1189 return farg.ll;
1190 }
1191
1192 /* fctid - fctid. */
1193 uint64_t helper_fctid (uint64_t arg)
1194 {
1195 CPU_DoubleU farg;
1196 farg.ll = arg;
1197
1198 if (unlikely(float64_is_signaling_nan(farg.d))) {
1199 /* sNaN conversion */
1200 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1201 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1202 /* qNan / infinity conversion */
1203 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1204 } else {
1205 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1206 }
1207 return farg.ll;
1208 }
1209
1210 /* fctidz - fctidz. */
1211 uint64_t helper_fctidz (uint64_t arg)
1212 {
1213 CPU_DoubleU farg;
1214 farg.ll = arg;
1215
1216 if (unlikely(float64_is_signaling_nan(farg.d))) {
1217 /* sNaN conversion */
1218 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1219 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1220 /* qNan / infinity conversion */
1221 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1222 } else {
1223 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1224 }
1225 return farg.ll;
1226 }
1227
1228 #endif
1229
1230 static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
1231 {
1232 CPU_DoubleU farg;
1233 farg.ll = arg;
1234
1235 if (unlikely(float64_is_signaling_nan(farg.d))) {
1236 /* sNaN round */
1237 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
1238 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
1239 /* qNan / infinity round */
1240 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1241 } else {
1242 set_float_rounding_mode(rounding_mode, &env->fp_status);
1243 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1244 /* Restore rounding mode from FPSCR */
1245 fpscr_set_rounding_mode();
1246 }
1247 return farg.ll;
1248 }
1249
1250 uint64_t helper_frin (uint64_t arg)
1251 {
1252 return do_fri(arg, float_round_nearest_even);
1253 }
1254
1255 uint64_t helper_friz (uint64_t arg)
1256 {
1257 return do_fri(arg, float_round_to_zero);
1258 }
1259
1260 uint64_t helper_frip (uint64_t arg)
1261 {
1262 return do_fri(arg, float_round_up);
1263 }
1264
1265 uint64_t helper_frim (uint64_t arg)
1266 {
1267 return do_fri(arg, float_round_down);
1268 }
1269
1270 /* fmadd - fmadd. */
1271 uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1272 {
1273 CPU_DoubleU farg1, farg2, farg3;
1274
1275 farg1.ll = arg1;
1276 farg2.ll = arg2;
1277 farg3.ll = arg3;
1278
1279 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1280 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1281 /* Multiplication of zero by infinity */
1282 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1283 } else {
1284 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1285 float64_is_signaling_nan(farg2.d) ||
1286 float64_is_signaling_nan(farg3.d))) {
1287 /* sNaN operation */
1288 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1289 }
1290 #ifdef FLOAT128
1291 /* This is the way the PowerPC specification defines it */
1292 float128 ft0_128, ft1_128;
1293
1294 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1295 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1296 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1297 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1298 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1299 /* Magnitude subtraction of infinities */
1300 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1301 } else {
1302 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1303 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1304 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1305 }
1306 #else
1307 /* This is OK on x86 hosts */
1308 farg1.d = (farg1.d * farg2.d) + farg3.d;
1309 #endif
1310 }
1311
1312 return farg1.ll;
1313 }
1314
1315 /* fmsub - fmsub. */
1316 uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1317 {
1318 CPU_DoubleU farg1, farg2, farg3;
1319
1320 farg1.ll = arg1;
1321 farg2.ll = arg2;
1322 farg3.ll = arg3;
1323
1324 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1325 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1326 /* Multiplication of zero by infinity */
1327 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1328 } else {
1329 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1330 float64_is_signaling_nan(farg2.d) ||
1331 float64_is_signaling_nan(farg3.d))) {
1332 /* sNaN operation */
1333 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1334 }
1335 #ifdef FLOAT128
1336 /* This is the way the PowerPC specification defines it */
1337 float128 ft0_128, ft1_128;
1338
1339 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1340 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1341 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1342 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1343 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1344 /* Magnitude subtraction of infinities */
1345 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1346 } else {
1347 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1348 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1349 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1350 }
1351 #else
1352 /* This is OK on x86 hosts */
1353 farg1.d = (farg1.d * farg2.d) - farg3.d;
1354 #endif
1355 }
1356 return farg1.ll;
1357 }
1358
1359 /* fnmadd - fnmadd. */
1360 uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1361 {
1362 CPU_DoubleU farg1, farg2, farg3;
1363
1364 farg1.ll = arg1;
1365 farg2.ll = arg2;
1366 farg3.ll = arg3;
1367
1368 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1369 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1370 /* Multiplication of zero by infinity */
1371 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1372 } else {
1373 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1374 float64_is_signaling_nan(farg2.d) ||
1375 float64_is_signaling_nan(farg3.d))) {
1376 /* sNaN operation */
1377 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1378 }
1379 #ifdef FLOAT128
1380 /* This is the way the PowerPC specification defines it */
1381 float128 ft0_128, ft1_128;
1382
1383 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1384 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1385 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1386 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1387 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1388 /* Magnitude subtraction of infinities */
1389 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1390 } else {
1391 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1392 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1393 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1394 }
1395 #else
1396 /* This is OK on x86 hosts */
1397 farg1.d = (farg1.d * farg2.d) + farg3.d;
1398 #endif
1399 if (likely(!float64_is_any_nan(farg1.d))) {
1400 farg1.d = float64_chs(farg1.d);
1401 }
1402 }
1403 return farg1.ll;
1404 }
1405
1406 /* fnmsub - fnmsub. */
1407 uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1408 {
1409 CPU_DoubleU farg1, farg2, farg3;
1410
1411 farg1.ll = arg1;
1412 farg2.ll = arg2;
1413 farg3.ll = arg3;
1414
1415 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1416 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1417 /* Multiplication of zero by infinity */
1418 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1419 } else {
1420 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1421 float64_is_signaling_nan(farg2.d) ||
1422 float64_is_signaling_nan(farg3.d))) {
1423 /* sNaN operation */
1424 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1425 }
1426 #ifdef FLOAT128
1427 /* This is the way the PowerPC specification defines it */
1428 float128 ft0_128, ft1_128;
1429
1430 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1431 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1432 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1433 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1434 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1435 /* Magnitude subtraction of infinities */
1436 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1437 } else {
1438 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1439 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1440 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1441 }
1442 #else
1443 /* This is OK on x86 hosts */
1444 farg1.d = (farg1.d * farg2.d) - farg3.d;
1445 #endif
1446 if (likely(!float64_is_any_nan(farg1.d))) {
1447 farg1.d = float64_chs(farg1.d);
1448 }
1449 }
1450 return farg1.ll;
1451 }
1452
1453 /* frsp - frsp. */
1454 uint64_t helper_frsp (uint64_t arg)
1455 {
1456 CPU_DoubleU farg;
1457 float32 f32;
1458 farg.ll = arg;
1459
1460 if (unlikely(float64_is_signaling_nan(farg.d))) {
1461 /* sNaN square root */
1462 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1463 }
1464 f32 = float64_to_float32(farg.d, &env->fp_status);
1465 farg.d = float32_to_float64(f32, &env->fp_status);
1466
1467 return farg.ll;
1468 }
1469
1470 /* fsqrt - fsqrt. */
1471 uint64_t helper_fsqrt (uint64_t arg)
1472 {
1473 CPU_DoubleU farg;
1474 farg.ll = arg;
1475
1476 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1477 /* Square root of a negative nonzero number */
1478 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1479 } else {
1480 if (unlikely(float64_is_signaling_nan(farg.d))) {
1481 /* sNaN square root */
1482 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1483 }
1484 farg.d = float64_sqrt(farg.d, &env->fp_status);
1485 }
1486 return farg.ll;
1487 }
1488
1489 /* fre - fre. */
1490 uint64_t helper_fre (uint64_t arg)
1491 {
1492 CPU_DoubleU farg;
1493 farg.ll = arg;
1494
1495 if (unlikely(float64_is_signaling_nan(farg.d))) {
1496 /* sNaN reciprocal */
1497 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1498 }
1499 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1500 return farg.d;
1501 }
1502
1503 /* fres - fres. */
1504 uint64_t helper_fres (uint64_t arg)
1505 {
1506 CPU_DoubleU farg;
1507 float32 f32;
1508 farg.ll = arg;
1509
1510 if (unlikely(float64_is_signaling_nan(farg.d))) {
1511 /* sNaN reciprocal */
1512 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1513 }
1514 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1515 f32 = float64_to_float32(farg.d, &env->fp_status);
1516 farg.d = float32_to_float64(f32, &env->fp_status);
1517
1518 return farg.ll;
1519 }
1520
1521 /* frsqrte - frsqrte. */
1522 uint64_t helper_frsqrte (uint64_t arg)
1523 {
1524 CPU_DoubleU farg;
1525 float32 f32;
1526 farg.ll = arg;
1527
1528 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1529 /* Reciprocal square root of a negative nonzero number */
1530 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1531 } else {
1532 if (unlikely(float64_is_signaling_nan(farg.d))) {
1533 /* sNaN reciprocal square root */
1534 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1535 }
1536 farg.d = float64_sqrt(farg.d, &env->fp_status);
1537 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1538 f32 = float64_to_float32(farg.d, &env->fp_status);
1539 farg.d = float32_to_float64(f32, &env->fp_status);
1540 }
1541 return farg.ll;
1542 }
1543
1544 /* fsel - fsel. */
1545 uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1546 {
1547 CPU_DoubleU farg1;
1548
1549 farg1.ll = arg1;
1550
1551 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
1552 return arg2;
1553 } else {
1554 return arg3;
1555 }
1556 }
1557
1558 void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1559 {
1560 CPU_DoubleU farg1, farg2;
1561 uint32_t ret = 0;
1562 farg1.ll = arg1;
1563 farg2.ll = arg2;
1564
1565 if (unlikely(float64_is_any_nan(farg1.d) ||
1566 float64_is_any_nan(farg2.d))) {
1567 ret = 0x01UL;
1568 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1569 ret = 0x08UL;
1570 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1571 ret = 0x04UL;
1572 } else {
1573 ret = 0x02UL;
1574 }
1575
1576 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1577 env->fpscr |= ret << FPSCR_FPRF;
1578 env->crf[crfD] = ret;
1579 if (unlikely(ret == 0x01UL
1580 && (float64_is_signaling_nan(farg1.d) ||
1581 float64_is_signaling_nan(farg2.d)))) {
1582 /* sNaN comparison */
1583 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1584 }
1585 }
1586
1587 void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1588 {
1589 CPU_DoubleU farg1, farg2;
1590 uint32_t ret = 0;
1591 farg1.ll = arg1;
1592 farg2.ll = arg2;
1593
1594 if (unlikely(float64_is_any_nan(farg1.d) ||
1595 float64_is_any_nan(farg2.d))) {
1596 ret = 0x01UL;
1597 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1598 ret = 0x08UL;
1599 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1600 ret = 0x04UL;
1601 } else {
1602 ret = 0x02UL;
1603 }
1604
1605 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1606 env->fpscr |= ret << FPSCR_FPRF;
1607 env->crf[crfD] = ret;
1608 if (unlikely (ret == 0x01UL)) {
1609 if (float64_is_signaling_nan(farg1.d) ||
1610 float64_is_signaling_nan(farg2.d)) {
1611 /* sNaN comparison */
1612 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1613 POWERPC_EXCP_FP_VXVC);
1614 } else {
1615 /* qNaN comparison */
1616 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1617 }
1618 }
1619 }
1620
1621 #if !defined (CONFIG_USER_ONLY)
1622 void helper_store_msr (target_ulong val)
1623 {
1624 val = hreg_store_msr(env, val, 0);
1625 if (val != 0) {
1626 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1627 helper_raise_exception(val);
1628 }
1629 }
1630
1631 static inline void do_rfi(target_ulong nip, target_ulong msr,
1632 target_ulong msrm, int keep_msrh)
1633 {
1634 #if defined(TARGET_PPC64)
1635 if (msr & (1ULL << MSR_SF)) {
1636 nip = (uint64_t)nip;
1637 msr &= (uint64_t)msrm;
1638 } else {
1639 nip = (uint32_t)nip;
1640 msr = (uint32_t)(msr & msrm);
1641 if (keep_msrh)
1642 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
1643 }
1644 #else
1645 nip = (uint32_t)nip;
1646 msr &= (uint32_t)msrm;
1647 #endif
1648 /* XXX: beware: this is false if VLE is supported */
1649 env->nip = nip & ~((target_ulong)0x00000003);
1650 hreg_store_msr(env, msr, 1);
1651 #if defined (DEBUG_OP)
1652 cpu_dump_rfi(env->nip, env->msr);
1653 #endif
1654 /* No need to raise an exception here,
1655 * as rfi is always the last insn of a TB
1656 */
1657 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1658 }
1659
1660 void helper_rfi (void)
1661 {
1662 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1663 ~((target_ulong)0x783F0000), 1);
1664 }
1665
1666 #if defined(TARGET_PPC64)
1667 void helper_rfid (void)
1668 {
1669 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1670 ~((target_ulong)0x783F0000), 0);
1671 }
1672
1673 void helper_hrfid (void)
1674 {
1675 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1676 ~((target_ulong)0x783F0000), 0);
1677 }
1678 #endif
1679 #endif
1680
1681 void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
1682 {
1683 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1684 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1685 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1686 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1687 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
1688 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1689 }
1690 }
1691
1692 #if defined(TARGET_PPC64)
1693 void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
1694 {
1695 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1696 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1697 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1698 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1699 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
1700 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
1701 }
1702 #endif
1703
1704 /*****************************************************************************/
1705 /* PowerPC 601 specific instructions (POWER bridge) */
1706
1707 target_ulong helper_clcs (uint32_t arg)
1708 {
1709 switch (arg) {
1710 case 0x0CUL:
1711 /* Instruction cache line size */
1712 return env->icache_line_size;
1713 break;
1714 case 0x0DUL:
1715 /* Data cache line size */
1716 return env->dcache_line_size;
1717 break;
1718 case 0x0EUL:
1719 /* Minimum cache line size */
1720 return (env->icache_line_size < env->dcache_line_size) ?
1721 env->icache_line_size : env->dcache_line_size;
1722 break;
1723 case 0x0FUL:
1724 /* Maximum cache line size */
1725 return (env->icache_line_size > env->dcache_line_size) ?
1726 env->icache_line_size : env->dcache_line_size;
1727 break;
1728 default:
1729 /* Undefined */
1730 return 0;
1731 break;
1732 }
1733 }
1734
1735 target_ulong helper_div (target_ulong arg1, target_ulong arg2)
1736 {
1737 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1738
1739 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1740 (int32_t)arg2 == 0) {
1741 env->spr[SPR_MQ] = 0;
1742 return INT32_MIN;
1743 } else {
1744 env->spr[SPR_MQ] = tmp % arg2;
1745 return tmp / (int32_t)arg2;
1746 }
1747 }
1748
1749 target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
1750 {
1751 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1752
1753 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1754 (int32_t)arg2 == 0) {
1755 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1756 env->spr[SPR_MQ] = 0;
1757 return INT32_MIN;
1758 } else {
1759 env->spr[SPR_MQ] = tmp % arg2;
1760 tmp /= (int32_t)arg2;
1761 if ((int32_t)tmp != tmp) {
1762 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1763 } else {
1764 env->xer &= ~(1 << XER_OV);
1765 }
1766 return tmp;
1767 }
1768 }
1769
1770 target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
1771 {
1772 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1773 (int32_t)arg2 == 0) {
1774 env->spr[SPR_MQ] = 0;
1775 return INT32_MIN;
1776 } else {
1777 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1778 return (int32_t)arg1 / (int32_t)arg2;
1779 }
1780 }
1781
1782 target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
1783 {
1784 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1785 (int32_t)arg2 == 0) {
1786 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1787 env->spr[SPR_MQ] = 0;
1788 return INT32_MIN;
1789 } else {
1790 env->xer &= ~(1 << XER_OV);
1791 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1792 return (int32_t)arg1 / (int32_t)arg2;
1793 }
1794 }
1795
1796 #if !defined (CONFIG_USER_ONLY)
1797 target_ulong helper_rac (target_ulong addr)
1798 {
1799 mmu_ctx_t ctx;
1800 int nb_BATs;
1801 target_ulong ret = 0;
1802
1803 /* We don't have to generate many instances of this instruction,
1804 * as rac is supervisor only.
1805 */
1806 /* XXX: FIX THIS: Pretend we have no BAT */
1807 nb_BATs = env->nb_BATs;
1808 env->nb_BATs = 0;
1809 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1810 ret = ctx.raddr;
1811 env->nb_BATs = nb_BATs;
1812 return ret;
1813 }
1814
1815 void helper_rfsvc (void)
1816 {
1817 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1818 }
1819 #endif
1820
1821 /*****************************************************************************/
1822 /* 602 specific instructions */
1823 /* mfrom is the most crazy instruction ever seen, imho ! */
1824 /* Real implementation uses a ROM table. Do the same */
1825 /* Extremly decomposed:
1826 * -arg / 256
1827 * return 256 * log10(10 + 1.0) + 0.5
1828 */
1829 #if !defined (CONFIG_USER_ONLY)
1830 target_ulong helper_602_mfrom (target_ulong arg)
1831 {
1832 if (likely(arg < 602)) {
1833 #include "mfrom_table.c"
1834 return mfrom_ROM_table[arg];
1835 } else {
1836 return 0;
1837 }
1838 }
1839 #endif
1840
1841 /*****************************************************************************/
1842 /* Embedded PowerPC specific helpers */
1843
1844 /* XXX: to be improved to check access rights when in user-mode */
1845 target_ulong helper_load_dcr (target_ulong dcrn)
1846 {
1847 uint32_t val = 0;
1848
1849 if (unlikely(env->dcr_env == NULL)) {
1850 qemu_log("No DCR environment\n");
1851 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1852 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1853 } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1854 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1855 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1856 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1857 }
1858 return val;
1859 }
1860
1861 void helper_store_dcr (target_ulong dcrn, target_ulong val)
1862 {
1863 if (unlikely(env->dcr_env == NULL)) {
1864 qemu_log("No DCR environment\n");
1865 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1866 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1867 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1868 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1869 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1870 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1871 }
1872 }
1873
1874 #if !defined(CONFIG_USER_ONLY)
1875 void helper_40x_rfci (void)
1876 {
1877 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1878 ~((target_ulong)0xFFFF0000), 0);
1879 }
1880
1881 void helper_rfci (void)
1882 {
1883 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1884 ~((target_ulong)0x3FFF0000), 0);
1885 }
1886
1887 void helper_rfdi (void)
1888 {
1889 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1890 ~((target_ulong)0x3FFF0000), 0);
1891 }
1892
1893 void helper_rfmci (void)
1894 {
1895 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1896 ~((target_ulong)0x3FFF0000), 0);
1897 }
1898 #endif
1899
1900 /* 440 specific */
1901 target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
1902 {
1903 target_ulong mask;
1904 int i;
1905
1906 i = 1;
1907 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1908 if ((high & mask) == 0) {
1909 if (update_Rc) {
1910 env->crf[0] = 0x4;
1911 }
1912 goto done;
1913 }
1914 i++;
1915 }
1916 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1917 if ((low & mask) == 0) {
1918 if (update_Rc) {
1919 env->crf[0] = 0x8;
1920 }
1921 goto done;
1922 }
1923 i++;
1924 }
1925 if (update_Rc) {
1926 env->crf[0] = 0x2;
1927 }
1928 done:
1929 env->xer = (env->xer & ~0x7F) | i;
1930 if (update_Rc) {
1931 env->crf[0] |= xer_so;
1932 }
1933 return i;
1934 }
1935
1936 /*****************************************************************************/
1937 /* Altivec extension helpers */
1938 #if defined(HOST_WORDS_BIGENDIAN)
1939 #define HI_IDX 0
1940 #define LO_IDX 1
1941 #else
1942 #define HI_IDX 1
1943 #define LO_IDX 0
1944 #endif
1945
1946 #if defined(HOST_WORDS_BIGENDIAN)
1947 #define VECTOR_FOR_INORDER_I(index, element) \
1948 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1949 #else
1950 #define VECTOR_FOR_INORDER_I(index, element) \
1951 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1952 #endif
1953
1954 /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1955 * execute the following block. */
1956 #define DO_HANDLE_NAN(result, x) \
1957 if (float32_is_any_nan(x)) { \
1958 CPU_FloatU __f; \
1959 __f.f = x; \
1960 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1961 result = __f.f; \
1962 } else
1963
1964 #define HANDLE_NAN1(result, x) \
1965 DO_HANDLE_NAN(result, x)
1966 #define HANDLE_NAN2(result, x, y) \
1967 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1968 #define HANDLE_NAN3(result, x, y, z) \
1969 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1970
1971 /* Saturating arithmetic helpers. */
1972 #define SATCVT(from, to, from_type, to_type, min, max) \
1973 static inline to_type cvt##from##to(from_type x, int *sat) \
1974 { \
1975 to_type r; \
1976 if (x < (from_type)min) { \
1977 r = min; \
1978 *sat = 1; \
1979 } else if (x > (from_type)max) { \
1980 r = max; \
1981 *sat = 1; \
1982 } else { \
1983 r = x; \
1984 } \
1985 return r; \
1986 }
1987 #define SATCVTU(from, to, from_type, to_type, min, max) \
1988 static inline to_type cvt##from##to(from_type x, int *sat) \
1989 { \
1990 to_type r; \
1991 if (x > (from_type)max) { \
1992 r = max; \
1993 *sat = 1; \
1994 } else { \
1995 r = x; \
1996 } \
1997 return r; \
1998 }
1999 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
2000 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
2001 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
2002
2003 SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
2004 SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
2005 SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
2006 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
2007 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
2008 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
2009 #undef SATCVT
2010 #undef SATCVTU
2011
2012 #define LVE(name, access, swap, element) \
2013 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2014 { \
2015 size_t n_elems = ARRAY_SIZE(r->element); \
2016 int adjust = HI_IDX*(n_elems-1); \
2017 int sh = sizeof(r->element[0]) >> 1; \
2018 int index = (addr & 0xf) >> sh; \
2019 if(msr_le) { \
2020 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2021 } else { \
2022 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2023 } \
2024 }
2025 #define I(x) (x)
2026 LVE(lvebx, ldub, I, u8)
2027 LVE(lvehx, lduw, bswap16, u16)
2028 LVE(lvewx, ldl, bswap32, u32)
2029 #undef I
2030 #undef LVE
2031
2032 void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2033 {
2034 int i, j = (sh & 0xf);
2035
2036 VECTOR_FOR_INORDER_I (i, u8) {
2037 r->u8[i] = j++;
2038 }
2039 }
2040
2041 void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2042 {
2043 int i, j = 0x10 - (sh & 0xf);
2044
2045 VECTOR_FOR_INORDER_I (i, u8) {
2046 r->u8[i] = j++;
2047 }
2048 }
2049
2050 #define STVE(name, access, swap, element) \
2051 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2052 { \
2053 size_t n_elems = ARRAY_SIZE(r->element); \
2054 int adjust = HI_IDX*(n_elems-1); \
2055 int sh = sizeof(r->element[0]) >> 1; \
2056 int index = (addr & 0xf) >> sh; \
2057 if(msr_le) { \
2058 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2059 } else { \
2060 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2061 } \
2062 }
2063 #define I(x) (x)
2064 STVE(stvebx, stb, I, u8)
2065 STVE(stvehx, stw, bswap16, u16)
2066 STVE(stvewx, stl, bswap32, u32)
2067 #undef I
2068 #undef LVE
2069
2070 void helper_mtvscr (ppc_avr_t *r)
2071 {
2072 #if defined(HOST_WORDS_BIGENDIAN)
2073 env->vscr = r->u32[3];
2074 #else
2075 env->vscr = r->u32[0];
2076 #endif
2077 set_flush_to_zero(vscr_nj, &env->vec_status);
2078 }
2079
2080 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2081 {
2082 int i;
2083 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2084 r->u32[i] = ~a->u32[i] < b->u32[i];
2085 }
2086 }
2087
2088 #define VARITH_DO(name, op, element) \
2089 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2090 { \
2091 int i; \
2092 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2093 r->element[i] = a->element[i] op b->element[i]; \
2094 } \
2095 }
2096 #define VARITH(suffix, element) \
2097 VARITH_DO(add##suffix, +, element) \
2098 VARITH_DO(sub##suffix, -, element)
2099 VARITH(ubm, u8)
2100 VARITH(uhm, u16)
2101 VARITH(uwm, u32)
2102 #undef VARITH_DO
2103 #undef VARITH
2104
2105 #define VARITHFP(suffix, func) \
2106 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2107 { \
2108 int i; \
2109 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2110 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2111 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2112 } \
2113 } \
2114 }
2115 VARITHFP(addfp, float32_add)
2116 VARITHFP(subfp, float32_sub)
2117 #undef VARITHFP
2118
2119 #define VARITHSAT_CASE(type, op, cvt, element) \
2120 { \
2121 type result = (type)a->element[i] op (type)b->element[i]; \
2122 r->element[i] = cvt(result, &sat); \
2123 }
2124
2125 #define VARITHSAT_DO(name, op, optype, cvt, element) \
2126 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2127 { \
2128 int sat = 0; \
2129 int i; \
2130 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2131 switch (sizeof(r->element[0])) { \
2132 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2133 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2134 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2135 } \
2136 } \
2137 if (sat) { \
2138 env->vscr |= (1 << VSCR_SAT); \
2139 } \
2140 }
2141 #define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2142 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2143 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2144 #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2145 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2146 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2147 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2148 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2149 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2150 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2151 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2152 VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2153 #undef VARITHSAT_CASE
2154 #undef VARITHSAT_DO
2155 #undef VARITHSAT_SIGNED
2156 #undef VARITHSAT_UNSIGNED
2157
2158 #define VAVG_DO(name, element, etype) \
2159 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2160 { \
2161 int i; \
2162 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2163 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2164 r->element[i] = x >> 1; \
2165 } \
2166 }
2167
2168 #define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2169 VAVG_DO(avgs##type, signed_element, signed_type) \
2170 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2171 VAVG(b, s8, int16_t, u8, uint16_t)
2172 VAVG(h, s16, int32_t, u16, uint32_t)
2173 VAVG(w, s32, int64_t, u32, uint64_t)
2174 #undef VAVG_DO
2175 #undef VAVG
2176
2177 #define VCF(suffix, cvt, element) \
2178 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2179 { \
2180 int i; \
2181 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2182 float32 t = cvt(b->element[i], &env->vec_status); \
2183 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2184 } \
2185 }
2186 VCF(ux, uint32_to_float32, u32)
2187 VCF(sx, int32_to_float32, s32)
2188 #undef VCF
2189
2190 #define VCMP_DO(suffix, compare, element, record) \
2191 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2192 { \
2193 uint32_t ones = (uint32_t)-1; \
2194 uint32_t all = ones; \
2195 uint32_t none = 0; \
2196 int i; \
2197 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2198 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2199 switch (sizeof (a->element[0])) { \
2200 case 4: r->u32[i] = result; break; \
2201 case 2: r->u16[i] = result; break; \
2202 case 1: r->u8[i] = result; break; \
2203 } \
2204 all &= result; \
2205 none |= result; \
2206 } \
2207 if (record) { \
2208 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2209 } \
2210 }
2211 #define VCMP(suffix, compare, element) \
2212 VCMP_DO(suffix, compare, element, 0) \
2213 VCMP_DO(suffix##_dot, compare, element, 1)
2214 VCMP(equb, ==, u8)
2215 VCMP(equh, ==, u16)
2216 VCMP(equw, ==, u32)
2217 VCMP(gtub, >, u8)
2218 VCMP(gtuh, >, u16)
2219 VCMP(gtuw, >, u32)
2220 VCMP(gtsb, >, s8)
2221 VCMP(gtsh, >, s16)
2222 VCMP(gtsw, >, s32)
2223 #undef VCMP_DO
2224 #undef VCMP
2225
2226 #define VCMPFP_DO(suffix, compare, order, record) \
2227 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2228 { \
2229 uint32_t ones = (uint32_t)-1; \
2230 uint32_t all = ones; \
2231 uint32_t none = 0; \
2232 int i; \
2233 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2234 uint32_t result; \
2235 int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2236 if (rel == float_relation_unordered) { \
2237 result = 0; \
2238 } else if (rel compare order) { \
2239 result = ones; \
2240 } else { \
2241 result = 0; \
2242 } \
2243 r->u32[i] = result; \
2244 all &= result; \
2245 none |= result; \
2246 } \
2247 if (record) { \
2248 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2249 } \
2250 }
2251 #define VCMPFP(suffix, compare, order) \
2252 VCMPFP_DO(suffix, compare, order, 0) \
2253 VCMPFP_DO(suffix##_dot, compare, order, 1)
2254 VCMPFP(eqfp, ==, float_relation_equal)
2255 VCMPFP(gefp, !=, float_relation_less)
2256 VCMPFP(gtfp, ==, float_relation_greater)
2257 #undef VCMPFP_DO
2258 #undef VCMPFP
2259
2260 static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
2261 int record)
2262 {
2263 int i;
2264 int all_in = 0;
2265 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2266 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2267 if (le_rel == float_relation_unordered) {
2268 r->u32[i] = 0xc0000000;
2269 /* ALL_IN does not need to be updated here. */
2270 } else {
2271 float32 bneg = float32_chs(b->f[i]);
2272 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2273 int le = le_rel != float_relation_greater;
2274 int ge = ge_rel != float_relation_less;
2275 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2276 all_in |= (!le | !ge);
2277 }
2278 }
2279 if (record) {
2280 env->crf[6] = (all_in == 0) << 1;
2281 }
2282 }
2283
2284 void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2285 {
2286 vcmpbfp_internal(r, a, b, 0);
2287 }
2288
2289 void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2290 {
2291 vcmpbfp_internal(r, a, b, 1);
2292 }
2293
2294 #define VCT(suffix, satcvt, element) \
2295 void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2296 { \
2297 int i; \
2298 int sat = 0; \
2299 float_status s = env->vec_status; \
2300 set_float_rounding_mode(float_round_to_zero, &s); \
2301 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2302 if (float32_is_any_nan(b->f[i])) { \
2303 r->element[i] = 0; \
2304 } else { \
2305 float64 t = float32_to_float64(b->f[i], &s); \
2306 int64_t j; \
2307 t = float64_scalbn(t, uim, &s); \
2308 j = float64_to_int64(t, &s); \
2309 r->element[i] = satcvt(j, &sat); \
2310 } \
2311 } \
2312 if (sat) { \
2313 env->vscr |= (1 << VSCR_SAT); \
2314 } \
2315 }
2316 VCT(uxs, cvtsduw, u32)
2317 VCT(sxs, cvtsdsw, s32)
2318 #undef VCT
2319
2320 void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2321 {
2322 int i;
2323 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2324 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2325 /* Need to do the computation in higher precision and round
2326 * once at the end. */
2327 float64 af, bf, cf, t;
2328 af = float32_to_float64(a->f[i], &env->vec_status);
2329 bf = float32_to_float64(b->f[i], &env->vec_status);
2330 cf = float32_to_float64(c->f[i], &env->vec_status);
2331 t = float64_mul(af, cf, &env->vec_status);
2332 t = float64_add(t, bf, &env->vec_status);
2333 r->f[i] = float64_to_float32(t, &env->vec_status);
2334 }
2335 }
2336 }
2337
2338 void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2339 {
2340 int sat = 0;
2341 int i;
2342
2343 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2344 int32_t prod = a->s16[i] * b->s16[i];
2345 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2346 r->s16[i] = cvtswsh (t, &sat);
2347 }
2348
2349 if (sat) {
2350 env->vscr |= (1 << VSCR_SAT);
2351 }
2352 }
2353
2354 void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2355 {
2356 int sat = 0;
2357 int i;
2358
2359 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2360 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2361 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2362 r->s16[i] = cvtswsh (t, &sat);
2363 }
2364
2365 if (sat) {
2366 env->vscr |= (1 << VSCR_SAT);
2367 }
2368 }
2369
2370 #define VMINMAX_DO(name, compare, element) \
2371 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2372 { \
2373 int i; \
2374 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2375 if (a->element[i] compare b->element[i]) { \
2376 r->element[i] = b->element[i]; \
2377 } else { \
2378 r->element[i] = a->element[i]; \
2379 } \
2380 } \
2381 }
2382 #define VMINMAX(suffix, element) \
2383 VMINMAX_DO(min##suffix, >, element) \
2384 VMINMAX_DO(max##suffix, <, element)
2385 VMINMAX(sb, s8)
2386 VMINMAX(sh, s16)
2387 VMINMAX(sw, s32)
2388 VMINMAX(ub, u8)
2389 VMINMAX(uh, u16)
2390 VMINMAX(uw, u32)
2391 #undef VMINMAX_DO
2392 #undef VMINMAX
2393
2394 #define VMINMAXFP(suffix, rT, rF) \
2395 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2396 { \
2397 int i; \
2398 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2399 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2400 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2401 r->f[i] = rT->f[i]; \
2402 } else { \
2403 r->f[i] = rF->f[i]; \
2404 } \
2405 } \
2406 } \
2407 }
2408 VMINMAXFP(minfp, a, b)
2409 VMINMAXFP(maxfp, b, a)
2410 #undef VMINMAXFP
2411
2412 void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2413 {
2414 int i;
2415 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2416 int32_t prod = a->s16[i] * b->s16[i];
2417 r->s16[i] = (int16_t) (prod + c->s16[i]);
2418 }
2419 }
2420
2421 #define VMRG_DO(name, element, highp) \
2422 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2423 { \
2424 ppc_avr_t result; \
2425 int i; \
2426 size_t n_elems = ARRAY_SIZE(r->element); \
2427 for (i = 0; i < n_elems/2; i++) { \
2428 if (highp) { \
2429 result.element[i*2+HI_IDX] = a->element[i]; \
2430 result.element[i*2+LO_IDX] = b->element[i]; \
2431 } else { \
2432 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2433 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2434 } \
2435 } \
2436 *r = result; \
2437 }
2438 #if defined(HOST_WORDS_BIGENDIAN)
2439 #define MRGHI 0
2440 #define MRGLO 1
2441 #else
2442 #define MRGHI 1
2443 #define MRGLO 0
2444 #endif
2445 #define VMRG(suffix, element) \
2446 VMRG_DO(mrgl##suffix, element, MRGHI) \
2447 VMRG_DO(mrgh##suffix, element, MRGLO)
2448 VMRG(b, u8)
2449 VMRG(h, u16)
2450 VMRG(w, u32)
2451 #undef VMRG_DO
2452 #undef VMRG
2453 #undef MRGHI
2454 #undef MRGLO
2455
2456 void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2457 {
2458 int32_t prod[16];
2459 int i;
2460
2461 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2462 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2463 }
2464
2465 VECTOR_FOR_INORDER_I(i, s32) {
2466 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2467 }
2468 }
2469
2470 void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2471 {
2472 int32_t prod[8];
2473 int i;
2474
2475 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2476 prod[i] = a->s16[i] * b->s16[i];
2477 }
2478
2479 VECTOR_FOR_INORDER_I(i, s32) {
2480 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2481 }
2482 }
2483
2484 void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2485 {
2486 int32_t prod[8];
2487 int i;
2488 int sat = 0;
2489
2490 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2491 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2492 }
2493
2494 VECTOR_FOR_INORDER_I (i, s32) {
2495 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2496 r->u32[i] = cvtsdsw(t, &sat);
2497 }
2498
2499 if (sat) {
2500 env->vscr |= (1 << VSCR_SAT);
2501 }
2502 }
2503
2504 void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2505 {
2506 uint16_t prod[16];
2507 int i;
2508
2509 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2510 prod[i] = a->u8[i] * b->u8[i];
2511 }
2512
2513 VECTOR_FOR_INORDER_I(i, u32) {
2514 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2515 }
2516 }
2517
2518 void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2519 {
2520 uint32_t prod[8];
2521 int i;
2522
2523 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2524 prod[i] = a->u16[i] * b->u16[i];
2525 }
2526
2527 VECTOR_FOR_INORDER_I(i, u32) {
2528 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2529 }
2530 }
2531
2532 void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2533 {
2534 uint32_t prod[8];
2535 int i;
2536 int sat = 0;
2537
2538 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2539 prod[i] = a->u16[i] * b->u16[i];
2540 }
2541
2542 VECTOR_FOR_INORDER_I (i, s32) {
2543 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2544 r->u32[i] = cvtuduw(t, &sat);
2545 }
2546
2547 if (sat) {
2548 env->vscr |= (1 << VSCR_SAT);
2549 }
2550 }
2551
2552 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2553 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2554 { \
2555 int i; \
2556 VECTOR_FOR_INORDER_I(i, prod_element) { \
2557 if (evenp) { \
2558 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2559 } else { \
2560 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2561 } \
2562 } \
2563 }
2564 #define VMUL(suffix, mul_element, prod_element) \
2565 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2566 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2567 VMUL(sb, s8, s16)
2568 VMUL(sh, s16, s32)
2569 VMUL(ub, u8, u16)
2570 VMUL(uh, u16, u32)
2571 #undef VMUL_DO
2572 #undef VMUL
2573
2574 void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2575 {
2576 int i;
2577 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2578 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2579 /* Need to do the computation is higher precision and round
2580 * once at the end. */
2581 float64 af, bf, cf, t;
2582 af = float32_to_float64(a->f[i], &env->vec_status);
2583 bf = float32_to_float64(b->f[i], &env->vec_status);
2584 cf = float32_to_float64(c->f[i], &env->vec_status);
2585 t = float64_mul(af, cf, &env->vec_status);
2586 t = float64_sub(t, bf, &env->vec_status);
2587 t = float64_chs(t);
2588 r->f[i] = float64_to_float32(t, &env->vec_status);
2589 }
2590 }
2591 }
2592
2593 void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2594 {
2595 ppc_avr_t result;
2596 int i;
2597 VECTOR_FOR_INORDER_I (i, u8) {
2598 int s = c->u8[i] & 0x1f;
2599 #if defined(HOST_WORDS_BIGENDIAN)
2600 int index = s & 0xf;
2601 #else
2602 int index = 15 - (s & 0xf);
2603 #endif
2604 if (s & 0x10) {
2605 result.u8[i] = b->u8[index];
2606 } else {
2607 result.u8[i] = a->u8[index];
2608 }
2609 }
2610 *r = result;
2611 }
2612
2613 #if defined(HOST_WORDS_BIGENDIAN)
2614 #define PKBIG 1
2615 #else
2616 #define PKBIG 0
2617 #endif
2618 void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2619 {
2620 int i, j;
2621 ppc_avr_t result;
2622 #if defined(HOST_WORDS_BIGENDIAN)
2623 const ppc_avr_t *x[2] = { a, b };
2624 #else
2625 const ppc_avr_t *x[2] = { b, a };
2626 #endif
2627
2628 VECTOR_FOR_INORDER_I (i, u64) {
2629 VECTOR_FOR_INORDER_I (j, u32){
2630 uint32_t e = x[i]->u32[j];
2631 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2632 ((e >> 6) & 0x3e0) |
2633 ((e >> 3) & 0x1f));
2634 }
2635 }
2636 *r = result;
2637 }
2638
2639 #define VPK(suffix, from, to, cvt, dosat) \
2640 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2641 { \
2642 int i; \
2643 int sat = 0; \
2644 ppc_avr_t result; \
2645 ppc_avr_t *a0 = PKBIG ? a : b; \
2646 ppc_avr_t *a1 = PKBIG ? b : a; \
2647 VECTOR_FOR_INORDER_I (i, from) { \
2648 result.to[i] = cvt(a0->from[i], &sat); \
2649 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2650 } \
2651 *r = result; \
2652 if (dosat && sat) { \
2653 env->vscr |= (1 << VSCR_SAT); \
2654 } \
2655 }
2656 #define I(x, y) (x)
2657 VPK(shss, s16, s8, cvtshsb, 1)
2658 VPK(shus, s16, u8, cvtshub, 1)
2659 VPK(swss, s32, s16, cvtswsh, 1)
2660 VPK(swus, s32, u16, cvtswuh, 1)
2661 VPK(uhus, u16, u8, cvtuhub, 1)
2662 VPK(uwus, u32, u16, cvtuwuh, 1)
2663 VPK(uhum, u16, u8, I, 0)
2664 VPK(uwum, u32, u16, I, 0)
2665 #undef I
2666 #undef VPK
2667 #undef PKBIG
2668
2669 void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
2670 {
2671 int i;
2672 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2673 HANDLE_NAN1(r->f[i], b->f[i]) {
2674 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2675 }
2676 }
2677 }
2678
2679 #define VRFI(suffix, rounding) \
2680 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2681 { \
2682 int i; \
2683 float_status s = env->vec_status; \
2684 set_float_rounding_mode(rounding, &s); \
2685 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2686 HANDLE_NAN1(r->f[i], b->f[i]) { \
2687 r->f[i] = float32_round_to_int (b->f[i], &s); \
2688 } \
2689 } \
2690 }
2691 VRFI(n, float_round_nearest_even)
2692 VRFI(m, float_round_down)
2693 VRFI(p, float_round_up)
2694 VRFI(z, float_round_to_zero)
2695 #undef VRFI
2696
2697 #define VROTATE(suffix, element) \
2698 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2699 { \
2700 int i; \
2701 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2702 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2703 unsigned int shift = b->element[i] & mask; \
2704 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2705 } \
2706 }
2707 VROTATE(b, u8)
2708 VROTATE(h, u16)
2709 VROTATE(w, u32)
2710 #undef VROTATE
2711
2712 void helper_vrsqrtefp (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 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2718 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2719 }
2720 }
2721 }
2722
2723 void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2724 {
2725 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2726 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2727 }
2728
2729 void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2730 {
2731 int i;
2732 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2733 HANDLE_NAN1(r->f[i], b->f[i]) {
2734 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2735 }
2736 }
2737 }
2738
2739 void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
2740 {
2741 int i;
2742 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2743 HANDLE_NAN1(r->f[i], b->f[i]) {
2744 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2745 }
2746 }
2747 }
2748
2749 #if defined(HOST_WORDS_BIGENDIAN)
2750 #define LEFT 0
2751 #define RIGHT 1
2752 #else
2753 #define LEFT 1
2754 #define RIGHT 0
2755 #endif
2756 /* The specification says that the results are undefined if all of the
2757 * shift counts are not identical. We check to make sure that they are
2758 * to conform to what real hardware appears to do. */
2759 #define VSHIFT(suffix, leftp) \
2760 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2761 { \
2762 int shift = b->u8[LO_IDX*15] & 0x7; \
2763 int doit = 1; \
2764 int i; \
2765 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2766 doit = doit && ((b->u8[i] & 0x7) == shift); \
2767 } \
2768 if (doit) { \
2769 if (shift == 0) { \
2770 *r = *a; \
2771 } else if (leftp) { \
2772 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2773 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2774 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2775 } else { \
2776 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2777 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2778 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2779 } \
2780 } \
2781 }
2782 VSHIFT(l, LEFT)
2783 VSHIFT(r, RIGHT)
2784 #undef VSHIFT
2785 #undef LEFT
2786 #undef RIGHT
2787
2788 #define VSL(suffix, element) \
2789 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2790 { \
2791 int i; \
2792 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2793 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2794 unsigned int shift = b->element[i] & mask; \
2795 r->element[i] = a->element[i] << shift; \
2796 } \
2797 }
2798 VSL(b, u8)
2799 VSL(h, u16)
2800 VSL(w, u32)
2801 #undef VSL
2802
2803 void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2804 {
2805 int sh = shift & 0xf;
2806 int i;
2807 ppc_avr_t result;
2808
2809 #if defined(HOST_WORDS_BIGENDIAN)
2810 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2811 int index = sh + i;
2812 if (index > 0xf) {
2813 result.u8[i] = b->u8[index-0x10];
2814 } else {
2815 result.u8[i] = a->u8[index];
2816 }
2817 }
2818 #else
2819 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2820 int index = (16 - sh) + i;
2821 if (index > 0xf) {
2822 result.u8[i] = a->u8[index-0x10];
2823 } else {
2824 result.u8[i] = b->u8[index];
2825 }
2826 }
2827 #endif
2828 *r = result;
2829 }
2830
2831 void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2832 {
2833 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2834
2835 #if defined (HOST_WORDS_BIGENDIAN)
2836 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2837 memset (&r->u8[16-sh], 0, sh);
2838 #else
2839 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2840 memset (&r->u8[0], 0, sh);
2841 #endif
2842 }
2843
2844 /* Experimental testing shows that hardware masks the immediate. */
2845 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2846 #if defined(HOST_WORDS_BIGENDIAN)
2847 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2848 #else
2849 #define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2850 #endif
2851 #define VSPLT(suffix, element) \
2852 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2853 { \
2854 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2855 int i; \
2856 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2857 r->element[i] = s; \
2858 } \
2859 }
2860 VSPLT(b, u8)
2861 VSPLT(h, u16)
2862 VSPLT(w, u32)
2863 #undef VSPLT
2864 #undef SPLAT_ELEMENT
2865 #undef _SPLAT_MASKED
2866
2867 #define VSPLTI(suffix, element, splat_type) \
2868 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2869 { \
2870 splat_type x = (int8_t)(splat << 3) >> 3; \
2871 int i; \
2872 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2873 r->element[i] = x; \
2874 } \
2875 }
2876 VSPLTI(b, s8, int8_t)
2877 VSPLTI(h, s16, int16_t)
2878 VSPLTI(w, s32, int32_t)
2879 #undef VSPLTI
2880
2881 #define VSR(suffix, element) \
2882 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2883 { \
2884 int i; \
2885 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2886 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2887 unsigned int shift = b->element[i] & mask; \
2888 r->element[i] = a->element[i] >> shift; \
2889 } \
2890 }
2891 VSR(ab, s8)
2892 VSR(ah, s16)
2893 VSR(aw, s32)
2894 VSR(b, u8)
2895 VSR(h, u16)
2896 VSR(w, u32)
2897 #undef VSR
2898
2899 void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2900 {
2901 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2902
2903 #if defined (HOST_WORDS_BIGENDIAN)
2904 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2905 memset (&r->u8[0], 0, sh);
2906 #else
2907 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2908 memset (&r->u8[16-sh], 0, sh);
2909 #endif
2910 }
2911
2912 void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2913 {
2914 int i;
2915 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2916 r->u32[i] = a->u32[i] >= b->u32[i];
2917 }
2918 }
2919
2920 void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2921 {
2922 int64_t t;
2923 int i, upper;
2924 ppc_avr_t result;
2925 int sat = 0;
2926
2927 #if defined(HOST_WORDS_BIGENDIAN)
2928 upper = ARRAY_SIZE(r->s32)-1;
2929 #else
2930 upper = 0;
2931 #endif
2932 t = (int64_t)b->s32[upper];
2933 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2934 t += a->s32[i];
2935 result.s32[i] = 0;
2936 }
2937 result.s32[upper] = cvtsdsw(t, &sat);
2938 *r = result;
2939
2940 if (sat) {
2941 env->vscr |= (1 << VSCR_SAT);
2942 }
2943 }
2944
2945 void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2946 {
2947 int i, j, upper;
2948 ppc_avr_t result;
2949 int sat = 0;
2950
2951 #if defined(HOST_WORDS_BIGENDIAN)
2952 upper = 1;
2953 #else
2954 upper = 0;
2955 #endif
2956 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2957 int64_t t = (int64_t)b->s32[upper+i*2];
2958 result.u64[i] = 0;
2959 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2960 t += a->s32[2*i+j];
2961 }
2962 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2963 }
2964
2965 *r = result;
2966 if (sat) {
2967 env->vscr |= (1 << VSCR_SAT);
2968 }
2969 }
2970
2971 void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2972 {
2973 int i, j;
2974 int sat = 0;
2975
2976 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2977 int64_t t = (int64_t)b->s32[i];
2978 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2979 t += a->s8[4*i+j];
2980 }
2981 r->s32[i] = cvtsdsw(t, &sat);
2982 }
2983
2984 if (sat) {
2985 env->vscr |= (1 << VSCR_SAT);
2986 }
2987 }
2988
2989 void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2990 {
2991 int sat = 0;
2992 int i;
2993
2994 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2995 int64_t t = (int64_t)b->s32[i];
2996 t += a->s16[2*i] + a->s16[2*i+1];
2997 r->s32[i] = cvtsdsw(t, &sat);
2998 }
2999
3000 if (sat) {
3001 env->vscr |= (1 << VSCR_SAT);
3002 }
3003 }
3004
3005 void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
3006 {
3007 int i, j;
3008 int sat = 0;
3009
3010 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
3011 uint64_t t = (uint64_t)b->u32[i];
3012 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
3013 t += a->u8[4*i+j];
3014 }
3015 r->u32[i] = cvtuduw(t, &sat);
3016 }
3017
3018 if (sat) {
3019 env->vscr |= (1 << VSCR_SAT);
3020 }
3021 }
3022
3023 #if defined(HOST_WORDS_BIGENDIAN)
3024 #define UPKHI 1
3025 #define UPKLO 0
3026 #else
3027 #define UPKHI 0
3028 #define UPKLO 1
3029 #endif
3030 #define VUPKPX(suffix, hi) \
3031 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
3032 { \
3033 int i; \
3034 ppc_avr_t result; \
3035 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
3036 uint16_t e = b->u16[hi ? i : i+4]; \
3037 uint8_t a = (e >> 15) ? 0xff : 0; \
3038 uint8_t r = (e >> 10) & 0x1f; \
3039 uint8_t g = (e >> 5) & 0x1f; \
3040 uint8_t b = e & 0x1f; \
3041 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3042 } \
3043 *r = result; \
3044 }
3045 VUPKPX(lpx, UPKLO)
3046 VUPKPX(hpx, UPKHI)
3047 #undef VUPKPX
3048
3049 #define VUPK(suffix, unpacked, packee, hi) \
3050 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
3051 { \
3052 int i; \
3053 ppc_avr_t result; \
3054 if (hi) { \
3055 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3056 result.unpacked[i] = b->packee[i]; \
3057 } \
3058 } else { \
3059 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3060 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3061 } \
3062 } \
3063 *r = result; \
3064 }
3065 VUPK(hsb, s16, s8, UPKHI)
3066 VUPK(hsh, s32, s16, UPKHI)
3067 VUPK(lsb, s16, s8, UPKLO)
3068 VUPK(lsh, s32, s16, UPKLO)
3069 #undef VUPK
3070 #undef UPKHI
3071 #undef UPKLO
3072
3073 #undef DO_HANDLE_NAN
3074 #undef HANDLE_NAN1
3075 #undef HANDLE_NAN2
3076 #undef HANDLE_NAN3
3077 #undef VECTOR_FOR_INORDER_I
3078 #undef HI_IDX
3079 #undef LO_IDX
3080
3081 /*****************************************************************************/
3082 /* SPE extension helpers */
3083 /* Use a table to make this quicker */
3084 static uint8_t hbrev[16] = {
3085 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3086 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3087 };
3088
3089 static inline uint8_t byte_reverse(uint8_t val)
3090 {
3091 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3092 }
3093
3094 static inline uint32_t word_reverse(uint32_t val)
3095 {
3096 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3097 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3098 }
3099
3100 #define MASKBITS 16 // Random value - to be fixed (implementation dependant)
3101 target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
3102 {
3103 uint32_t a, b, d, mask;
3104
3105 mask = UINT32_MAX >> (32 - MASKBITS);
3106 a = arg1 & mask;
3107 b = arg2 & mask;
3108 d = word_reverse(1 + word_reverse(a | ~b));
3109 return (arg1 & ~mask) | (d & b);
3110 }
3111
3112 uint32_t helper_cntlsw32 (uint32_t val)
3113 {
3114 if (val & 0x80000000)
3115 return clz32(~val);
3116 else
3117 return clz32(val);
3118 }
3119
3120 uint32_t helper_cntlzw32 (uint32_t val)
3121 {
3122 return clz32(val);
3123 }
3124
3125 /* Single-precision floating-point conversions */
3126 static inline uint32_t efscfsi(uint32_t val)
3127 {
3128 CPU_FloatU u;
3129
3130 u.f = int32_to_float32(val, &env->vec_status);
3131
3132 return u.l;
3133 }
3134
3135 static inline uint32_t efscfui(uint32_t val)
3136 {
3137 CPU_FloatU u;
3138
3139 u.f = uint32_to_float32(val, &env->vec_status);
3140
3141 return u.l;
3142 }
3143
3144 static inline int32_t efsctsi(uint32_t val)
3145 {
3146 CPU_FloatU u;
3147
3148 u.l = val;
3149 /* NaN are not treated the same way IEEE 754 does */
3150 if (unlikely(float32_is_quiet_nan(u.f)))
3151 return 0;
3152
3153 return float32_to_int32(u.f, &env->vec_status);
3154 }
3155
3156 static inline uint32_t efsctui(uint32_t val)
3157 {
3158 CPU_FloatU u;
3159
3160 u.l = val;
3161 /* NaN are not treated the same way IEEE 754 does */
3162 if (unlikely(float32_is_quiet_nan(u.f)))
3163 return 0;
3164
3165 return float32_to_uint32(u.f, &env->vec_status);
3166 }
3167
3168 static inline uint32_t efsctsiz(uint32_t val)
3169 {
3170 CPU_FloatU u;
3171
3172 u.l = val;
3173 /* NaN are not treated the same way IEEE 754 does */
3174 if (unlikely(float32_is_quiet_nan(u.f)))
3175 return 0;
3176
3177 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3178 }
3179
3180 static inline uint32_t efsctuiz(uint32_t val)
3181 {
3182 CPU_FloatU u;
3183
3184 u.l = val;
3185 /* NaN are not treated the same way IEEE 754 does */
3186 if (unlikely(float32_is_quiet_nan(u.f)))
3187 return 0;
3188
3189 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3190 }
3191
3192 static inline uint32_t efscfsf(uint32_t val)
3193 {
3194 CPU_FloatU u;
3195 float32 tmp;
3196
3197 u.f = int32_to_float32(val, &env->vec_status);
3198 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3199 u.f = float32_div(u.f, tmp, &env->vec_status);
3200
3201 return u.l;
3202 }
3203
3204 static inline uint32_t efscfuf(uint32_t val)
3205 {
3206 CPU_FloatU u;
3207 float32 tmp;
3208
3209 u.f = uint32_to_float32(val, &env->vec_status);
3210 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3211 u.f = float32_div(u.f, tmp, &env->vec_status);
3212
3213 return u.l;
3214 }
3215
3216 static inline uint32_t efsctsf(uint32_t val)
3217 {
3218 CPU_FloatU u;
3219 float32 tmp;
3220
3221 u.l = val;
3222 /* NaN are not treated the same way IEEE 754 does */
3223 if (unlikely(float32_is_quiet_nan(u.f)))
3224 return 0;
3225 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3226 u.f = float32_mul(u.f, tmp, &env->vec_status);
3227
3228 return float32_to_int32(u.f, &env->vec_status);
3229 }
3230
3231 static inline uint32_t efsctuf(uint32_t val)
3232 {
3233 CPU_FloatU u;
3234 float32 tmp;
3235
3236 u.l = val;
3237 /* NaN are not treated the same way IEEE 754 does */
3238 if (unlikely(float32_is_quiet_nan(u.f)))
3239 return 0;
3240 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3241 u.f = float32_mul(u.f, tmp, &env->vec_status);
3242
3243 return float32_to_uint32(u.f, &env->vec_status);
3244 }
3245
3246 #define HELPER_SPE_SINGLE_CONV(name) \
3247 uint32_t helper_e##name (uint32_t val) \
3248 { \
3249 return e##name(val); \
3250 }
3251 /* efscfsi */
3252 HELPER_SPE_SINGLE_CONV(fscfsi);
3253 /* efscfui */
3254 HELPER_SPE_SINGLE_CONV(fscfui);
3255 /* efscfuf */
3256 HELPER_SPE_SINGLE_CONV(fscfuf);
3257 /* efscfsf */
3258 HELPER_SPE_SINGLE_CONV(fscfsf);
3259 /* efsctsi */
3260 HELPER_SPE_SINGLE_CONV(fsctsi);
3261 /* efsctui */
3262 HELPER_SPE_SINGLE_CONV(fsctui);
3263 /* efsctsiz */
3264 HELPER_SPE_SINGLE_CONV(fsctsiz);
3265 /* efsctuiz */
3266 HELPER_SPE_SINGLE_CONV(fsctuiz);
3267 /* efsctsf */
3268 HELPER_SPE_SINGLE_CONV(fsctsf);
3269 /* efsctuf */
3270 HELPER_SPE_SINGLE_CONV(fsctuf);
3271
3272 #define HELPER_SPE_VECTOR_CONV(name) \
3273 uint64_t helper_ev##name (uint64_t val) \
3274 { \
3275 return ((uint64_t)e##name(val >> 32) << 32) | \
3276 (uint64_t)e##name(val); \
3277 }
3278 /* evfscfsi */
3279 HELPER_SPE_VECTOR_CONV(fscfsi);
3280 /* evfscfui */
3281 HELPER_SPE_VECTOR_CONV(fscfui);
3282 /* evfscfuf */
3283 HELPER_SPE_VECTOR_CONV(fscfuf);
3284 /* evfscfsf */
3285 HELPER_SPE_VECTOR_CONV(fscfsf);
3286 /* evfsctsi */
3287 HELPER_SPE_VECTOR_CONV(fsctsi);
3288 /* evfsctui */
3289 HELPER_SPE_VECTOR_CONV(fsctui);
3290 /* evfsctsiz */
3291 HELPER_SPE_VECTOR_CONV(fsctsiz);
3292 /* evfsctuiz */
3293 HELPER_SPE_VECTOR_CONV(fsctuiz);
3294 /* evfsctsf */
3295 HELPER_SPE_VECTOR_CONV(fsctsf);
3296 /* evfsctuf */
3297 HELPER_SPE_VECTOR_CONV(fsctuf);
3298
3299 /* Single-precision floating-point arithmetic */
3300 static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
3301 {
3302 CPU_FloatU u1, u2;
3303 u1.l = op1;
3304 u2.l = op2;
3305 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3306 return u1.l;
3307 }
3308
3309 static inline uint32_t efssub(uint32_t op1, uint32_t op2)
3310 {
3311 CPU_FloatU u1, u2;
3312 u1.l = op1;
3313 u2.l = op2;
3314 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3315 return u1.l;
3316 }
3317
3318 static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
3319 {
3320 CPU_FloatU u1, u2;
3321 u1.l = op1;
3322 u2.l = op2;
3323 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3324 return u1.l;
3325 }
3326
3327 static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
3328 {
3329 CPU_FloatU u1, u2;
3330 u1.l = op1;
3331 u2.l = op2;
3332 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3333 return u1.l;
3334 }
3335
3336 #define HELPER_SPE_SINGLE_ARITH(name) \
3337 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3338 { \
3339 return e##name(op1, op2); \
3340 }
3341 /* efsadd */
3342 HELPER_SPE_SINGLE_ARITH(fsadd);
3343 /* efssub */
3344 HELPER_SPE_SINGLE_ARITH(fssub);
3345 /* efsmul */
3346 HELPER_SPE_SINGLE_ARITH(fsmul);
3347 /* efsdiv */
3348 HELPER_SPE_SINGLE_ARITH(fsdiv);
3349
3350 #define HELPER_SPE_VECTOR_ARITH(name) \
3351 uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3352 { \
3353 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3354 (uint64_t)e##name(op1, op2); \
3355 }
3356 /* evfsadd */
3357 HELPER_SPE_VECTOR_ARITH(fsadd);
3358 /* evfssub */
3359 HELPER_SPE_VECTOR_ARITH(fssub);
3360 /* evfsmul */
3361 HELPER_SPE_VECTOR_ARITH(fsmul);
3362 /* evfsdiv */
3363 HELPER_SPE_VECTOR_ARITH(fsdiv);
3364
3365 /* Single-precision floating-point comparisons */
3366 static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
3367 {
3368 CPU_FloatU u1, u2;
3369 u1.l = op1;
3370 u2.l = op2;
3371 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3372 }
3373
3374 static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
3375 {
3376 CPU_FloatU u1, u2;
3377 u1.l = op1;
3378 u2.l = op2;
3379 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3380 }
3381
3382 static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
3383 {
3384 CPU_FloatU u1, u2;
3385 u1.l = op1;
3386 u2.l = op2;
3387 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3388 }
3389
3390 static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
3391 {
3392 /* XXX: TODO: test special values (NaN, infinites, ...) */
3393 return efststlt(op1, op2);
3394 }
3395
3396 static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
3397 {
3398 /* XXX: TODO: test special values (NaN, infinites, ...) */
3399 return efststgt(op1, op2);
3400 }
3401
3402 static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
3403 {
3404 /* XXX: TODO: test special values (NaN, infinites, ...) */
3405 return efststeq(op1, op2);
3406 }
3407
3408 #define HELPER_SINGLE_SPE_CMP(name) \
3409 uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3410 { \
3411 return e##name(op1, op2) << 2; \
3412 }
3413 /* efststlt */
3414 HELPER_SINGLE_SPE_CMP(fststlt);
3415 /* efststgt */
3416 HELPER_SINGLE_SPE_CMP(fststgt);
3417 /* efststeq */
3418 HELPER_SINGLE_SPE_CMP(fststeq);
3419 /* efscmplt */
3420 HELPER_SINGLE_SPE_CMP(fscmplt);
3421 /* efscmpgt */
3422 HELPER_SINGLE_SPE_CMP(fscmpgt);
3423 /* efscmpeq */
3424 HELPER_SINGLE_SPE_CMP(fscmpeq);
3425
3426 static inline uint32_t evcmp_merge(int t0, int t1)
3427 {
3428 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3429 }
3430
3431 #define HELPER_VECTOR_SPE_CMP(name) \
3432 uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3433 { \
3434 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3435 }
3436 /* evfststlt */
3437 HELPER_VECTOR_SPE_CMP(fststlt);
3438 /* evfststgt */
3439 HELPER_VECTOR_SPE_CMP(fststgt);
3440 /* evfststeq */
3441 HELPER_VECTOR_SPE_CMP(fststeq);
3442 /* evfscmplt */
3443 HELPER_VECTOR_SPE_CMP(fscmplt);
3444 /* evfscmpgt */
3445 HELPER_VECTOR_SPE_CMP(fscmpgt);
3446 /* evfscmpeq */
3447 HELPER_VECTOR_SPE_CMP(fscmpeq);
3448
3449 /* Double-precision floating-point conversion */
3450 uint64_t helper_efdcfsi (uint32_t val)
3451 {
3452 CPU_DoubleU u;
3453
3454 u.d = int32_to_float64(val, &env->vec_status);
3455
3456 return u.ll;
3457 }
3458
3459 uint64_t helper_efdcfsid (uint64_t val)
3460 {
3461 CPU_DoubleU u;
3462
3463 u.d = int64_to_float64(val, &env->vec_status);
3464
3465 return u.ll;
3466 }
3467
3468 uint64_t helper_efdcfui (uint32_t val)
3469 {
3470 CPU_DoubleU u;
3471
3472 u.d = uint32_to_float64(val, &env->vec_status);
3473
3474 return u.ll;
3475 }
3476
3477 uint64_t helper_efdcfuid (uint64_t val)
3478 {
3479 CPU_DoubleU u;
3480
3481 u.d = uint64_to_float64(val, &env->vec_status);
3482
3483 return u.ll;
3484 }
3485
3486 uint32_t helper_efdctsi (uint64_t val)
3487 {
3488 CPU_DoubleU u;
3489
3490 u.ll = val;
3491 /* NaN are not treated the same way IEEE 754 does */
3492 if (unlikely(float64_is_any_nan(u.d))) {
3493 return 0;
3494 }
3495
3496 return float64_to_int32(u.d, &env->vec_status);
3497 }
3498
3499 uint32_t helper_efdctui (uint64_t val)
3500 {
3501 CPU_DoubleU u;
3502
3503 u.ll = val;
3504 /* NaN are not treated the same way IEEE 754 does */
3505 if (unlikely(float64_is_any_nan(u.d))) {
3506 return 0;
3507 }
3508
3509 return float64_to_uint32(u.d, &env->vec_status);
3510 }
3511
3512 uint32_t helper_efdctsiz (uint64_t val)
3513 {
3514 CPU_DoubleU u;
3515
3516 u.ll = val;
3517 /* NaN are not treated the same way IEEE 754 does */
3518 if (unlikely(float64_is_any_nan(u.d))) {
3519 return 0;
3520 }
3521
3522 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3523 }
3524
3525 uint64_t helper_efdctsidz (uint64_t val)
3526 {
3527 CPU_DoubleU u;
3528
3529 u.ll = val;
3530 /* NaN are not treated the same way IEEE 754 does */
3531 if (unlikely(float64_is_any_nan(u.d))) {
3532 return 0;
3533 }
3534
3535 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3536 }
3537
3538 uint32_t helper_efdctuiz (uint64_t val)
3539 {
3540 CPU_DoubleU u;
3541
3542 u.ll = val;
3543 /* NaN are not treated the same way IEEE 754 does */
3544 if (unlikely(float64_is_any_nan(u.d))) {
3545 return 0;
3546 }
3547
3548 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3549 }
3550
3551 uint64_t helper_efdctuidz (uint64_t val)
3552 {
3553 CPU_DoubleU u;
3554
3555 u.ll = val;
3556 /* NaN are not treated the same way IEEE 754 does */
3557 if (unlikely(float64_is_any_nan(u.d))) {
3558 return 0;
3559 }
3560
3561 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3562 }
3563
3564 uint64_t helper_efdcfsf (uint32_t val)
3565 {
3566 CPU_DoubleU u;
3567 float64 tmp;
3568
3569 u.d = int32_to_float64(val, &env->vec_status);
3570 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3571 u.d = float64_div(u.d, tmp, &env->vec_status);
3572
3573 return u.ll;
3574 }
3575
3576 uint64_t helper_efdcfuf (uint32_t val)
3577 {
3578 CPU_DoubleU u;
3579 float64 tmp;
3580
3581 u.d = uint32_to_float64(val, &env->vec_status);
3582 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3583 u.d = float64_div(u.d, tmp, &env->vec_status);
3584
3585 return u.ll;
3586 }
3587
3588 uint32_t helper_efdctsf (uint64_t val)
3589 {
3590 CPU_DoubleU u;
3591 float64 tmp;
3592
3593 u.ll = val;
3594 /* NaN are not treated the same way IEEE 754 does */
3595 if (unlikely(float64_is_any_nan(u.d))) {
3596 return 0;
3597 }
3598 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3599 u.d = float64_mul(u.d, tmp, &env->vec_status);
3600
3601 return float64_to_int32(u.d, &env->vec_status);
3602 }
3603
3604 uint32_t helper_efdctuf (uint64_t val)
3605 {
3606 CPU_DoubleU u;
3607 float64 tmp;
3608
3609 u.ll = val;
3610 /* NaN are not treated the same way IEEE 754 does */
3611 if (unlikely(float64_is_any_nan(u.d))) {
3612 return 0;
3613 }
3614 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3615 u.d = float64_mul(u.d, tmp, &env->vec_status);
3616
3617 return float64_to_uint32(u.d, &env->vec_status);
3618 }
3619
3620 uint32_t helper_efscfd (uint64_t val)
3621 {
3622 CPU_DoubleU u1;
3623 CPU_FloatU u2;
3624
3625 u1.ll = val;
3626 u2.f = float64_to_float32(u1.d, &env->vec_status);
3627
3628 return u2.l;
3629 }
3630
3631 uint64_t helper_efdcfs (uint32_t val)
3632 {
3633 CPU_DoubleU u2;
3634 CPU_FloatU u1;
3635
3636 u1.l = val;
3637 u2.d = float32_to_float64(u1.f, &env->vec_status);
3638
3639 return u2.ll;
3640 }
3641
3642 /* Double precision fixed-point arithmetic */
3643 uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
3644 {
3645 CPU_DoubleU u1, u2;
3646 u1.ll = op1;
3647 u2.ll = op2;
3648 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3649 return u1.ll;
3650 }
3651
3652 uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
3653 {
3654 CPU_DoubleU u1, u2;
3655 u1.ll = op1;
3656 u2.ll = op2;
3657 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3658 return u1.ll;
3659 }
3660
3661 uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3662 {
3663 CPU_DoubleU u1, u2;
3664 u1.ll = op1;
3665 u2.ll = op2;
3666 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3667 return u1.ll;
3668 }
3669
3670 uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3671 {
3672 CPU_DoubleU u1, u2;
3673 u1.ll = op1;
3674 u2.ll = op2;
3675 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3676 return u1.ll;
3677 }
3678
3679 /* Double precision floating point helpers */
3680 uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3681 {
3682 CPU_DoubleU u1, u2;
3683 u1.ll = op1;
3684 u2.ll = op2;
3685 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3686 }
3687
3688 uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3689 {
3690 CPU_DoubleU u1, u2;
3691 u1.ll = op1;
3692 u2.ll = op2;
3693 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3694 }
3695
3696 uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3697 {
3698 CPU_DoubleU u1, u2;
3699 u1.ll = op1;
3700 u2.ll = op2;
3701 return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3702 }
3703
3704 uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
3705 {
3706 /* XXX: TODO: test special values (NaN, infinites, ...) */
3707 return helper_efdtstlt(op1, op2);
3708 }
3709
3710 uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3711 {
3712 /* XXX: TODO: test special values (NaN, infinites, ...) */
3713 return helper_efdtstgt(op1, op2);
3714 }
3715
3716 uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3717 {
3718 /* XXX: TODO: test special values (NaN, infinites, ...) */
3719 return helper_efdtsteq(op1, op2);
3720 }
3721
3722 /*****************************************************************************/
3723 /* Softmmu support */
3724 #if !defined (CONFIG_USER_ONLY)
3725
3726 #define MMUSUFFIX _mmu
3727
3728 #define SHIFT 0
3729 #include "softmmu_template.h"
3730
3731 #define SHIFT 1
3732 #include "softmmu_template.h"
3733
3734 #define SHIFT 2
3735 #include "softmmu_template.h"
3736
3737 #define SHIFT 3
3738 #include "softmmu_template.h"
3739
3740 /* try to fill the TLB and return an exception if error. If retaddr is
3741 NULL, it means that the function was called in C code (i.e. not
3742 from generated code or from helper.c) */
3743 /* XXX: fix it to restore all registers */
3744 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
3745 {
3746 TranslationBlock *tb;
3747 CPUState *saved_env;
3748 unsigned long pc;
3749 int ret;
3750
3751 /* XXX: hack to restore env in all cases, even if not called from
3752 generated code */
3753 saved_env = env;
3754 env = cpu_single_env;
3755 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
3756 if (unlikely(ret != 0)) {
3757 if (likely(retaddr)) {
3758 /* now we have a real cpu fault */
3759 pc = (unsigned long)retaddr;
3760 tb = tb_find_pc(pc);
3761 if (likely(tb)) {
3762 /* the PC is inside the translated code. It means that we have
3763 a virtual CPU fault */
3764 cpu_restore_state(tb, env, pc, NULL);
3765 }
3766 }
3767 helper_raise_exception_err(env->exception_index, env->error_code);
3768 }
3769 env = saved_env;
3770 }
3771
3772 /* Segment registers load and store */
3773 target_ulong helper_load_sr (target_ulong sr_num)
3774 {
3775 #if defined(TARGET_PPC64)
3776 if (env->mmu_model & POWERPC_MMU_64)
3777 return ppc_load_sr(env, sr_num);
3778 #endif
3779 return env->sr[sr_num];
3780 }
3781
3782 void helper_store_sr (target_ulong sr_num, target_ulong val)
3783 {
3784 ppc_store_sr(env, sr_num, val);
3785 }
3786
3787 /* SLB management */
3788 #if defined(TARGET_PPC64)
3789 void helper_store_slb (target_ulong rb, target_ulong rs)
3790 {
3791 if (ppc_store_slb(env, rb, rs) < 0) {
3792 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3793 }
3794 }
3795
3796 target_ulong helper_load_slb_esid (target_ulong rb)
3797 {
3798 target_ulong rt;
3799
3800 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
3801 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3802 }
3803 return rt;
3804 }
3805
3806 target_ulong helper_load_slb_vsid (target_ulong rb)
3807 {
3808 target_ulong rt;
3809
3810 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
3811 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3812 }
3813 return rt;
3814 }
3815
3816 void helper_slbia (void)
3817 {
3818 ppc_slb_invalidate_all(env);
3819 }
3820
3821 void helper_slbie (target_ulong addr)
3822 {
3823 ppc_slb_invalidate_one(env, addr);
3824 }
3825
3826 #endif /* defined(TARGET_PPC64) */
3827
3828 /* TLB management */
3829 void helper_tlbia (void)
3830 {
3831 ppc_tlb_invalidate_all(env);
3832 }
3833
3834 void helper_tlbie (target_ulong addr)
3835 {
3836 ppc_tlb_invalidate_one(env, addr);
3837 }
3838
3839 /* Software driven TLBs management */
3840 /* PowerPC 602/603 software TLB load instructions helpers */
3841 static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3842 {
3843 target_ulong RPN, CMP, EPN;
3844 int way;
3845
3846 RPN = env->spr[SPR_RPA];
3847 if (is_code) {
3848 CMP = env->spr[SPR_ICMP];
3849 EPN = env->spr[SPR_IMISS];
3850 } else {
3851 CMP = env->spr[SPR_DCMP];
3852 EPN = env->spr[SPR_DMISS];
3853 }
3854 way = (env->spr[SPR_SRR1] >> 17) & 1;
3855 (void)EPN; /* avoid a compiler warning */
3856 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3857 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3858 RPN, way);
3859 /* Store this TLB */
3860 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3861 way, is_code, CMP, RPN);
3862 }
3863
3864 void helper_6xx_tlbd (target_ulong EPN)
3865 {
3866 do_6xx_tlb(EPN, 0);
3867 }
3868
3869 void helper_6xx_tlbi (target_ulong EPN)
3870 {
3871 do_6xx_tlb(EPN, 1);
3872 }
3873
3874 /* PowerPC 74xx software TLB load instructions helpers */
3875 static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3876 {
3877 target_ulong RPN, CMP, EPN;
3878 int way;
3879
3880 RPN = env->spr[SPR_PTELO];
3881 CMP = env->spr[SPR_PTEHI];
3882 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3883 way = env->spr[SPR_TLBMISS] & 0x3;
3884 (void)EPN; /* avoid a compiler warning */
3885 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3886 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3887 RPN, way);
3888 /* Store this TLB */
3889 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3890 way, is_code, CMP, RPN);
3891 }
3892
3893 void helper_74xx_tlbd (target_ulong EPN)
3894 {
3895 do_74xx_tlb(EPN, 0);
3896 }
3897
3898 void helper_74xx_tlbi (target_ulong EPN)
3899 {
3900 do_74xx_tlb(EPN, 1);
3901 }
3902
3903 static inline target_ulong booke_tlb_to_page_size(int size)
3904 {
3905 return 1024 << (2 * size);
3906 }
3907
3908 static inline int booke_page_size_to_tlb(target_ulong page_size)
3909 {
3910 int size;
3911
3912 switch (page_size) {
3913 case 0x00000400UL:
3914 size = 0x0;
3915 break;
3916 case 0x00001000UL:
3917 size = 0x1;
3918 break;
3919 case 0x00004000UL:
3920 size = 0x2;
3921 break;
3922 case 0x00010000UL:
3923 size = 0x3;
3924 break;
3925 case 0x00040000UL:
3926 size = 0x4;
3927 break;
3928 case 0x00100000UL:
3929 size = 0x5;
3930 break;
3931 case 0x00400000UL:
3932 size = 0x6;
3933 break;
3934 case 0x01000000UL:
3935 size = 0x7;
3936 break;
3937 case 0x04000000UL:
3938 size = 0x8;
3939 break;
3940 case 0x10000000UL:
3941 size = 0x9;
3942 break;
3943 case 0x40000000UL:
3944 size = 0xA;
3945 break;
3946 #if defined (TARGET_PPC64)
3947 case 0x000100000000ULL:
3948 size = 0xB;
3949 break;
3950 case 0x000400000000ULL:
3951 size = 0xC;
3952 break;
3953 case 0x001000000000ULL:
3954 size = 0xD;
3955 break;
3956 case 0x004000000000ULL:
3957 size = 0xE;
3958 break;
3959 case 0x010000000000ULL:
3960 size = 0xF;
3961 break;
3962 #endif
3963 default:
3964 size = -1;
3965 break;
3966 }
3967
3968 return size;
3969 }
3970
3971 /* Helpers for 4xx TLB management */
3972 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
3973
3974 #define PPC4XX_TLBHI_V 0x00000040
3975 #define PPC4XX_TLBHI_E 0x00000020
3976 #define PPC4XX_TLBHI_SIZE_MIN 0
3977 #define PPC4XX_TLBHI_SIZE_MAX 7
3978 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
3979 #define PPC4XX_TLBHI_SIZE_SHIFT 7
3980 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
3981
3982 #define PPC4XX_TLBLO_EX 0x00000200
3983 #define PPC4XX_TLBLO_WR 0x00000100
3984 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
3985 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
3986
3987 target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3988 {
3989 ppcemb_tlb_t *tlb;
3990 target_ulong ret;
3991 int size;
3992
3993 entry &= PPC4XX_TLB_ENTRY_MASK;
3994 tlb = &env->tlb[entry].tlbe;
3995 ret = tlb->EPN;
3996 if (tlb->prot & PAGE_VALID) {
3997 ret |= PPC4XX_TLBHI_V;
3998 }
3999 size = booke_page_size_to_tlb(tlb->size);
4000 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
4001 size = PPC4XX_TLBHI_SIZE_DEFAULT;
4002 }
4003 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
4004 env->spr[SPR_40x_PID] = tlb->PID;
4005 return ret;
4006 }
4007
4008 target_ulong helper_4xx_tlbre_lo (target_ulong entry)
4009 {
4010 ppcemb_tlb_t *tlb;
4011 target_ulong ret;
4012
4013 entry &= PPC4XX_TLB_ENTRY_MASK;
4014 tlb = &env->tlb[entry].tlbe;
4015 ret = tlb->RPN;
4016 if (tlb->prot & PAGE_EXEC) {
4017 ret |= PPC4XX_TLBLO_EX;
4018 }
4019 if (tlb->prot & PAGE_WRITE) {
4020 ret |= PPC4XX_TLBLO_WR;
4021 }
4022 return ret;
4023 }
4024
4025 void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
4026 {
4027 ppcemb_tlb_t *tlb;
4028 target_ulong page, end;
4029
4030 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
4031 val);
4032 entry &= PPC4XX_TLB_ENTRY_MASK;
4033 tlb = &env->tlb[entry].tlbe;
4034 /* Invalidate previous TLB (if it's valid) */
4035 if (tlb->prot & PAGE_VALID) {
4036 end = tlb->EPN + tlb->size;
4037 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
4038 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4039 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4040 tlb_flush_page(env, page);
4041 }
4042 }
4043 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4044 & PPC4XX_TLBHI_SIZE_MASK);
4045 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4046 * If this ever occurs, one should use the ppcemb target instead
4047 * of the ppc or ppc64 one
4048 */
4049 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
4050 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4051 "are not supported (%d)\n",
4052 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
4053 }
4054 tlb->EPN = val & ~(tlb->size - 1);
4055 if (val & PPC4XX_TLBHI_V) {
4056 tlb->prot |= PAGE_VALID;
4057 if (val & PPC4XX_TLBHI_E) {
4058 /* XXX: TO BE FIXED */
4059 cpu_abort(env,
4060 "Little-endian TLB entries are not supported by now\n");
4061 }
4062 } else {
4063 tlb->prot &= ~PAGE_VALID;
4064 }
4065 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
4066 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4067 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4068 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4069 tlb->prot & PAGE_READ ? 'r' : '-',
4070 tlb->prot & PAGE_WRITE ? 'w' : '-',
4071 tlb->prot & PAGE_EXEC ? 'x' : '-',
4072 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4073 /* Invalidate new TLB (if valid) */
4074 if (tlb->prot & PAGE_VALID) {
4075 end = tlb->EPN + tlb->size;
4076 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4077 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4078 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4079 tlb_flush_page(env, page);
4080 }
4081 }
4082 }
4083
4084 void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
4085 {
4086 ppcemb_tlb_t *tlb;
4087
4088 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4089 val);
4090 entry &= PPC4XX_TLB_ENTRY_MASK;
4091 tlb = &env->tlb[entry].tlbe;
4092 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4093 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
4094 tlb->prot = PAGE_READ;
4095 if (val & PPC4XX_TLBLO_EX) {
4096 tlb->prot |= PAGE_EXEC;
4097 }
4098 if (val & PPC4XX_TLBLO_WR) {
4099 tlb->prot |= PAGE_WRITE;
4100 }
4101 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4102 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4103 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4104 tlb->prot & PAGE_READ ? 'r' : '-',
4105 tlb->prot & PAGE_WRITE ? 'w' : '-',
4106 tlb->prot & PAGE_EXEC ? 'x' : '-',
4107 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4108 }
4109
4110 target_ulong helper_4xx_tlbsx (target_ulong address)
4111 {
4112 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4113 }
4114
4115 /* PowerPC 440 TLB management */
4116 void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
4117 {
4118 ppcemb_tlb_t *tlb;
4119 target_ulong EPN, RPN, size;
4120 int do_flush_tlbs;
4121
4122 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4123 __func__, word, (int)entry, value);
4124 do_flush_tlbs = 0;
4125 entry &= 0x3F;
4126 tlb = &env->tlb[entry].tlbe;
4127 switch (word) {
4128 default:
4129 /* Just here to please gcc */
4130 case 0:
4131 EPN = value & 0xFFFFFC00;
4132 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
4133 do_flush_tlbs = 1;
4134 tlb->EPN = EPN;
4135 size = booke_tlb_to_page_size((value >> 4) & 0xF);
4136 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4137 do_flush_tlbs = 1;
4138 tlb->size = size;
4139 tlb->attr &= ~0x1;
4140 tlb->attr |= (value >> 8) & 1;
4141 if (value & 0x200) {
4142 tlb->prot |= PAGE_VALID;
4143 } else {
4144 if (tlb->prot & PAGE_VALID) {
4145 tlb->prot &= ~PAGE_VALID;
4146 do_flush_tlbs = 1;
4147 }
4148 }
4149 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4150 if (do_flush_tlbs)
4151 tlb_flush(env, 1);
4152 break;
4153 case 1:
4154 RPN = value & 0xFFFFFC0F;
4155 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4156 tlb_flush(env, 1);
4157 tlb->RPN = RPN;
4158 break;
4159 case 2:
4160 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4161 tlb->prot = tlb->prot & PAGE_VALID;
4162 if (value & 0x1)
4163 tlb->prot |= PAGE_READ << 4;
4164 if (value & 0x2)
4165 tlb->prot |= PAGE_WRITE << 4;
4166 if (value & 0x4)
4167 tlb->prot |= PAGE_EXEC << 4;
4168 if (value & 0x8)
4169 tlb->prot |= PAGE_READ;
4170 if (value & 0x10)
4171 tlb->prot |= PAGE_WRITE;
4172 if (value & 0x20)
4173 tlb->prot |= PAGE_EXEC;
4174 break;
4175 }
4176 }
4177
4178 target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
4179 {
4180 ppcemb_tlb_t *tlb;
4181 target_ulong ret;
4182 int size;
4183
4184 entry &= 0x3F;
4185 tlb = &env->tlb[entry].tlbe;
4186 switch (word) {
4187 default:
4188 /* Just here to please gcc */
4189 case 0:
4190 ret = tlb->EPN;
4191 size = booke_page_size_to_tlb(tlb->size);
4192 if (size < 0 || size > 0xF)
4193 size = 1;
4194 ret |= size << 4;
4195 if (tlb->attr & 0x1)
4196 ret |= 0x100;
4197 if (tlb->prot & PAGE_VALID)
4198 ret |= 0x200;
4199 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4200 env->spr[SPR_440_MMUCR] |= tlb->PID;
4201 break;
4202 case 1:
4203 ret = tlb->RPN;
4204 break;
4205 case 2:
4206 ret = tlb->attr & ~0x1;
4207 if (tlb->prot & (PAGE_READ << 4))
4208 ret |= 0x1;
4209 if (tlb->prot & (PAGE_WRITE << 4))
4210 ret |= 0x2;
4211 if (tlb->prot & (PAGE_EXEC << 4))
4212 ret |= 0x4;
4213 if (tlb->prot & PAGE_READ)
4214 ret |= 0x8;
4215 if (tlb->prot & PAGE_WRITE)
4216 ret |= 0x10;
4217 if (tlb->prot & PAGE_EXEC)
4218 ret |= 0x20;
4219 break;
4220 }
4221 return ret;
4222 }
4223
4224 target_ulong helper_440_tlbsx (target_ulong address)
4225 {
4226 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4227 }
4228
4229 #endif /* !CONFIG_USER_ONLY */