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