]> Git Repo - qemu.git/blob - target-ppc/op_helper.c
PPC: E500: Implement msgsnd
[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(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
3718               void *retaddr)
3719 {
3720     TranslationBlock *tb;
3721     CPUState *saved_env;
3722     unsigned long pc;
3723     int ret;
3724
3725     saved_env = env;
3726     env = env1;
3727     ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
3728     if (unlikely(ret != 0)) {
3729         if (likely(retaddr)) {
3730             /* now we have a real cpu fault */
3731             pc = (unsigned long)retaddr;
3732             tb = tb_find_pc(pc);
3733             if (likely(tb)) {
3734                 /* the PC is inside the translated code. It means that we have
3735                    a virtual CPU fault */
3736                 cpu_restore_state(tb, env, pc);
3737             }
3738         }
3739         helper_raise_exception_err(env->exception_index, env->error_code);
3740     }
3741     env = saved_env;
3742 }
3743
3744 /* Segment registers load and store */
3745 target_ulong helper_load_sr (target_ulong sr_num)
3746 {
3747 #if defined(TARGET_PPC64)
3748     if (env->mmu_model & POWERPC_MMU_64)
3749         return ppc_load_sr(env, sr_num);
3750 #endif
3751     return env->sr[sr_num];
3752 }
3753
3754 void helper_store_sr (target_ulong sr_num, target_ulong val)
3755 {
3756     ppc_store_sr(env, sr_num, val);
3757 }
3758
3759 /* SLB management */
3760 #if defined(TARGET_PPC64)
3761 void helper_store_slb (target_ulong rb, target_ulong rs)
3762 {
3763     if (ppc_store_slb(env, rb, rs) < 0) {
3764         helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3765     }
3766 }
3767
3768 target_ulong helper_load_slb_esid (target_ulong rb)
3769 {
3770     target_ulong rt;
3771
3772     if (ppc_load_slb_esid(env, rb, &rt) < 0) {
3773         helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3774     }
3775     return rt;
3776 }
3777
3778 target_ulong helper_load_slb_vsid (target_ulong rb)
3779 {
3780     target_ulong rt;
3781
3782     if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
3783         helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3784     }
3785     return rt;
3786 }
3787
3788 void helper_slbia (void)
3789 {
3790     ppc_slb_invalidate_all(env);
3791 }
3792
3793 void helper_slbie (target_ulong addr)
3794 {
3795     ppc_slb_invalidate_one(env, addr);
3796 }
3797
3798 #endif /* defined(TARGET_PPC64) */
3799
3800 /* TLB management */
3801 void helper_tlbia (void)
3802 {
3803     ppc_tlb_invalidate_all(env);
3804 }
3805
3806 void helper_tlbie (target_ulong addr)
3807 {
3808     ppc_tlb_invalidate_one(env, addr);
3809 }
3810
3811 /* Software driven TLBs management */
3812 /* PowerPC 602/603 software TLB load instructions helpers */
3813 static void do_6xx_tlb (target_ulong new_EPN, int is_code)
3814 {
3815     target_ulong RPN, CMP, EPN;
3816     int way;
3817
3818     RPN = env->spr[SPR_RPA];
3819     if (is_code) {
3820         CMP = env->spr[SPR_ICMP];
3821         EPN = env->spr[SPR_IMISS];
3822     } else {
3823         CMP = env->spr[SPR_DCMP];
3824         EPN = env->spr[SPR_DMISS];
3825     }
3826     way = (env->spr[SPR_SRR1] >> 17) & 1;
3827     (void)EPN; /* avoid a compiler warning */
3828     LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3829               " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3830               RPN, way);
3831     /* Store this TLB */
3832     ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3833                      way, is_code, CMP, RPN);
3834 }
3835
3836 void helper_6xx_tlbd (target_ulong EPN)
3837 {
3838     do_6xx_tlb(EPN, 0);
3839 }
3840
3841 void helper_6xx_tlbi (target_ulong EPN)
3842 {
3843     do_6xx_tlb(EPN, 1);
3844 }
3845
3846 /* PowerPC 74xx software TLB load instructions helpers */
3847 static void do_74xx_tlb (target_ulong new_EPN, int is_code)
3848 {
3849     target_ulong RPN, CMP, EPN;
3850     int way;
3851
3852     RPN = env->spr[SPR_PTELO];
3853     CMP = env->spr[SPR_PTEHI];
3854     EPN = env->spr[SPR_TLBMISS] & ~0x3;
3855     way = env->spr[SPR_TLBMISS] & 0x3;
3856     (void)EPN; /* avoid a compiler warning */
3857     LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3858               " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3859               RPN, way);
3860     /* Store this TLB */
3861     ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3862                      way, is_code, CMP, RPN);
3863 }
3864
3865 void helper_74xx_tlbd (target_ulong EPN)
3866 {
3867     do_74xx_tlb(EPN, 0);
3868 }
3869
3870 void helper_74xx_tlbi (target_ulong EPN)
3871 {
3872     do_74xx_tlb(EPN, 1);
3873 }
3874
3875 static inline target_ulong booke_tlb_to_page_size(int size)
3876 {
3877     return 1024 << (2 * size);
3878 }
3879
3880 static inline int booke_page_size_to_tlb(target_ulong page_size)
3881 {
3882     int size;
3883
3884     switch (page_size) {
3885     case 0x00000400UL:
3886         size = 0x0;
3887         break;
3888     case 0x00001000UL:
3889         size = 0x1;
3890         break;
3891     case 0x00004000UL:
3892         size = 0x2;
3893         break;
3894     case 0x00010000UL:
3895         size = 0x3;
3896         break;
3897     case 0x00040000UL:
3898         size = 0x4;
3899         break;
3900     case 0x00100000UL:
3901         size = 0x5;
3902         break;
3903     case 0x00400000UL:
3904         size = 0x6;
3905         break;
3906     case 0x01000000UL:
3907         size = 0x7;
3908         break;
3909     case 0x04000000UL:
3910         size = 0x8;
3911         break;
3912     case 0x10000000UL:
3913         size = 0x9;
3914         break;
3915     case 0x40000000UL:
3916         size = 0xA;
3917         break;
3918 #if defined (TARGET_PPC64)
3919     case 0x000100000000ULL:
3920         size = 0xB;
3921         break;
3922     case 0x000400000000ULL:
3923         size = 0xC;
3924         break;
3925     case 0x001000000000ULL:
3926         size = 0xD;
3927         break;
3928     case 0x004000000000ULL:
3929         size = 0xE;
3930         break;
3931     case 0x010000000000ULL:
3932         size = 0xF;
3933         break;
3934 #endif
3935     default:
3936         size = -1;
3937         break;
3938     }
3939
3940     return size;
3941 }
3942
3943 /* Helpers for 4xx TLB management */
3944 #define PPC4XX_TLB_ENTRY_MASK       0x0000003f  /* Mask for 64 TLB entries */
3945
3946 #define PPC4XX_TLBHI_V              0x00000040
3947 #define PPC4XX_TLBHI_E              0x00000020
3948 #define PPC4XX_TLBHI_SIZE_MIN       0
3949 #define PPC4XX_TLBHI_SIZE_MAX       7
3950 #define PPC4XX_TLBHI_SIZE_DEFAULT   1
3951 #define PPC4XX_TLBHI_SIZE_SHIFT     7
3952 #define PPC4XX_TLBHI_SIZE_MASK      0x00000007
3953
3954 #define PPC4XX_TLBLO_EX             0x00000200
3955 #define PPC4XX_TLBLO_WR             0x00000100
3956 #define PPC4XX_TLBLO_ATTR_MASK      0x000000FF
3957 #define PPC4XX_TLBLO_RPN_MASK       0xFFFFFC00
3958
3959 target_ulong helper_4xx_tlbre_hi (target_ulong entry)
3960 {
3961     ppcemb_tlb_t *tlb;
3962     target_ulong ret;
3963     int size;
3964
3965     entry &= PPC4XX_TLB_ENTRY_MASK;
3966     tlb = &env->tlb.tlbe[entry];
3967     ret = tlb->EPN;
3968     if (tlb->prot & PAGE_VALID) {
3969         ret |= PPC4XX_TLBHI_V;
3970     }
3971     size = booke_page_size_to_tlb(tlb->size);
3972     if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
3973         size = PPC4XX_TLBHI_SIZE_DEFAULT;
3974     }
3975     ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
3976     env->spr[SPR_40x_PID] = tlb->PID;
3977     return ret;
3978 }
3979
3980 target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3981 {
3982     ppcemb_tlb_t *tlb;
3983     target_ulong ret;
3984
3985     entry &= PPC4XX_TLB_ENTRY_MASK;
3986     tlb = &env->tlb.tlbe[entry];
3987     ret = tlb->RPN;
3988     if (tlb->prot & PAGE_EXEC) {
3989         ret |= PPC4XX_TLBLO_EX;
3990     }
3991     if (tlb->prot & PAGE_WRITE) {
3992         ret |= PPC4XX_TLBLO_WR;
3993     }
3994     return ret;
3995 }
3996
3997 void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
3998 {
3999     ppcemb_tlb_t *tlb;
4000     target_ulong page, end;
4001
4002     LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
4003               val);
4004     entry &= PPC4XX_TLB_ENTRY_MASK;
4005     tlb = &env->tlb.tlbe[entry];
4006     /* Invalidate previous TLB (if it's valid) */
4007     if (tlb->prot & PAGE_VALID) {
4008         end = tlb->EPN + tlb->size;
4009         LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
4010                   TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4011         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4012             tlb_flush_page(env, page);
4013         }
4014     }
4015     tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4016                                        & PPC4XX_TLBHI_SIZE_MASK);
4017     /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4018      * If this ever occurs, one should use the ppcemb target instead
4019      * of the ppc or ppc64 one
4020      */
4021     if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
4022         cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4023                   "are not supported (%d)\n",
4024                   tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
4025     }
4026     tlb->EPN = val & ~(tlb->size - 1);
4027     if (val & PPC4XX_TLBHI_V) {
4028         tlb->prot |= PAGE_VALID;
4029         if (val & PPC4XX_TLBHI_E) {
4030             /* XXX: TO BE FIXED */
4031             cpu_abort(env,
4032                       "Little-endian TLB entries are not supported by now\n");
4033         }
4034     } else {
4035         tlb->prot &= ~PAGE_VALID;
4036     }
4037     tlb->PID = env->spr[SPR_40x_PID]; /* PID */
4038     LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4039               " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4040               (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4041               tlb->prot & PAGE_READ ? 'r' : '-',
4042               tlb->prot & PAGE_WRITE ? 'w' : '-',
4043               tlb->prot & PAGE_EXEC ? 'x' : '-',
4044               tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4045     /* Invalidate new TLB (if valid) */
4046     if (tlb->prot & PAGE_VALID) {
4047         end = tlb->EPN + tlb->size;
4048         LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4049                   TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4050         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4051             tlb_flush_page(env, page);
4052         }
4053     }
4054 }
4055
4056 void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
4057 {
4058     ppcemb_tlb_t *tlb;
4059
4060     LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4061               val);
4062     entry &= PPC4XX_TLB_ENTRY_MASK;
4063     tlb = &env->tlb.tlbe[entry];
4064     tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4065     tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
4066     tlb->prot = PAGE_READ;
4067     if (val & PPC4XX_TLBLO_EX) {
4068         tlb->prot |= PAGE_EXEC;
4069     }
4070     if (val & PPC4XX_TLBLO_WR) {
4071         tlb->prot |= PAGE_WRITE;
4072     }
4073     LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4074               " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4075               (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4076               tlb->prot & PAGE_READ ? 'r' : '-',
4077               tlb->prot & PAGE_WRITE ? 'w' : '-',
4078               tlb->prot & PAGE_EXEC ? 'x' : '-',
4079               tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4080 }
4081
4082 target_ulong helper_4xx_tlbsx (target_ulong address)
4083 {
4084     return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4085 }
4086
4087 /* PowerPC 440 TLB management */
4088 void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
4089 {
4090     ppcemb_tlb_t *tlb;
4091     target_ulong EPN, RPN, size;
4092     int do_flush_tlbs;
4093
4094     LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4095               __func__, word, (int)entry, value);
4096     do_flush_tlbs = 0;
4097     entry &= 0x3F;
4098     tlb = &env->tlb.tlbe[entry];
4099     switch (word) {
4100     default:
4101         /* Just here to please gcc */
4102     case 0:
4103         EPN = value & 0xFFFFFC00;
4104         if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
4105             do_flush_tlbs = 1;
4106         tlb->EPN = EPN;
4107         size = booke_tlb_to_page_size((value >> 4) & 0xF);
4108         if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4109             do_flush_tlbs = 1;
4110         tlb->size = size;
4111         tlb->attr &= ~0x1;
4112         tlb->attr |= (value >> 8) & 1;
4113         if (value & 0x200) {
4114             tlb->prot |= PAGE_VALID;
4115         } else {
4116             if (tlb->prot & PAGE_VALID) {
4117                 tlb->prot &= ~PAGE_VALID;
4118                 do_flush_tlbs = 1;
4119             }
4120         }
4121         tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4122         if (do_flush_tlbs)
4123             tlb_flush(env, 1);
4124         break;
4125     case 1:
4126         RPN = value & 0xFFFFFC0F;
4127         if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4128             tlb_flush(env, 1);
4129         tlb->RPN = RPN;
4130         break;
4131     case 2:
4132         tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4133         tlb->prot = tlb->prot & PAGE_VALID;
4134         if (value & 0x1)
4135             tlb->prot |= PAGE_READ << 4;
4136         if (value & 0x2)
4137             tlb->prot |= PAGE_WRITE << 4;
4138         if (value & 0x4)
4139             tlb->prot |= PAGE_EXEC << 4;
4140         if (value & 0x8)
4141             tlb->prot |= PAGE_READ;
4142         if (value & 0x10)
4143             tlb->prot |= PAGE_WRITE;
4144         if (value & 0x20)
4145             tlb->prot |= PAGE_EXEC;
4146         break;
4147     }
4148 }
4149
4150 target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
4151 {
4152     ppcemb_tlb_t *tlb;
4153     target_ulong ret;
4154     int size;
4155
4156     entry &= 0x3F;
4157     tlb = &env->tlb.tlbe[entry];
4158     switch (word) {
4159     default:
4160         /* Just here to please gcc */
4161     case 0:
4162         ret = tlb->EPN;
4163         size = booke_page_size_to_tlb(tlb->size);
4164         if (size < 0 || size > 0xF)
4165             size = 1;
4166         ret |= size << 4;
4167         if (tlb->attr & 0x1)
4168             ret |= 0x100;
4169         if (tlb->prot & PAGE_VALID)
4170             ret |= 0x200;
4171         env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4172         env->spr[SPR_440_MMUCR] |= tlb->PID;
4173         break;
4174     case 1:
4175         ret = tlb->RPN;
4176         break;
4177     case 2:
4178         ret = tlb->attr & ~0x1;
4179         if (tlb->prot & (PAGE_READ << 4))
4180             ret |= 0x1;
4181         if (tlb->prot & (PAGE_WRITE << 4))
4182             ret |= 0x2;
4183         if (tlb->prot & (PAGE_EXEC << 4))
4184             ret |= 0x4;
4185         if (tlb->prot & PAGE_READ)
4186             ret |= 0x8;
4187         if (tlb->prot & PAGE_WRITE)
4188             ret |= 0x10;
4189         if (tlb->prot & PAGE_EXEC)
4190             ret |= 0x20;
4191         break;
4192     }
4193     return ret;
4194 }
4195
4196 target_ulong helper_440_tlbsx (target_ulong address)
4197 {
4198     return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4199 }
4200
4201 /* PowerPC BookE 2.06 TLB management */
4202
4203 static ppcmas_tlb_t *booke206_cur_tlb(CPUState *env)
4204 {
4205     uint32_t tlbncfg = 0;
4206     int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
4207     int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
4208     int tlb;
4209
4210     tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4211     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
4212
4213     if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
4214         cpu_abort(env, "we don't support HES yet\n");
4215     }
4216
4217     return booke206_get_tlbm(env, tlb, ea, esel);
4218 }
4219
4220 void helper_booke_setpid(uint32_t pidn, target_ulong pid)
4221 {
4222     env->spr[pidn] = pid;
4223     /* changing PIDs mean we're in a different address space now */
4224     tlb_flush(env, 1);
4225 }
4226
4227 void helper_booke206_tlbwe(void)
4228 {
4229     uint32_t tlbncfg, tlbn;
4230     ppcmas_tlb_t *tlb;
4231     uint32_t size_tlb, size_ps;
4232
4233     switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
4234     case MAS0_WQ_ALWAYS:
4235         /* good to go, write that entry */
4236         break;
4237     case MAS0_WQ_COND:
4238         /* XXX check if reserved */
4239         if (0) {
4240             return;
4241         }
4242         break;
4243     case MAS0_WQ_CLR_RSRV:
4244         /* XXX clear entry */
4245         return;
4246     default:
4247         /* no idea what to do */
4248         return;
4249     }
4250
4251     if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
4252          !msr_gs) {
4253         /* XXX we don't support direct LRAT setting yet */
4254         fprintf(stderr, "cpu: don't support LRAT setting yet\n");
4255         return;
4256     }
4257
4258     tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4259     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
4260
4261     tlb = booke206_cur_tlb(env);
4262
4263     if (!tlb) {
4264         helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
4265                                    POWERPC_EXCP_INVAL |
4266                                    POWERPC_EXCP_INVAL_INVAL);
4267     }
4268
4269     /* check that we support the targeted size */
4270     size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
4271     size_ps = booke206_tlbnps(env, tlbn);
4272     if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
4273         !(size_ps & (1 << size_tlb))) {
4274         helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
4275                                    POWERPC_EXCP_INVAL |
4276                                    POWERPC_EXCP_INVAL_INVAL);
4277     }
4278
4279     if (msr_gs) {
4280         cpu_abort(env, "missing HV implementation\n");
4281     }
4282     tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
4283                   env->spr[SPR_BOOKE_MAS3];
4284     tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
4285
4286     /* MAV 1.0 only */
4287     if (!(tlbncfg & TLBnCFG_AVAIL)) {
4288         /* force !AVAIL TLB entries to correct page size */
4289         tlb->mas1 &= ~MAS1_TSIZE_MASK;
4290         /* XXX can be configured in MMUCSR0 */
4291         tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
4292     }
4293
4294     /* XXX needs to change when supporting 64-bit e500 */
4295     tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
4296
4297     if (!(tlbncfg & TLBnCFG_IPROT)) {
4298         /* no IPROT supported by TLB */
4299         tlb->mas1 &= ~MAS1_IPROT;
4300     }
4301
4302     if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
4303         tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
4304     } else {
4305         tlb_flush(env, 1);
4306     }
4307 }
4308
4309 static inline void booke206_tlb_to_mas(CPUState *env, ppcmas_tlb_t *tlb)
4310 {
4311     int tlbn = booke206_tlbm_to_tlbn(env, tlb);
4312     int way = booke206_tlbm_to_way(env, tlb);
4313
4314     env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
4315     env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
4316     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4317
4318     env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
4319     env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
4320     env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
4321     env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
4322 }
4323
4324 void helper_booke206_tlbre(void)
4325 {
4326     ppcmas_tlb_t *tlb = NULL;
4327
4328     tlb = booke206_cur_tlb(env);
4329     if (!tlb) {
4330         env->spr[SPR_BOOKE_MAS1] = 0;
4331     } else {
4332         booke206_tlb_to_mas(env, tlb);
4333     }
4334 }
4335
4336 void helper_booke206_tlbsx(target_ulong address)
4337 {
4338     ppcmas_tlb_t *tlb = NULL;
4339     int i, j;
4340     target_phys_addr_t raddr;
4341     uint32_t spid, sas;
4342
4343     spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
4344     sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
4345
4346     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4347         int ways = booke206_tlb_ways(env, i);
4348
4349         for (j = 0; j < ways; j++) {
4350             tlb = booke206_get_tlbm(env, i, address, j);
4351
4352             if (!tlb) {
4353                 continue;
4354             }
4355
4356             if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
4357                 continue;
4358             }
4359
4360             if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
4361                 continue;
4362             }
4363
4364             booke206_tlb_to_mas(env, tlb);
4365             return;
4366         }
4367     }
4368
4369     /* no entry found, fill with defaults */
4370     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
4371     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
4372     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
4373     env->spr[SPR_BOOKE_MAS3] = 0;
4374     env->spr[SPR_BOOKE_MAS7] = 0;
4375
4376     if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
4377         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
4378     }
4379
4380     env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
4381                                 << MAS1_TID_SHIFT;
4382
4383     /* next victim logic */
4384     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
4385     env->last_way++;
4386     env->last_way &= booke206_tlb_ways(env, 0) - 1;
4387     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4388 }
4389
4390 static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
4391                                               uint32_t ea)
4392 {
4393     int i;
4394     int ways = booke206_tlb_ways(env, tlbn);
4395     target_ulong mask;
4396
4397     for (i = 0; i < ways; i++) {
4398         ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
4399         if (!tlb) {
4400             continue;
4401         }
4402         mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
4403         if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
4404             !(tlb->mas1 & MAS1_IPROT)) {
4405             tlb->mas1 &= ~MAS1_VALID;
4406         }
4407     }
4408 }
4409
4410 void helper_booke206_tlbivax(target_ulong address)
4411 {
4412     if (address & 0x4) {
4413         /* flush all entries */
4414         if (address & 0x8) {
4415             /* flush all of TLB1 */
4416             booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
4417         } else {
4418             /* flush all of TLB0 */
4419             booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
4420         }
4421         return;
4422     }
4423
4424     if (address & 0x8) {
4425         /* flush TLB1 entries */
4426         booke206_invalidate_ea_tlb(env, 1, address);
4427         tlb_flush(env, 1);
4428     } else {
4429         /* flush TLB0 entries */
4430         booke206_invalidate_ea_tlb(env, 0, address);
4431         tlb_flush_page(env, address & MAS2_EPN_MASK);
4432     }
4433 }
4434
4435 void helper_booke206_tlbilx0(target_ulong address)
4436 {
4437     /* XXX missing LPID handling */
4438     booke206_flush_tlb(env, -1, 1);
4439 }
4440
4441 void helper_booke206_tlbilx1(target_ulong address)
4442 {
4443     int i, j;
4444     int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4445     ppcmas_tlb_t *tlb = env->tlb.tlbm;
4446     int tlb_size;
4447
4448     /* XXX missing LPID handling */
4449     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4450         tlb_size = booke206_tlb_size(env, i);
4451         for (j = 0; j < tlb_size; j++) {
4452             if (!(tlb[j].mas1 & MAS1_IPROT) &&
4453                 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
4454                 tlb[j].mas1 &= ~MAS1_VALID;
4455             }
4456         }
4457         tlb += booke206_tlb_size(env, i);
4458     }
4459     tlb_flush(env, 1);
4460 }
4461
4462 void helper_booke206_tlbilx3(target_ulong address)
4463 {
4464     int i, j;
4465     ppcmas_tlb_t *tlb;
4466     int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4467     int pid = tid >> MAS6_SPID_SHIFT;
4468     int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
4469     int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
4470     /* XXX check for unsupported isize and raise an invalid opcode then */
4471     int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
4472     /* XXX implement MAV2 handling */
4473     bool mav2 = false;
4474
4475     /* XXX missing LPID handling */
4476     /* flush by pid and ea */
4477     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4478         int ways = booke206_tlb_ways(env, i);
4479
4480         for (j = 0; j < ways; j++) {
4481             tlb = booke206_get_tlbm(env, i, address, j);
4482             if (!tlb) {
4483                 continue;
4484             }
4485             if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
4486                 (tlb->mas1 & MAS1_IPROT) ||
4487                 ((tlb->mas1 & MAS1_IND) != ind) ||
4488                 ((tlb->mas8 & MAS8_TGS) != sgs)) {
4489                 continue;
4490             }
4491             if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
4492                 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
4493                 continue;
4494             }
4495             /* XXX e500mc doesn't match SAS, but other cores might */
4496             tlb->mas1 &= ~MAS1_VALID;
4497         }
4498     }
4499     tlb_flush(env, 1);
4500 }
4501
4502 void helper_booke206_tlbflush(uint32_t type)
4503 {
4504     int flags = 0;
4505
4506     if (type & 2) {
4507         flags |= BOOKE206_FLUSH_TLB1;
4508     }
4509
4510     if (type & 4) {
4511         flags |= BOOKE206_FLUSH_TLB0;
4512     }
4513
4514     booke206_flush_tlb(env, flags, 1);
4515 }
4516
4517 /* Embedded.Processor Control */
4518 static int dbell2irq(target_ulong rb)
4519 {
4520     int msg = rb & DBELL_TYPE_MASK;
4521     int irq = -1;
4522
4523     switch (msg) {
4524     case DBELL_TYPE_DBELL:
4525         irq = PPC_INTERRUPT_DOORBELL;
4526         break;
4527     case DBELL_TYPE_DBELL_CRIT:
4528         irq = PPC_INTERRUPT_CDOORBELL;
4529         break;
4530     case DBELL_TYPE_G_DBELL:
4531     case DBELL_TYPE_G_DBELL_CRIT:
4532     case DBELL_TYPE_G_DBELL_MC:
4533         /* XXX implement */
4534     default:
4535         break;
4536     }
4537
4538     return irq;
4539 }
4540
4541 void helper_msgclr(target_ulong rb)
4542 {
4543     int irq = dbell2irq(rb);
4544
4545     if (irq < 0) {
4546         return;
4547     }
4548
4549     env->pending_interrupts &= ~(1 << irq);
4550 }
4551
4552 void helper_msgsnd(target_ulong rb)
4553 {
4554     int irq = dbell2irq(rb);
4555     int pir = rb & DBELL_PIRTAG_MASK;
4556     CPUState *cenv;
4557
4558     if (irq < 0) {
4559         return;
4560     }
4561
4562     for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
4563         if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
4564             cenv->pending_interrupts |= 1 << irq;
4565             cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
4566         }
4567     }
4568 }
4569
4570 #endif /* !CONFIG_USER_ONLY */
This page took 0.27156 seconds and 4 git commands to generate.