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