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