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