]> Git Repo - qemu.git/blob - target-ppc/op_helper.c
Allow use of SPE extension by all PowerPC targets,
[qemu.git] / target-ppc / op_helper.c
1 /*
2  *  PowerPC emulation helpers for qemu.
3  *
4  *  Copyright (c) 2003-2007 Jocelyn Mayer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include "exec.h"
21 #include "host-utils.h"
22
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 == (int32_t)-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         T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
185     }
186     xer_so |= xer_ov;
187 }
188
189 #if defined(TARGET_PPC64)
190 void do_divdo (void)
191 {
192     if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == (int64_t)-1LL) ||
193                  (int64_t)T1 == 0))) {
194         xer_ov = 0;
195         T0 = (int64_t)T0 / (int64_t)T1;
196     } else {
197         xer_ov = 1;
198         T0 = UINT64_MAX * ((uint64_t)T0 >> 63);
199     }
200     xer_so |= xer_ov;
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     T0 = (int64_t)tl;
251     /* If th != 0 && th != -1, then we had an overflow */
252     if (likely((uint64_t)(th + 1) <= 1)) {
253         xer_ov = 0;
254     } else {
255         xer_ov = 1;
256     }
257     xer_so |= xer_ov;
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 = UINT32_MAX * ((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 = UINT64_MAX * ((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_MAX;
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_MAX;
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 == (int32_t)-1) ||
1559         (int32_t)T1 == 0) {
1560         T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1561         env->spr[SPR_MQ] = 0;
1562     } else {
1563         tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
1564         env->spr[SPR_MQ] = tmp % T1;
1565         T0 = tmp / (int32_t)T1;
1566     }
1567 }
1568
1569 void do_POWER_divo (void)
1570 {
1571     int64_t tmp;
1572
1573     if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1574         (int32_t)T1 == 0) {
1575         T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1576         env->spr[SPR_MQ] = 0;
1577         xer_ov = 1;
1578     } else {
1579         tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
1580         env->spr[SPR_MQ] = tmp % T1;
1581         tmp /= (int32_t)T1;
1582         if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
1583             xer_ov = 1;
1584         } else {
1585             xer_ov = 0;
1586         }
1587         T0 = tmp;
1588     }
1589     xer_so |= xer_ov;
1590 }
1591
1592 void do_POWER_divs (void)
1593 {
1594     if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1595         (int32_t)T1 == 0) {
1596         T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1597         env->spr[SPR_MQ] = 0;
1598     } else {
1599         env->spr[SPR_MQ] = T0 % T1;
1600         T0 = (int32_t)T0 / (int32_t)T1;
1601     }
1602 }
1603
1604 void do_POWER_divso (void)
1605 {
1606     if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1607         (int32_t)T1 == 0) {
1608         T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
1609         env->spr[SPR_MQ] = 0;
1610         xer_ov = 1;
1611     } else {
1612         T0 = (int32_t)T0 / (int32_t)T1;
1613         env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
1614         xer_ov = 0;
1615     }
1616     xer_so |= xer_ov;
1617 }
1618
1619 void do_POWER_dozo (void)
1620 {
1621     if ((int32_t)T1 > (int32_t)T0) {
1622         T2 = T0;
1623         T0 = T1 - T0;
1624         if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
1625             ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
1626             xer_ov = 1;
1627             xer_so = 1;
1628         } else {
1629             xer_ov = 0;
1630         }
1631     } else {
1632         T0 = 0;
1633         xer_ov = 0;
1634     }
1635 }
1636
1637 void do_POWER_maskg (void)
1638 {
1639     uint32_t ret;
1640
1641     if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
1642         ret = UINT32_MAX;
1643     } else {
1644         ret = (UINT32_MAX >> ((uint32_t)T0)) ^
1645             ((UINT32_MAX >> ((uint32_t)T1)) >> 1);
1646         if ((uint32_t)T0 > (uint32_t)T1)
1647             ret = ~ret;
1648     }
1649     T0 = ret;
1650 }
1651
1652 void do_POWER_mulo (void)
1653 {
1654     uint64_t tmp;
1655
1656     tmp = (uint64_t)T0 * (uint64_t)T1;
1657     env->spr[SPR_MQ] = tmp >> 32;
1658     T0 = tmp;
1659     if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
1660         xer_ov = 1;
1661         xer_so = 1;
1662     } else {
1663         xer_ov = 0;
1664     }
1665 }
1666
1667 #if !defined (CONFIG_USER_ONLY)
1668 void do_POWER_rac (void)
1669 {
1670     mmu_ctx_t ctx;
1671     int nb_BATs;
1672
1673     /* We don't have to generate many instances of this instruction,
1674      * as rac is supervisor only.
1675      */
1676     /* XXX: FIX THIS: Pretend we have no BAT */
1677     nb_BATs = env->nb_BATs;
1678     env->nb_BATs = 0;
1679     if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0)
1680         T0 = ctx.raddr;
1681     env->nb_BATs = nb_BATs;
1682 }
1683
1684 void do_POWER_rfsvc (void)
1685 {
1686     __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
1687 }
1688
1689 void do_store_hid0_601 (void)
1690 {
1691     uint32_t hid0;
1692
1693     hid0 = env->spr[SPR_HID0];
1694     if ((T0 ^ hid0) & 0x00000008) {
1695         /* Change current endianness */
1696         env->hflags &= ~(1 << MSR_LE);
1697         env->hflags_nmsr &= ~(1 << MSR_LE);
1698         env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE);
1699         env->hflags |= env->hflags_nmsr;
1700         if (loglevel != 0) {
1701             fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
1702                     __func__, T0 & 0x8 ? 'l' : 'b', env->hflags);
1703         }
1704     }
1705     env->spr[SPR_HID0] = T0;
1706 }
1707 #endif
1708
1709 /*****************************************************************************/
1710 /* 602 specific instructions */
1711 /* mfrom is the most crazy instruction ever seen, imho ! */
1712 /* Real implementation uses a ROM table. Do the same */
1713 #define USE_MFROM_ROM_TABLE
1714 void do_op_602_mfrom (void)
1715 {
1716     if (likely(T0 < 602)) {
1717 #if defined(USE_MFROM_ROM_TABLE)
1718 #include "mfrom_table.c"
1719         T0 = mfrom_ROM_table[T0];
1720 #else
1721         double d;
1722         /* Extremly decomposed:
1723          *                    -T0 / 256
1724          * T0 = 256 * log10(10          + 1.0) + 0.5
1725          */
1726         d = T0;
1727         d = float64_div(d, 256, &env->fp_status);
1728         d = float64_chs(d);
1729         d = exp10(d); // XXX: use float emulation function
1730         d = float64_add(d, 1.0, &env->fp_status);
1731         d = log10(d); // XXX: use float emulation function
1732         d = float64_mul(d, 256, &env->fp_status);
1733         d = float64_add(d, 0.5, &env->fp_status);
1734         T0 = float64_round_to_int(d, &env->fp_status);
1735 #endif
1736     } else {
1737         T0 = 0;
1738     }
1739 }
1740
1741 /*****************************************************************************/
1742 /* Embedded PowerPC specific helpers */
1743 void do_405_check_sat (void)
1744 {
1745     if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
1746                 !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
1747         /* Saturate result */
1748         if (T2 >> 31) {
1749             T0 = INT32_MIN;
1750         } else {
1751             T0 = INT32_MAX;
1752         }
1753     }
1754 }
1755
1756 /* XXX: to be improved to check access rights when in user-mode */
1757 void do_load_dcr (void)
1758 {
1759     target_ulong val;
1760
1761     if (unlikely(env->dcr_env == NULL)) {
1762         if (loglevel != 0) {
1763             fprintf(logfile, "No DCR environment\n");
1764         }
1765         do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1766                                POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1767     } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
1768         if (loglevel != 0) {
1769             fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
1770         }
1771         do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1772                                POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1773     } else {
1774         T0 = val;
1775     }
1776 }
1777
1778 void do_store_dcr (void)
1779 {
1780     if (unlikely(env->dcr_env == NULL)) {
1781         if (loglevel != 0) {
1782             fprintf(logfile, "No DCR environment\n");
1783         }
1784         do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1785                                POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
1786     } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
1787         if (loglevel != 0) {
1788             fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
1789         }
1790         do_raise_exception_err(POWERPC_EXCP_PROGRAM,
1791                                POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1792     }
1793 }
1794
1795 #if !defined(CONFIG_USER_ONLY)
1796 void do_40x_rfci (void)
1797 {
1798     __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1799              ~((target_ulong)0xFFFF0000), 0);
1800 }
1801
1802 void do_rfci (void)
1803 {
1804     __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1805              ~((target_ulong)0x3FFF0000), 0);
1806 }
1807
1808 void do_rfdi (void)
1809 {
1810     __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1811              ~((target_ulong)0x3FFF0000), 0);
1812 }
1813
1814 void do_rfmci (void)
1815 {
1816     __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1817              ~((target_ulong)0x3FFF0000), 0);
1818 }
1819
1820 void do_load_403_pb (int num)
1821 {
1822     T0 = env->pb[num];
1823 }
1824
1825 void do_store_403_pb (int num)
1826 {
1827     if (likely(env->pb[num] != T0)) {
1828         env->pb[num] = T0;
1829         /* Should be optimized */
1830         tlb_flush(env, 1);
1831     }
1832 }
1833 #endif
1834
1835 /* 440 specific */
1836 void do_440_dlmzb (void)
1837 {
1838     target_ulong mask;
1839     int i;
1840
1841     i = 1;
1842     for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1843         if ((T0 & mask) == 0)
1844             goto done;
1845         i++;
1846     }
1847     for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1848         if ((T1 & mask) == 0)
1849             break;
1850         i++;
1851     }
1852  done:
1853     T0 = i;
1854 }
1855
1856 /* SPE extension helpers */
1857 /* Use a table to make this quicker */
1858 static uint8_t hbrev[16] = {
1859     0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1860     0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1861 };
1862
1863 static always_inline uint8_t byte_reverse (uint8_t val)
1864 {
1865     return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1866 }
1867
1868 static always_inline uint32_t word_reverse (uint32_t val)
1869 {
1870     return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1871         (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1872 }
1873
1874 #define MASKBITS 16 // Random value - to be fixed (implementation dependant)
1875 void do_brinc (void)
1876 {
1877     uint32_t a, b, d, mask;
1878
1879     mask = UINT32_MAX >> (32 - MASKBITS);
1880     a = T0 & mask;
1881     b = T1 & mask;
1882     d = word_reverse(1 + word_reverse(a | ~b));
1883     T0 = (T0 & ~mask) | (d & b);
1884 }
1885
1886 #define DO_SPE_OP2(name)                                                      \
1887 void do_ev##name (void)                                                       \
1888 {                                                                             \
1889     T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) |         \
1890         (uint64_t)_do_e##name(T0_64, T1_64);                                  \
1891 }
1892
1893 #define DO_SPE_OP1(name)                                                      \
1894 void do_ev##name (void)                                                       \
1895 {                                                                             \
1896     T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) |                      \
1897         (uint64_t)_do_e##name(T0_64);                                         \
1898 }
1899
1900 /* Fixed-point vector arithmetic */
1901 static always_inline uint32_t _do_eabs (uint32_t val)
1902 {
1903     if ((val & 0x80000000) && val != 0x80000000)
1904         val -= val;
1905
1906     return val;
1907 }
1908
1909 static always_inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2)
1910 {
1911     return op1 + op2;
1912 }
1913
1914 static always_inline int _do_ecntlsw (uint32_t val)
1915 {
1916     if (val & 0x80000000)
1917         return clz32(~val);
1918     else
1919         return clz32(val);
1920 }
1921
1922 static always_inline int _do_ecntlzw (uint32_t val)
1923 {
1924     return clz32(val);
1925 }
1926
1927 static always_inline uint32_t _do_eneg (uint32_t val)
1928 {
1929     if (val != 0x80000000)
1930         val -= val;
1931
1932     return val;
1933 }
1934
1935 static always_inline uint32_t _do_erlw (uint32_t op1, uint32_t op2)
1936 {
1937     return rotl32(op1, op2);
1938 }
1939
1940 static always_inline uint32_t _do_erndw (uint32_t val)
1941 {
1942     return (val + 0x000080000000) & 0xFFFF0000;
1943 }
1944
1945 static always_inline uint32_t _do_eslw (uint32_t op1, uint32_t op2)
1946 {
1947     /* No error here: 6 bits are used */
1948     return op1 << (op2 & 0x3F);
1949 }
1950
1951 static always_inline int32_t _do_esrws (int32_t op1, uint32_t op2)
1952 {
1953     /* No error here: 6 bits are used */
1954     return op1 >> (op2 & 0x3F);
1955 }
1956
1957 static always_inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2)
1958 {
1959     /* No error here: 6 bits are used */
1960     return op1 >> (op2 & 0x3F);
1961 }
1962
1963 static always_inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2)
1964 {
1965     return op2 - op1;
1966 }
1967
1968 /* evabs */
1969 DO_SPE_OP1(abs);
1970 /* evaddw */
1971 DO_SPE_OP2(addw);
1972 /* evcntlsw */
1973 DO_SPE_OP1(cntlsw);
1974 /* evcntlzw */
1975 DO_SPE_OP1(cntlzw);
1976 /* evneg */
1977 DO_SPE_OP1(neg);
1978 /* evrlw */
1979 DO_SPE_OP2(rlw);
1980 /* evrnd */
1981 DO_SPE_OP1(rndw);
1982 /* evslw */
1983 DO_SPE_OP2(slw);
1984 /* evsrws */
1985 DO_SPE_OP2(srws);
1986 /* evsrwu */
1987 DO_SPE_OP2(srwu);
1988 /* evsubfw */
1989 DO_SPE_OP2(subfw);
1990
1991 /* evsel is a little bit more complicated... */
1992 static always_inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n)
1993 {
1994     if (n)
1995         return op1;
1996     else
1997         return op2;
1998 }
1999
2000 void do_evsel (void)
2001 {
2002     T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) |
2003         (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1);
2004 }
2005
2006 /* Fixed-point vector comparisons */
2007 #define DO_SPE_CMP(name)                                                      \
2008 void do_ev##name (void)                                                       \
2009 {                                                                             \
2010     T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32,                   \
2011                                                T1_64 >> 32) << 32,            \
2012                          _do_e##name(T0_64, T1_64));                          \
2013 }
2014
2015 static always_inline uint32_t _do_evcmp_merge (int t0, int t1)
2016 {
2017     return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
2018 }
2019 static always_inline int _do_ecmpeq (uint32_t op1, uint32_t op2)
2020 {
2021     return op1 == op2 ? 1 : 0;
2022 }
2023
2024 static always_inline int _do_ecmpgts (int32_t op1, int32_t op2)
2025 {
2026     return op1 > op2 ? 1 : 0;
2027 }
2028
2029 static always_inline int _do_ecmpgtu (uint32_t op1, uint32_t op2)
2030 {
2031     return op1 > op2 ? 1 : 0;
2032 }
2033
2034 static always_inline int _do_ecmplts (int32_t op1, int32_t op2)
2035 {
2036     return op1 < op2 ? 1 : 0;
2037 }
2038
2039 static always_inline int _do_ecmpltu (uint32_t op1, uint32_t op2)
2040 {
2041     return op1 < op2 ? 1 : 0;
2042 }
2043
2044 /* evcmpeq */
2045 DO_SPE_CMP(cmpeq);
2046 /* evcmpgts */
2047 DO_SPE_CMP(cmpgts);
2048 /* evcmpgtu */
2049 DO_SPE_CMP(cmpgtu);
2050 /* evcmplts */
2051 DO_SPE_CMP(cmplts);
2052 /* evcmpltu */
2053 DO_SPE_CMP(cmpltu);
2054
2055 /* Single precision floating-point conversions from/to integer */
2056 static always_inline uint32_t _do_efscfsi (int32_t val)
2057 {
2058     union {
2059         uint32_t u;
2060         float32 f;
2061     } u;
2062
2063     u.f = int32_to_float32(val, &env->spe_status);
2064
2065     return u.u;
2066 }
2067
2068 static always_inline uint32_t _do_efscfui (uint32_t val)
2069 {
2070     union {
2071         uint32_t u;
2072         float32 f;
2073     } u;
2074
2075     u.f = uint32_to_float32(val, &env->spe_status);
2076
2077     return u.u;
2078 }
2079
2080 static always_inline int32_t _do_efsctsi (uint32_t val)
2081 {
2082     union {
2083         int32_t u;
2084         float32 f;
2085     } u;
2086
2087     u.u = val;
2088     /* NaN are not treated the same way IEEE 754 does */
2089     if (unlikely(isnan(u.f)))
2090         return 0;
2091
2092     return float32_to_int32(u.f, &env->spe_status);
2093 }
2094
2095 static always_inline uint32_t _do_efsctui (uint32_t val)
2096 {
2097     union {
2098         int32_t u;
2099         float32 f;
2100     } u;
2101
2102     u.u = val;
2103     /* NaN are not treated the same way IEEE 754 does */
2104     if (unlikely(isnan(u.f)))
2105         return 0;
2106
2107     return float32_to_uint32(u.f, &env->spe_status);
2108 }
2109
2110 static always_inline int32_t _do_efsctsiz (uint32_t val)
2111 {
2112     union {
2113         int32_t u;
2114         float32 f;
2115     } u;
2116
2117     u.u = val;
2118     /* NaN are not treated the same way IEEE 754 does */
2119     if (unlikely(isnan(u.f)))
2120         return 0;
2121
2122     return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2123 }
2124
2125 static always_inline uint32_t _do_efsctuiz (uint32_t val)
2126 {
2127     union {
2128         int32_t u;
2129         float32 f;
2130     } u;
2131
2132     u.u = val;
2133     /* NaN are not treated the same way IEEE 754 does */
2134     if (unlikely(isnan(u.f)))
2135         return 0;
2136
2137     return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2138 }
2139
2140 void do_efscfsi (void)
2141 {
2142     T0_64 = _do_efscfsi(T0_64);
2143 }
2144
2145 void do_efscfui (void)
2146 {
2147     T0_64 = _do_efscfui(T0_64);
2148 }
2149
2150 void do_efsctsi (void)
2151 {
2152     T0_64 = _do_efsctsi(T0_64);
2153 }
2154
2155 void do_efsctui (void)
2156 {
2157     T0_64 = _do_efsctui(T0_64);
2158 }
2159
2160 void do_efsctsiz (void)
2161 {
2162     T0_64 = _do_efsctsiz(T0_64);
2163 }
2164
2165 void do_efsctuiz (void)
2166 {
2167     T0_64 = _do_efsctuiz(T0_64);
2168 }
2169
2170 /* Single precision floating-point conversion to/from fractional */
2171 static always_inline uint32_t _do_efscfsf (uint32_t val)
2172 {
2173     union {
2174         uint32_t u;
2175         float32 f;
2176     } u;
2177     float32 tmp;
2178
2179     u.f = int32_to_float32(val, &env->spe_status);
2180     tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2181     u.f = float32_div(u.f, tmp, &env->spe_status);
2182
2183     return u.u;
2184 }
2185
2186 static always_inline uint32_t _do_efscfuf (uint32_t val)
2187 {
2188     union {
2189         uint32_t u;
2190         float32 f;
2191     } u;
2192     float32 tmp;
2193
2194     u.f = uint32_to_float32(val, &env->spe_status);
2195     tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2196     u.f = float32_div(u.f, tmp, &env->spe_status);
2197
2198     return u.u;
2199 }
2200
2201 static always_inline int32_t _do_efsctsf (uint32_t val)
2202 {
2203     union {
2204         int32_t u;
2205         float32 f;
2206     } u;
2207     float32 tmp;
2208
2209     u.u = val;
2210     /* NaN are not treated the same way IEEE 754 does */
2211     if (unlikely(isnan(u.f)))
2212         return 0;
2213     tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2214     u.f = float32_mul(u.f, tmp, &env->spe_status);
2215
2216     return float32_to_int32(u.f, &env->spe_status);
2217 }
2218
2219 static always_inline uint32_t _do_efsctuf (uint32_t val)
2220 {
2221     union {
2222         int32_t u;
2223         float32 f;
2224     } u;
2225     float32 tmp;
2226
2227     u.u = val;
2228     /* NaN are not treated the same way IEEE 754 does */
2229     if (unlikely(isnan(u.f)))
2230         return 0;
2231     tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2232     u.f = float32_mul(u.f, tmp, &env->spe_status);
2233
2234     return float32_to_uint32(u.f, &env->spe_status);
2235 }
2236
2237 static always_inline int32_t _do_efsctsfz (uint32_t val)
2238 {
2239     union {
2240         int32_t u;
2241         float32 f;
2242     } u;
2243     float32 tmp;
2244
2245     u.u = val;
2246     /* NaN are not treated the same way IEEE 754 does */
2247     if (unlikely(isnan(u.f)))
2248         return 0;
2249     tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2250     u.f = float32_mul(u.f, tmp, &env->spe_status);
2251
2252     return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2253 }
2254
2255 static always_inline uint32_t _do_efsctufz (uint32_t val)
2256 {
2257     union {
2258         int32_t u;
2259         float32 f;
2260     } u;
2261     float32 tmp;
2262
2263     u.u = val;
2264     /* NaN are not treated the same way IEEE 754 does */
2265     if (unlikely(isnan(u.f)))
2266         return 0;
2267     tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2268     u.f = float32_mul(u.f, tmp, &env->spe_status);
2269
2270     return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2271 }
2272
2273 void do_efscfsf (void)
2274 {
2275     T0_64 = _do_efscfsf(T0_64);
2276 }
2277
2278 void do_efscfuf (void)
2279 {
2280     T0_64 = _do_efscfuf(T0_64);
2281 }
2282
2283 void do_efsctsf (void)
2284 {
2285     T0_64 = _do_efsctsf(T0_64);
2286 }
2287
2288 void do_efsctuf (void)
2289 {
2290     T0_64 = _do_efsctuf(T0_64);
2291 }
2292
2293 void do_efsctsfz (void)
2294 {
2295     T0_64 = _do_efsctsfz(T0_64);
2296 }
2297
2298 void do_efsctufz (void)
2299 {
2300     T0_64 = _do_efsctufz(T0_64);
2301 }
2302
2303 /* Double precision floating point helpers */
2304 static always_inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
2305 {
2306     /* XXX: TODO: test special values (NaN, infinites, ...) */
2307     return _do_efdtstlt(op1, op2);
2308 }
2309
2310 static always_inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
2311 {
2312     /* XXX: TODO: test special values (NaN, infinites, ...) */
2313     return _do_efdtstgt(op1, op2);
2314 }
2315
2316 static always_inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
2317 {
2318     /* XXX: TODO: test special values (NaN, infinites, ...) */
2319     return _do_efdtsteq(op1, op2);
2320 }
2321
2322 void do_efdcmplt (void)
2323 {
2324     T0 = _do_efdcmplt(T0_64, T1_64);
2325 }
2326
2327 void do_efdcmpgt (void)
2328 {
2329     T0 = _do_efdcmpgt(T0_64, T1_64);
2330 }
2331
2332 void do_efdcmpeq (void)
2333 {
2334     T0 = _do_efdcmpeq(T0_64, T1_64);
2335 }
2336
2337 /* Double precision floating-point conversion to/from integer */
2338 static always_inline uint64_t _do_efdcfsi (int64_t val)
2339 {
2340     union {
2341         uint64_t u;
2342         float64 f;
2343     } u;
2344
2345     u.f = int64_to_float64(val, &env->spe_status);
2346
2347     return u.u;
2348 }
2349
2350 static always_inline uint64_t _do_efdcfui (uint64_t val)
2351 {
2352     union {
2353         uint64_t u;
2354         float64 f;
2355     } u;
2356
2357     u.f = uint64_to_float64(val, &env->spe_status);
2358
2359     return u.u;
2360 }
2361
2362 static always_inline int64_t _do_efdctsi (uint64_t val)
2363 {
2364     union {
2365         int64_t u;
2366         float64 f;
2367     } u;
2368
2369     u.u = val;
2370     /* NaN are not treated the same way IEEE 754 does */
2371     if (unlikely(isnan(u.f)))
2372         return 0;
2373
2374     return float64_to_int64(u.f, &env->spe_status);
2375 }
2376
2377 static always_inline uint64_t _do_efdctui (uint64_t val)
2378 {
2379     union {
2380         int64_t u;
2381         float64 f;
2382     } u;
2383
2384     u.u = val;
2385     /* NaN are not treated the same way IEEE 754 does */
2386     if (unlikely(isnan(u.f)))
2387         return 0;
2388
2389     return float64_to_uint64(u.f, &env->spe_status);
2390 }
2391
2392 static always_inline int64_t _do_efdctsiz (uint64_t val)
2393 {
2394     union {
2395         int64_t u;
2396         float64 f;
2397     } u;
2398
2399     u.u = val;
2400     /* NaN are not treated the same way IEEE 754 does */
2401     if (unlikely(isnan(u.f)))
2402         return 0;
2403
2404     return float64_to_int64_round_to_zero(u.f, &env->spe_status);
2405 }
2406
2407 static always_inline uint64_t _do_efdctuiz (uint64_t val)
2408 {
2409     union {
2410         int64_t u;
2411         float64 f;
2412     } u;
2413
2414     u.u = val;
2415     /* NaN are not treated the same way IEEE 754 does */
2416     if (unlikely(isnan(u.f)))
2417         return 0;
2418
2419     return float64_to_uint64_round_to_zero(u.f, &env->spe_status);
2420 }
2421
2422 void do_efdcfsi (void)
2423 {
2424     T0_64 = _do_efdcfsi(T0_64);
2425 }
2426
2427 void do_efdcfui (void)
2428 {
2429     T0_64 = _do_efdcfui(T0_64);
2430 }
2431
2432 void do_efdctsi (void)
2433 {
2434     T0_64 = _do_efdctsi(T0_64);
2435 }
2436
2437 void do_efdctui (void)
2438 {
2439     T0_64 = _do_efdctui(T0_64);
2440 }
2441
2442 void do_efdctsiz (void)
2443 {
2444     T0_64 = _do_efdctsiz(T0_64);
2445 }
2446
2447 void do_efdctuiz (void)
2448 {
2449     T0_64 = _do_efdctuiz(T0_64);
2450 }
2451
2452 /* Double precision floating-point conversion to/from fractional */
2453 static always_inline uint64_t _do_efdcfsf (int64_t val)
2454 {
2455     union {
2456         uint64_t u;
2457         float64 f;
2458     } u;
2459     float64 tmp;
2460
2461     u.f = int32_to_float64(val, &env->spe_status);
2462     tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2463     u.f = float64_div(u.f, tmp, &env->spe_status);
2464
2465     return u.u;
2466 }
2467
2468 static always_inline uint64_t _do_efdcfuf (uint64_t val)
2469 {
2470     union {
2471         uint64_t u;
2472         float64 f;
2473     } u;
2474     float64 tmp;
2475
2476     u.f = uint32_to_float64(val, &env->spe_status);
2477     tmp = int64_to_float64(1ULL << 32, &env->spe_status);
2478     u.f = float64_div(u.f, tmp, &env->spe_status);
2479
2480     return u.u;
2481 }
2482
2483 static always_inline int64_t _do_efdctsf (uint64_t val)
2484 {
2485     union {
2486         int64_t u;
2487         float64 f;
2488     } u;
2489     float64 tmp;
2490
2491     u.u = val;
2492     /* NaN are not treated the same way IEEE 754 does */
2493     if (unlikely(isnan(u.f)))
2494         return 0;
2495     tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2496     u.f = float64_mul(u.f, tmp, &env->spe_status);
2497
2498     return float64_to_int32(u.f, &env->spe_status);
2499 }
2500
2501 static always_inline uint64_t _do_efdctuf (uint64_t val)
2502 {
2503     union {
2504         int64_t u;
2505         float64 f;
2506     } u;
2507     float64 tmp;
2508
2509     u.u = val;
2510     /* NaN are not treated the same way IEEE 754 does */
2511     if (unlikely(isnan(u.f)))
2512         return 0;
2513     tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2514     u.f = float64_mul(u.f, tmp, &env->spe_status);
2515
2516     return float64_to_uint32(u.f, &env->spe_status);
2517 }
2518
2519 static always_inline int64_t _do_efdctsfz (uint64_t val)
2520 {
2521     union {
2522         int64_t u;
2523         float64 f;
2524     } u;
2525     float64 tmp;
2526
2527     u.u = val;
2528     /* NaN are not treated the same way IEEE 754 does */
2529     if (unlikely(isnan(u.f)))
2530         return 0;
2531     tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2532     u.f = float64_mul(u.f, tmp, &env->spe_status);
2533
2534     return float64_to_int32_round_to_zero(u.f, &env->spe_status);
2535 }
2536
2537 static always_inline uint64_t _do_efdctufz (uint64_t val)
2538 {
2539     union {
2540         int64_t u;
2541         float64 f;
2542     } u;
2543     float64 tmp;
2544
2545     u.u = val;
2546     /* NaN are not treated the same way IEEE 754 does */
2547     if (unlikely(isnan(u.f)))
2548         return 0;
2549     tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
2550     u.f = float64_mul(u.f, tmp, &env->spe_status);
2551
2552     return float64_to_uint32_round_to_zero(u.f, &env->spe_status);
2553 }
2554
2555 void do_efdcfsf (void)
2556 {
2557     T0_64 = _do_efdcfsf(T0_64);
2558 }
2559
2560 void do_efdcfuf (void)
2561 {
2562     T0_64 = _do_efdcfuf(T0_64);
2563 }
2564
2565 void do_efdctsf (void)
2566 {
2567     T0_64 = _do_efdctsf(T0_64);
2568 }
2569
2570 void do_efdctuf (void)
2571 {
2572     T0_64 = _do_efdctuf(T0_64);
2573 }
2574
2575 void do_efdctsfz (void)
2576 {
2577     T0_64 = _do_efdctsfz(T0_64);
2578 }
2579
2580 void do_efdctufz (void)
2581 {
2582     T0_64 = _do_efdctufz(T0_64);
2583 }
2584
2585 /* Floating point conversion between single and double precision */
2586 static always_inline uint32_t _do_efscfd (uint64_t val)
2587 {
2588     union {
2589         uint64_t u;
2590         float64 f;
2591     } u1;
2592     union {
2593         uint32_t u;
2594         float32 f;
2595     } u2;
2596
2597     u1.u = val;
2598     u2.f = float64_to_float32(u1.f, &env->spe_status);
2599
2600     return u2.u;
2601 }
2602
2603 static always_inline uint64_t _do_efdcfs (uint32_t val)
2604 {
2605     union {
2606         uint64_t u;
2607         float64 f;
2608     } u2;
2609     union {
2610         uint32_t u;
2611         float32 f;
2612     } u1;
2613
2614     u1.u = val;
2615     u2.f = float32_to_float64(u1.f, &env->spe_status);
2616
2617     return u2.u;
2618 }
2619
2620 void do_efscfd (void)
2621 {
2622     T0_64 = _do_efscfd(T0_64);
2623 }
2624
2625 void do_efdcfs (void)
2626 {
2627     T0_64 = _do_efdcfs(T0_64);
2628 }
2629
2630 /* Single precision fixed-point vector arithmetic */
2631 /* evfsabs */
2632 DO_SPE_OP1(fsabs);
2633 /* evfsnabs */
2634 DO_SPE_OP1(fsnabs);
2635 /* evfsneg */
2636 DO_SPE_OP1(fsneg);
2637 /* evfsadd */
2638 DO_SPE_OP2(fsadd);
2639 /* evfssub */
2640 DO_SPE_OP2(fssub);
2641 /* evfsmul */
2642 DO_SPE_OP2(fsmul);
2643 /* evfsdiv */
2644 DO_SPE_OP2(fsdiv);
2645
2646 /* Single-precision floating-point comparisons */
2647 static always_inline int _do_efscmplt (uint32_t op1, uint32_t op2)
2648 {
2649     /* XXX: TODO: test special values (NaN, infinites, ...) */
2650     return _do_efststlt(op1, op2);
2651 }
2652
2653 static always_inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
2654 {
2655     /* XXX: TODO: test special values (NaN, infinites, ...) */
2656     return _do_efststgt(op1, op2);
2657 }
2658
2659 static always_inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
2660 {
2661     /* XXX: TODO: test special values (NaN, infinites, ...) */
2662     return _do_efststeq(op1, op2);
2663 }
2664
2665 void do_efscmplt (void)
2666 {
2667     T0 = _do_efscmplt(T0_64, T1_64);
2668 }
2669
2670 void do_efscmpgt (void)
2671 {
2672     T0 = _do_efscmpgt(T0_64, T1_64);
2673 }
2674
2675 void do_efscmpeq (void)
2676 {
2677     T0 = _do_efscmpeq(T0_64, T1_64);
2678 }
2679
2680 /* Single-precision floating-point vector comparisons */
2681 /* evfscmplt */
2682 DO_SPE_CMP(fscmplt);
2683 /* evfscmpgt */
2684 DO_SPE_CMP(fscmpgt);
2685 /* evfscmpeq */
2686 DO_SPE_CMP(fscmpeq);
2687 /* evfststlt */
2688 DO_SPE_CMP(fststlt);
2689 /* evfststgt */
2690 DO_SPE_CMP(fststgt);
2691 /* evfststeq */
2692 DO_SPE_CMP(fststeq);
2693
2694 /* Single-precision floating-point vector conversions */
2695 /* evfscfsi */
2696 DO_SPE_OP1(fscfsi);
2697 /* evfscfui */
2698 DO_SPE_OP1(fscfui);
2699 /* evfscfuf */
2700 DO_SPE_OP1(fscfuf);
2701 /* evfscfsf */
2702 DO_SPE_OP1(fscfsf);
2703 /* evfsctsi */
2704 DO_SPE_OP1(fsctsi);
2705 /* evfsctui */
2706 DO_SPE_OP1(fsctui);
2707 /* evfsctsiz */
2708 DO_SPE_OP1(fsctsiz);
2709 /* evfsctuiz */
2710 DO_SPE_OP1(fsctuiz);
2711 /* evfsctsf */
2712 DO_SPE_OP1(fsctsf);
2713 /* evfsctuf */
2714 DO_SPE_OP1(fsctuf);
2715
2716 /*****************************************************************************/
2717 /* Softmmu support */
2718 #if !defined (CONFIG_USER_ONLY)
2719
2720 #define MMUSUFFIX _mmu
2721 #ifdef __s390__
2722 # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
2723 #else
2724 # define GETPC() (__builtin_return_address(0))
2725 #endif
2726
2727 #define SHIFT 0
2728 #include "softmmu_template.h"
2729
2730 #define SHIFT 1
2731 #include "softmmu_template.h"
2732
2733 #define SHIFT 2
2734 #include "softmmu_template.h"
2735
2736 #define SHIFT 3
2737 #include "softmmu_template.h"
2738
2739 /* try to fill the TLB and return an exception if error. If retaddr is
2740    NULL, it means that the function was called in C code (i.e. not
2741    from generated code or from helper.c) */
2742 /* XXX: fix it to restore all registers */
2743 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
2744 {
2745     TranslationBlock *tb;
2746     CPUState *saved_env;
2747     unsigned long pc;
2748     int ret;
2749
2750     /* XXX: hack to restore env in all cases, even if not called from
2751        generated code */
2752     saved_env = env;
2753     env = cpu_single_env;
2754     ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
2755     if (unlikely(ret != 0)) {
2756         if (likely(retaddr)) {
2757             /* now we have a real cpu fault */
2758             pc = (unsigned long)retaddr;
2759             tb = tb_find_pc(pc);
2760             if (likely(tb)) {
2761                 /* the PC is inside the translated code. It means that we have
2762                    a virtual CPU fault */
2763                 cpu_restore_state(tb, env, pc, NULL);
2764             }
2765         }
2766         do_raise_exception_err(env->exception_index, env->error_code);
2767     }
2768     env = saved_env;
2769 }
2770
2771 /* Software driven TLBs management */
2772 /* PowerPC 602/603 software TLB load instructions helpers */
2773 void do_load_6xx_tlb (int is_code)
2774 {
2775     target_ulong RPN, CMP, EPN;
2776     int way;
2777
2778     RPN = env->spr[SPR_RPA];
2779     if (is_code) {
2780         CMP = env->spr[SPR_ICMP];
2781         EPN = env->spr[SPR_IMISS];
2782     } else {
2783         CMP = env->spr[SPR_DCMP];
2784         EPN = env->spr[SPR_DMISS];
2785     }
2786     way = (env->spr[SPR_SRR1] >> 17) & 1;
2787 #if defined (DEBUG_SOFTWARE_TLB)
2788     if (loglevel != 0) {
2789         fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
2790                 __func__, (unsigned long)T0, (unsigned long)EPN,
2791                 (unsigned long)CMP, (unsigned long)RPN, way);
2792     }
2793 #endif
2794     /* Store this TLB */
2795     ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
2796                      way, is_code, CMP, RPN);
2797 }
2798
2799 void do_load_74xx_tlb (int is_code)
2800 {
2801     target_ulong RPN, CMP, EPN;
2802     int way;
2803
2804     RPN = env->spr[SPR_PTELO];
2805     CMP = env->spr[SPR_PTEHI];
2806     EPN = env->spr[SPR_TLBMISS] & ~0x3;
2807     way = env->spr[SPR_TLBMISS] & 0x3;
2808 #if defined (DEBUG_SOFTWARE_TLB)
2809     if (loglevel != 0) {
2810         fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
2811                 __func__, (unsigned long)T0, (unsigned long)EPN,
2812                 (unsigned long)CMP, (unsigned long)RPN, way);
2813     }
2814 #endif
2815     /* Store this TLB */
2816     ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
2817                      way, is_code, CMP, RPN);
2818 }
2819
2820 static always_inline target_ulong booke_tlb_to_page_size (int size)
2821 {
2822     return 1024 << (2 * size);
2823 }
2824
2825 static always_inline int booke_page_size_to_tlb (target_ulong page_size)
2826 {
2827     int size;
2828
2829     switch (page_size) {
2830     case 0x00000400UL:
2831         size = 0x0;
2832         break;
2833     case 0x00001000UL:
2834         size = 0x1;
2835         break;
2836     case 0x00004000UL:
2837         size = 0x2;
2838         break;
2839     case 0x00010000UL:
2840         size = 0x3;
2841         break;
2842     case 0x00040000UL:
2843         size = 0x4;
2844         break;
2845     case 0x00100000UL:
2846         size = 0x5;
2847         break;
2848     case 0x00400000UL:
2849         size = 0x6;
2850         break;
2851     case 0x01000000UL:
2852         size = 0x7;
2853         break;
2854     case 0x04000000UL:
2855         size = 0x8;
2856         break;
2857     case 0x10000000UL:
2858         size = 0x9;
2859         break;
2860     case 0x40000000UL:
2861         size = 0xA;
2862         break;
2863 #if defined (TARGET_PPC64)
2864     case 0x000100000000ULL:
2865         size = 0xB;
2866         break;
2867     case 0x000400000000ULL:
2868         size = 0xC;
2869         break;
2870     case 0x001000000000ULL:
2871         size = 0xD;
2872         break;
2873     case 0x004000000000ULL:
2874         size = 0xE;
2875         break;
2876     case 0x010000000000ULL:
2877         size = 0xF;
2878         break;
2879 #endif
2880     default:
2881         size = -1;
2882         break;
2883     }
2884
2885     return size;
2886 }
2887
2888 /* Helpers for 4xx TLB management */
2889 void do_4xx_tlbre_lo (void)
2890 {
2891     ppcemb_tlb_t *tlb;
2892     int size;
2893
2894     T0 &= 0x3F;
2895     tlb = &env->tlb[T0].tlbe;
2896     T0 = tlb->EPN;
2897     if (tlb->prot & PAGE_VALID)
2898         T0 |= 0x400;
2899     size = booke_page_size_to_tlb(tlb->size);
2900     if (size < 0 || size > 0x7)
2901         size = 1;
2902     T0 |= size << 7;
2903     env->spr[SPR_40x_PID] = tlb->PID;
2904 }
2905
2906 void do_4xx_tlbre_hi (void)
2907 {
2908     ppcemb_tlb_t *tlb;
2909
2910     T0 &= 0x3F;
2911     tlb = &env->tlb[T0].tlbe;
2912     T0 = tlb->RPN;
2913     if (tlb->prot & PAGE_EXEC)
2914         T0 |= 0x200;
2915     if (tlb->prot & PAGE_WRITE)
2916         T0 |= 0x100;
2917 }
2918
2919 void do_4xx_tlbwe_hi (void)
2920 {
2921     ppcemb_tlb_t *tlb;
2922     target_ulong page, end;
2923
2924 #if defined (DEBUG_SOFTWARE_TLB)
2925     if (loglevel != 0) {
2926         fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
2927     }
2928 #endif
2929     T0 &= 0x3F;
2930     tlb = &env->tlb[T0].tlbe;
2931     /* Invalidate previous TLB (if it's valid) */
2932     if (tlb->prot & PAGE_VALID) {
2933         end = tlb->EPN + tlb->size;
2934 #if defined (DEBUG_SOFTWARE_TLB)
2935         if (loglevel != 0) {
2936             fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
2937                     " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
2938         }
2939 #endif
2940         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2941             tlb_flush_page(env, page);
2942     }
2943     tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
2944     /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2945      * If this ever occurs, one should use the ppcemb target instead
2946      * of the ppc or ppc64 one
2947      */
2948     if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
2949         cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2950                   "are not supported (%d)\n",
2951                   tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
2952     }
2953     tlb->EPN = T1 & ~(tlb->size - 1);
2954     if (T1 & 0x40)
2955         tlb->prot |= PAGE_VALID;
2956     else
2957         tlb->prot &= ~PAGE_VALID;
2958     if (T1 & 0x20) {
2959         /* XXX: TO BE FIXED */
2960         cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
2961     }
2962     tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2963     tlb->attr = T1 & 0xFF;
2964 #if defined (DEBUG_SOFTWARE_TLB)
2965     if (loglevel != 0) {
2966         fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
2967                 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
2968                 (int)T0, tlb->RPN, tlb->EPN, tlb->size,
2969                 tlb->prot & PAGE_READ ? 'r' : '-',
2970                 tlb->prot & PAGE_WRITE ? 'w' : '-',
2971                 tlb->prot & PAGE_EXEC ? 'x' : '-',
2972                 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2973     }
2974 #endif
2975     /* Invalidate new TLB (if valid) */
2976     if (tlb->prot & PAGE_VALID) {
2977         end = tlb->EPN + tlb->size;
2978 #if defined (DEBUG_SOFTWARE_TLB)
2979         if (loglevel != 0) {
2980             fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
2981                     " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
2982         }
2983 #endif
2984         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2985             tlb_flush_page(env, page);
2986     }
2987 }
2988
2989 void do_4xx_tlbwe_lo (void)
2990 {
2991     ppcemb_tlb_t *tlb;
2992
2993 #if defined (DEBUG_SOFTWARE_TLB)
2994     if (loglevel != 0) {
2995         fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
2996     }
2997 #endif
2998     T0 &= 0x3F;
2999     tlb = &env->tlb[T0].tlbe;
3000     tlb->RPN = T1 & 0xFFFFFC00;
3001     tlb->prot = PAGE_READ;
3002     if (T1 & 0x200)
3003         tlb->prot |= PAGE_EXEC;
3004     if (T1 & 0x100)
3005         tlb->prot |= PAGE_WRITE;
3006 #if defined (DEBUG_SOFTWARE_TLB)
3007     if (loglevel != 0) {
3008         fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
3009                 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
3010                 (int)T0, tlb->RPN, tlb->EPN, tlb->size,
3011                 tlb->prot & PAGE_READ ? 'r' : '-',
3012                 tlb->prot & PAGE_WRITE ? 'w' : '-',
3013                 tlb->prot & PAGE_EXEC ? 'x' : '-',
3014                 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3015     }
3016 #endif
3017 }
3018
3019 /* PowerPC 440 TLB management */
3020 void do_440_tlbwe (int word)
3021 {
3022     ppcemb_tlb_t *tlb;
3023     target_ulong EPN, RPN, size;
3024     int do_flush_tlbs;
3025
3026 #if defined (DEBUG_SOFTWARE_TLB)
3027     if (loglevel != 0) {
3028         fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n",
3029                 __func__, word, T0, T1);
3030     }
3031 #endif
3032     do_flush_tlbs = 0;
3033     T0 &= 0x3F;
3034     tlb = &env->tlb[T0].tlbe;
3035     switch (word) {
3036     default:
3037         /* Just here to please gcc */
3038     case 0:
3039         EPN = T1 & 0xFFFFFC00;
3040         if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
3041             do_flush_tlbs = 1;
3042         tlb->EPN = EPN;
3043         size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
3044         if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3045             do_flush_tlbs = 1;
3046         tlb->size = size;
3047         tlb->attr &= ~0x1;
3048         tlb->attr |= (T1 >> 8) & 1;
3049         if (T1 & 0x200) {
3050             tlb->prot |= PAGE_VALID;
3051         } else {
3052             if (tlb->prot & PAGE_VALID) {
3053                 tlb->prot &= ~PAGE_VALID;
3054                 do_flush_tlbs = 1;
3055             }
3056         }
3057         tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3058         if (do_flush_tlbs)
3059             tlb_flush(env, 1);
3060         break;
3061     case 1:
3062         RPN = T1 & 0xFFFFFC0F;
3063         if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3064             tlb_flush(env, 1);
3065         tlb->RPN = RPN;
3066         break;
3067     case 2:
3068         tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
3069         tlb->prot = tlb->prot & PAGE_VALID;
3070         if (T1 & 0x1)
3071             tlb->prot |= PAGE_READ << 4;
3072         if (T1 & 0x2)
3073             tlb->prot |= PAGE_WRITE << 4;
3074         if (T1 & 0x4)
3075             tlb->prot |= PAGE_EXEC << 4;
3076         if (T1 & 0x8)
3077             tlb->prot |= PAGE_READ;
3078         if (T1 & 0x10)
3079             tlb->prot |= PAGE_WRITE;
3080         if (T1 & 0x20)
3081             tlb->prot |= PAGE_EXEC;
3082         break;
3083     }
3084 }
3085
3086 void do_440_tlbre (int word)
3087 {
3088     ppcemb_tlb_t *tlb;
3089     int size;
3090
3091     T0 &= 0x3F;
3092     tlb = &env->tlb[T0].tlbe;
3093     switch (word) {
3094     default:
3095         /* Just here to please gcc */
3096     case 0:
3097         T0 = tlb->EPN;
3098         size = booke_page_size_to_tlb(tlb->size);
3099         if (size < 0 || size > 0xF)
3100             size = 1;
3101         T0 |= size << 4;
3102         if (tlb->attr & 0x1)
3103             T0 |= 0x100;
3104         if (tlb->prot & PAGE_VALID)
3105             T0 |= 0x200;
3106         env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3107         env->spr[SPR_440_MMUCR] |= tlb->PID;
3108         break;
3109     case 1:
3110         T0 = tlb->RPN;
3111         break;
3112     case 2:
3113         T0 = tlb->attr & ~0x1;
3114         if (tlb->prot & (PAGE_READ << 4))
3115             T0 |= 0x1;
3116         if (tlb->prot & (PAGE_WRITE << 4))
3117             T0 |= 0x2;
3118         if (tlb->prot & (PAGE_EXEC << 4))
3119             T0 |= 0x4;
3120         if (tlb->prot & PAGE_READ)
3121             T0 |= 0x8;
3122         if (tlb->prot & PAGE_WRITE)
3123             T0 |= 0x10;
3124         if (tlb->prot & PAGE_EXEC)
3125             T0 |= 0x20;
3126         break;
3127     }
3128 }
3129 #endif /* !CONFIG_USER_ONLY */
This page took 0.193604 seconds and 4 git commands to generate.