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