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