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