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