]> git.proxmox.com Git - qemu.git/blob - target-ppc/op_helper.c
eedbb42d8c7679e0b6131531ec7f8df07156609d
[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, see <http://www.gnu.org/licenses/>.
18 */
19 #include <string.h>
20 #include "cpu.h"
21 #include "dyngen-exec.h"
22 #include "host-utils.h"
23 #include "helper.h"
24
25 #include "helper_regs.h"
26
27 #if !defined(CONFIG_USER_ONLY)
28 #include "softmmu_exec.h"
29 #endif /* !defined(CONFIG_USER_ONLY) */
30
31 //#define DEBUG_OP
32 //#define DEBUG_SOFTWARE_TLB
33
34 #ifdef DEBUG_SOFTWARE_TLB
35 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
36 #else
37 # define LOG_SWTLB(...) do { } while (0)
38 #endif
39
40 /*****************************************************************************/
41 /* SPR accesses */
42 void helper_load_dump_spr(uint32_t sprn)
43 {
44 qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
45 env->spr[sprn]);
46 }
47
48 void helper_store_dump_spr(uint32_t sprn)
49 {
50 qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
51 env->spr[sprn]);
52 }
53
54 target_ulong helper_load_tbl(void)
55 {
56 return (target_ulong)cpu_ppc_load_tbl(env);
57 }
58
59 target_ulong helper_load_tbu(void)
60 {
61 return cpu_ppc_load_tbu(env);
62 }
63
64 target_ulong helper_load_atbl(void)
65 {
66 return (target_ulong)cpu_ppc_load_atbl(env);
67 }
68
69 target_ulong helper_load_atbu(void)
70 {
71 return cpu_ppc_load_atbu(env);
72 }
73
74 #if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
75 target_ulong helper_load_purr(void)
76 {
77 return (target_ulong)cpu_ppc_load_purr(env);
78 }
79 #endif
80
81 target_ulong helper_load_601_rtcl(void)
82 {
83 return cpu_ppc601_load_rtcl(env);
84 }
85
86 target_ulong helper_load_601_rtcu(void)
87 {
88 return cpu_ppc601_load_rtcu(env);
89 }
90
91 #if !defined(CONFIG_USER_ONLY)
92 #if defined(TARGET_PPC64)
93 void helper_store_asr(target_ulong val)
94 {
95 ppc_store_asr(env, val);
96 }
97 #endif
98
99 void helper_store_sdr1(target_ulong val)
100 {
101 ppc_store_sdr1(env, val);
102 }
103
104 void helper_store_tbl(target_ulong val)
105 {
106 cpu_ppc_store_tbl(env, val);
107 }
108
109 void helper_store_tbu(target_ulong val)
110 {
111 cpu_ppc_store_tbu(env, val);
112 }
113
114 void helper_store_atbl(target_ulong val)
115 {
116 cpu_ppc_store_atbl(env, val);
117 }
118
119 void helper_store_atbu(target_ulong val)
120 {
121 cpu_ppc_store_atbu(env, val);
122 }
123
124 void helper_store_601_rtcl(target_ulong val)
125 {
126 cpu_ppc601_store_rtcl(env, val);
127 }
128
129 void helper_store_601_rtcu(target_ulong val)
130 {
131 cpu_ppc601_store_rtcu(env, val);
132 }
133
134 target_ulong helper_load_decr(void)
135 {
136 return cpu_ppc_load_decr(env);
137 }
138
139 void helper_store_decr(target_ulong val)
140 {
141 cpu_ppc_store_decr(env, val);
142 }
143
144 void helper_store_hid0_601(target_ulong val)
145 {
146 target_ulong hid0;
147
148 hid0 = env->spr[SPR_HID0];
149 if ((val ^ hid0) & 0x00000008) {
150 /* Change current endianness */
151 env->hflags &= ~(1 << MSR_LE);
152 env->hflags_nmsr &= ~(1 << MSR_LE);
153 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
154 env->hflags |= env->hflags_nmsr;
155 qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
156 val & 0x8 ? 'l' : 'b', env->hflags);
157 }
158 env->spr[SPR_HID0] = (uint32_t)val;
159 }
160
161 void helper_store_403_pbr(uint32_t num, target_ulong value)
162 {
163 if (likely(env->pb[num] != value)) {
164 env->pb[num] = value;
165 /* Should be optimized */
166 tlb_flush(env, 1);
167 }
168 }
169
170 target_ulong helper_load_40x_pit(void)
171 {
172 return load_40x_pit(env);
173 }
174
175 void helper_store_40x_pit(target_ulong val)
176 {
177 store_40x_pit(env, val);
178 }
179
180 void helper_store_40x_dbcr0(target_ulong val)
181 {
182 store_40x_dbcr0(env, val);
183 }
184
185 void helper_store_40x_sler(target_ulong val)
186 {
187 store_40x_sler(env, val);
188 }
189
190 void helper_store_booke_tcr(target_ulong val)
191 {
192 store_booke_tcr(env, val);
193 }
194
195 void helper_store_booke_tsr(target_ulong val)
196 {
197 store_booke_tsr(env, val);
198 }
199
200 void helper_store_ibatu(uint32_t nr, target_ulong val)
201 {
202 ppc_store_ibatu(env, nr, val);
203 }
204
205 void helper_store_ibatl(uint32_t nr, target_ulong val)
206 {
207 ppc_store_ibatl(env, nr, val);
208 }
209
210 void helper_store_dbatu(uint32_t nr, target_ulong val)
211 {
212 ppc_store_dbatu(env, nr, val);
213 }
214
215 void helper_store_dbatl(uint32_t nr, target_ulong val)
216 {
217 ppc_store_dbatl(env, nr, val);
218 }
219
220 void helper_store_601_batl(uint32_t nr, target_ulong val)
221 {
222 ppc_store_ibatl_601(env, nr, val);
223 }
224
225 void helper_store_601_batu(uint32_t nr, target_ulong val)
226 {
227 ppc_store_ibatu_601(env, nr, val);
228 }
229 #endif
230
231 /*****************************************************************************/
232 /* Memory load and stores */
233
234 static inline target_ulong addr_add(target_ulong addr, target_long arg)
235 {
236 #if defined(TARGET_PPC64)
237 if (!msr_sf) {
238 return (uint32_t)(addr + arg);
239 } else
240 #endif
241 {
242 return addr + arg;
243 }
244 }
245
246 void helper_lmw(target_ulong addr, uint32_t reg)
247 {
248 for (; reg < 32; reg++) {
249 if (msr_le) {
250 env->gpr[reg] = bswap32(ldl(addr));
251 } else {
252 env->gpr[reg] = ldl(addr);
253 }
254 addr = addr_add(addr, 4);
255 }
256 }
257
258 void helper_stmw(target_ulong addr, uint32_t reg)
259 {
260 for (; reg < 32; reg++) {
261 if (msr_le) {
262 stl(addr, bswap32((uint32_t)env->gpr[reg]));
263 } else {
264 stl(addr, (uint32_t)env->gpr[reg]);
265 }
266 addr = addr_add(addr, 4);
267 }
268 }
269
270 void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
271 {
272 int sh;
273
274 for (; nb > 3; nb -= 4) {
275 env->gpr[reg] = ldl(addr);
276 reg = (reg + 1) % 32;
277 addr = addr_add(addr, 4);
278 }
279 if (unlikely(nb > 0)) {
280 env->gpr[reg] = 0;
281 for (sh = 24; nb > 0; nb--, sh -= 8) {
282 env->gpr[reg] |= ldub(addr) << sh;
283 addr = addr_add(addr, 1);
284 }
285 }
286 }
287 /* PPC32 specification says we must generate an exception if
288 * rA is in the range of registers to be loaded.
289 * In an other hand, IBM says this is valid, but rA won't be loaded.
290 * For now, I'll follow the spec...
291 */
292 void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
293 {
294 if (likely(xer_bc != 0)) {
295 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
296 (reg < rb && (reg + xer_bc) > rb))) {
297 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
298 POWERPC_EXCP_INVAL |
299 POWERPC_EXCP_INVAL_LSWX);
300 } else {
301 helper_lsw(addr, xer_bc, reg);
302 }
303 }
304 }
305
306 void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
307 {
308 int sh;
309
310 for (; nb > 3; nb -= 4) {
311 stl(addr, env->gpr[reg]);
312 reg = (reg + 1) % 32;
313 addr = addr_add(addr, 4);
314 }
315 if (unlikely(nb > 0)) {
316 for (sh = 24; nb > 0; nb--, sh -= 8) {
317 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
318 addr = addr_add(addr, 1);
319 }
320 }
321 }
322
323 static void do_dcbz(target_ulong addr, int dcache_line_size)
324 {
325 int i;
326
327 addr &= ~(dcache_line_size - 1);
328 for (i = 0; i < dcache_line_size; i += 4) {
329 stl(addr + i, 0);
330 }
331 if (env->reserve_addr == addr) {
332 env->reserve_addr = (target_ulong)-1ULL;
333 }
334 }
335
336 void helper_dcbz(target_ulong addr)
337 {
338 do_dcbz(addr, env->dcache_line_size);
339 }
340
341 void helper_dcbz_970(target_ulong addr)
342 {
343 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
344 do_dcbz(addr, 32);
345 } else {
346 do_dcbz(addr, env->dcache_line_size);
347 }
348 }
349
350 void helper_icbi(target_ulong addr)
351 {
352 addr &= ~(env->dcache_line_size - 1);
353 /* Invalidate one cache line :
354 * PowerPC specification says this is to be treated like a load
355 * (not a fetch) by the MMU. To be sure it will be so,
356 * do the load "by hand".
357 */
358 ldl(addr);
359 }
360
361 /* XXX: to be tested */
362 target_ulong helper_lscbx(target_ulong addr, uint32_t reg, uint32_t ra,
363 uint32_t rb)
364 {
365 int i, c, d;
366
367 d = 24;
368 for (i = 0; i < xer_bc; i++) {
369 c = ldub(addr);
370 addr = addr_add(addr, 1);
371 /* ra (if not 0) and rb are never modified */
372 if (likely(reg != rb && (ra == 0 || reg != ra))) {
373 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
374 }
375 if (unlikely(c == xer_cmp)) {
376 break;
377 }
378 if (likely(d != 0)) {
379 d -= 8;
380 } else {
381 d = 24;
382 reg++;
383 reg = reg & 0x1F;
384 }
385 }
386 return i;
387 }
388
389 /*****************************************************************************/
390 /* Fixed point operations helpers */
391 #if defined(TARGET_PPC64)
392
393 /* multiply high word */
394 uint64_t helper_mulhd(uint64_t arg1, uint64_t arg2)
395 {
396 uint64_t tl, th;
397
398 muls64(&tl, &th, arg1, arg2);
399 return th;
400 }
401
402 /* multiply high word unsigned */
403 uint64_t helper_mulhdu(uint64_t arg1, uint64_t arg2)
404 {
405 uint64_t tl, th;
406
407 mulu64(&tl, &th, arg1, arg2);
408 return th;
409 }
410
411 uint64_t helper_mulldo(uint64_t arg1, uint64_t arg2)
412 {
413 int64_t th;
414 uint64_t tl;
415
416 muls64(&tl, (uint64_t *)&th, arg1, arg2);
417 /* If th != 0 && th != -1, then we had an overflow */
418 if (likely((uint64_t)(th + 1) <= 1)) {
419 env->xer &= ~(1 << XER_OV);
420 } else {
421 env->xer |= (1 << XER_OV) | (1 << XER_SO);
422 }
423 return (int64_t)tl;
424 }
425 #endif
426
427 target_ulong helper_cntlzw(target_ulong t)
428 {
429 return clz32(t);
430 }
431
432 #if defined(TARGET_PPC64)
433 target_ulong helper_cntlzd(target_ulong t)
434 {
435 return clz64(t);
436 }
437 #endif
438
439 /* shift right arithmetic helper */
440 target_ulong helper_sraw(target_ulong value, target_ulong shift)
441 {
442 int32_t ret;
443
444 if (likely(!(shift & 0x20))) {
445 if (likely((uint32_t)shift != 0)) {
446 shift &= 0x1f;
447 ret = (int32_t)value >> shift;
448 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
449 env->xer &= ~(1 << XER_CA);
450 } else {
451 env->xer |= (1 << XER_CA);
452 }
453 } else {
454 ret = (int32_t)value;
455 env->xer &= ~(1 << XER_CA);
456 }
457 } else {
458 ret = (int32_t)value >> 31;
459 if (ret) {
460 env->xer |= (1 << XER_CA);
461 } else {
462 env->xer &= ~(1 << XER_CA);
463 }
464 }
465 return (target_long)ret;
466 }
467
468 #if defined(TARGET_PPC64)
469 target_ulong helper_srad(target_ulong value, target_ulong shift)
470 {
471 int64_t ret;
472
473 if (likely(!(shift & 0x40))) {
474 if (likely((uint64_t)shift != 0)) {
475 shift &= 0x3f;
476 ret = (int64_t)value >> shift;
477 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
478 env->xer &= ~(1 << XER_CA);
479 } else {
480 env->xer |= (1 << XER_CA);
481 }
482 } else {
483 ret = (int64_t)value;
484 env->xer &= ~(1 << XER_CA);
485 }
486 } else {
487 ret = (int64_t)value >> 63;
488 if (ret) {
489 env->xer |= (1 << XER_CA);
490 } else {
491 env->xer &= ~(1 << XER_CA);
492 }
493 }
494 return ret;
495 }
496 #endif
497
498 #if defined(TARGET_PPC64)
499 target_ulong helper_popcntb(target_ulong val)
500 {
501 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
502 0x5555555555555555ULL);
503 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
504 0x3333333333333333ULL);
505 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
506 0x0f0f0f0f0f0f0f0fULL);
507 return val;
508 }
509
510 target_ulong helper_popcntw(target_ulong val)
511 {
512 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
513 0x5555555555555555ULL);
514 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
515 0x3333333333333333ULL);
516 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
517 0x0f0f0f0f0f0f0f0fULL);
518 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
519 0x00ff00ff00ff00ffULL);
520 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
521 0x0000ffff0000ffffULL);
522 return val;
523 }
524
525 target_ulong helper_popcntd(target_ulong val)
526 {
527 return ctpop64(val);
528 }
529 #else
530 target_ulong helper_popcntb(target_ulong val)
531 {
532 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
533 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
534 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
535 return val;
536 }
537
538 target_ulong helper_popcntw(target_ulong val)
539 {
540 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
541 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
542 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
543 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
544 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
545 return val;
546 }
547 #endif
548
549 /*****************************************************************************/
550 /* Floating point operations helpers */
551 uint64_t helper_float32_to_float64(uint32_t arg)
552 {
553 CPU_FloatU f;
554 CPU_DoubleU d;
555
556 f.l = arg;
557 d.d = float32_to_float64(f.f, &env->fp_status);
558 return d.ll;
559 }
560
561 uint32_t helper_float64_to_float32(uint64_t arg)
562 {
563 CPU_FloatU f;
564 CPU_DoubleU d;
565
566 d.ll = arg;
567 f.f = float64_to_float32(d.d, &env->fp_status);
568 return f.l;
569 }
570
571 static inline int isden(float64 d)
572 {
573 CPU_DoubleU u;
574
575 u.d = d;
576
577 return ((u.ll >> 52) & 0x7FF) == 0;
578 }
579
580 uint32_t helper_compute_fprf(uint64_t arg, uint32_t set_fprf)
581 {
582 CPU_DoubleU farg;
583 int isneg;
584 int ret;
585
586 farg.ll = arg;
587 isneg = float64_is_neg(farg.d);
588 if (unlikely(float64_is_any_nan(farg.d))) {
589 if (float64_is_signaling_nan(farg.d)) {
590 /* Signaling NaN: flags are undefined */
591 ret = 0x00;
592 } else {
593 /* Quiet NaN */
594 ret = 0x11;
595 }
596 } else if (unlikely(float64_is_infinity(farg.d))) {
597 /* +/- infinity */
598 if (isneg) {
599 ret = 0x09;
600 } else {
601 ret = 0x05;
602 }
603 } else {
604 if (float64_is_zero(farg.d)) {
605 /* +/- zero */
606 if (isneg) {
607 ret = 0x12;
608 } else {
609 ret = 0x02;
610 }
611 } else {
612 if (isden(farg.d)) {
613 /* Denormalized numbers */
614 ret = 0x10;
615 } else {
616 /* Normalized numbers */
617 ret = 0x00;
618 }
619 if (isneg) {
620 ret |= 0x08;
621 } else {
622 ret |= 0x04;
623 }
624 }
625 }
626 if (set_fprf) {
627 /* We update FPSCR_FPRF */
628 env->fpscr &= ~(0x1F << FPSCR_FPRF);
629 env->fpscr |= ret << FPSCR_FPRF;
630 }
631 /* We just need fpcc to update Rc1 */
632 return ret & 0xF;
633 }
634
635 /* Floating-point invalid operations exception */
636 static inline uint64_t fload_invalid_op_excp(int op)
637 {
638 uint64_t ret = 0;
639 int ve;
640
641 ve = fpscr_ve;
642 switch (op) {
643 case POWERPC_EXCP_FP_VXSNAN:
644 env->fpscr |= 1 << FPSCR_VXSNAN;
645 break;
646 case POWERPC_EXCP_FP_VXSOFT:
647 env->fpscr |= 1 << FPSCR_VXSOFT;
648 break;
649 case POWERPC_EXCP_FP_VXISI:
650 /* Magnitude subtraction of infinities */
651 env->fpscr |= 1 << FPSCR_VXISI;
652 goto update_arith;
653 case POWERPC_EXCP_FP_VXIDI:
654 /* Division of infinity by infinity */
655 env->fpscr |= 1 << FPSCR_VXIDI;
656 goto update_arith;
657 case POWERPC_EXCP_FP_VXZDZ:
658 /* Division of zero by zero */
659 env->fpscr |= 1 << FPSCR_VXZDZ;
660 goto update_arith;
661 case POWERPC_EXCP_FP_VXIMZ:
662 /* Multiplication of zero by infinity */
663 env->fpscr |= 1 << FPSCR_VXIMZ;
664 goto update_arith;
665 case POWERPC_EXCP_FP_VXVC:
666 /* Ordered comparison of NaN */
667 env->fpscr |= 1 << FPSCR_VXVC;
668 env->fpscr &= ~(0xF << FPSCR_FPCC);
669 env->fpscr |= 0x11 << FPSCR_FPCC;
670 /* We must update the target FPR before raising the exception */
671 if (ve != 0) {
672 env->exception_index = POWERPC_EXCP_PROGRAM;
673 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
674 /* Update the floating-point enabled exception summary */
675 env->fpscr |= 1 << FPSCR_FEX;
676 /* Exception is differed */
677 ve = 0;
678 }
679 break;
680 case POWERPC_EXCP_FP_VXSQRT:
681 /* Square root of a negative number */
682 env->fpscr |= 1 << FPSCR_VXSQRT;
683 update_arith:
684 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
685 if (ve == 0) {
686 /* Set the result to quiet NaN */
687 ret = 0x7FF8000000000000ULL;
688 env->fpscr &= ~(0xF << FPSCR_FPCC);
689 env->fpscr |= 0x11 << FPSCR_FPCC;
690 }
691 break;
692 case POWERPC_EXCP_FP_VXCVI:
693 /* Invalid conversion */
694 env->fpscr |= 1 << FPSCR_VXCVI;
695 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
696 if (ve == 0) {
697 /* Set the result to quiet NaN */
698 ret = 0x7FF8000000000000ULL;
699 env->fpscr &= ~(0xF << FPSCR_FPCC);
700 env->fpscr |= 0x11 << FPSCR_FPCC;
701 }
702 break;
703 }
704 /* Update the floating-point invalid operation summary */
705 env->fpscr |= 1 << FPSCR_VX;
706 /* Update the floating-point exception summary */
707 env->fpscr |= 1 << FPSCR_FX;
708 if (ve != 0) {
709 /* Update the floating-point enabled exception summary */
710 env->fpscr |= 1 << FPSCR_FEX;
711 if (msr_fe0 != 0 || msr_fe1 != 0) {
712 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
713 POWERPC_EXCP_FP | op);
714 }
715 }
716 return ret;
717 }
718
719 static inline void float_zero_divide_excp(void)
720 {
721 env->fpscr |= 1 << FPSCR_ZX;
722 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
723 /* Update the floating-point exception summary */
724 env->fpscr |= 1 << FPSCR_FX;
725 if (fpscr_ze != 0) {
726 /* Update the floating-point enabled exception summary */
727 env->fpscr |= 1 << FPSCR_FEX;
728 if (msr_fe0 != 0 || msr_fe1 != 0) {
729 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
730 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
731 }
732 }
733 }
734
735 static inline void float_overflow_excp(void)
736 {
737 env->fpscr |= 1 << FPSCR_OX;
738 /* Update the floating-point exception summary */
739 env->fpscr |= 1 << FPSCR_FX;
740 if (fpscr_oe != 0) {
741 /* XXX: should adjust the result */
742 /* Update the floating-point enabled exception summary */
743 env->fpscr |= 1 << FPSCR_FEX;
744 /* We must update the target FPR before raising the exception */
745 env->exception_index = POWERPC_EXCP_PROGRAM;
746 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
747 } else {
748 env->fpscr |= 1 << FPSCR_XX;
749 env->fpscr |= 1 << FPSCR_FI;
750 }
751 }
752
753 static inline void float_underflow_excp(void)
754 {
755 env->fpscr |= 1 << FPSCR_UX;
756 /* Update the floating-point exception summary */
757 env->fpscr |= 1 << FPSCR_FX;
758 if (fpscr_ue != 0) {
759 /* XXX: should adjust the result */
760 /* Update the floating-point enabled exception summary */
761 env->fpscr |= 1 << FPSCR_FEX;
762 /* We must update the target FPR before raising the exception */
763 env->exception_index = POWERPC_EXCP_PROGRAM;
764 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
765 }
766 }
767
768 static inline void float_inexact_excp(void)
769 {
770 env->fpscr |= 1 << FPSCR_XX;
771 /* Update the floating-point exception summary */
772 env->fpscr |= 1 << FPSCR_FX;
773 if (fpscr_xe != 0) {
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_XX;
779 }
780 }
781
782 static inline void fpscr_set_rounding_mode(void)
783 {
784 int rnd_type;
785
786 /* Set rounding mode */
787 switch (fpscr_rn) {
788 case 0:
789 /* Best approximation (round to nearest) */
790 rnd_type = float_round_nearest_even;
791 break;
792 case 1:
793 /* Smaller magnitude (round toward zero) */
794 rnd_type = float_round_to_zero;
795 break;
796 case 2:
797 /* Round toward +infinite */
798 rnd_type = float_round_up;
799 break;
800 default:
801 case 3:
802 /* Round toward -infinite */
803 rnd_type = float_round_down;
804 break;
805 }
806 set_float_rounding_mode(rnd_type, &env->fp_status);
807 }
808
809 void helper_fpscr_clrbit(uint32_t bit)
810 {
811 int prev;
812
813 prev = (env->fpscr >> bit) & 1;
814 env->fpscr &= ~(1 << bit);
815 if (prev == 1) {
816 switch (bit) {
817 case FPSCR_RN1:
818 case FPSCR_RN:
819 fpscr_set_rounding_mode();
820 break;
821 default:
822 break;
823 }
824 }
825 }
826
827 void helper_fpscr_setbit(uint32_t bit)
828 {
829 int prev;
830
831 prev = (env->fpscr >> bit) & 1;
832 env->fpscr |= 1 << bit;
833 if (prev == 0) {
834 switch (bit) {
835 case FPSCR_VX:
836 env->fpscr |= 1 << FPSCR_FX;
837 if (fpscr_ve) {
838 goto raise_ve;
839 }
840 case FPSCR_OX:
841 env->fpscr |= 1 << FPSCR_FX;
842 if (fpscr_oe) {
843 goto raise_oe;
844 }
845 break;
846 case FPSCR_UX:
847 env->fpscr |= 1 << FPSCR_FX;
848 if (fpscr_ue) {
849 goto raise_ue;
850 }
851 break;
852 case FPSCR_ZX:
853 env->fpscr |= 1 << FPSCR_FX;
854 if (fpscr_ze) {
855 goto raise_ze;
856 }
857 break;
858 case FPSCR_XX:
859 env->fpscr |= 1 << FPSCR_FX;
860 if (fpscr_xe) {
861 goto raise_xe;
862 }
863 break;
864 case FPSCR_VXSNAN:
865 case FPSCR_VXISI:
866 case FPSCR_VXIDI:
867 case FPSCR_VXZDZ:
868 case FPSCR_VXIMZ:
869 case FPSCR_VXVC:
870 case FPSCR_VXSOFT:
871 case FPSCR_VXSQRT:
872 case FPSCR_VXCVI:
873 env->fpscr |= 1 << FPSCR_VX;
874 env->fpscr |= 1 << FPSCR_FX;
875 if (fpscr_ve != 0) {
876 goto raise_ve;
877 }
878 break;
879 case FPSCR_VE:
880 if (fpscr_vx != 0) {
881 raise_ve:
882 env->error_code = POWERPC_EXCP_FP;
883 if (fpscr_vxsnan) {
884 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
885 }
886 if (fpscr_vxisi) {
887 env->error_code |= POWERPC_EXCP_FP_VXISI;
888 }
889 if (fpscr_vxidi) {
890 env->error_code |= POWERPC_EXCP_FP_VXIDI;
891 }
892 if (fpscr_vxzdz) {
893 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
894 }
895 if (fpscr_vximz) {
896 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
897 }
898 if (fpscr_vxvc) {
899 env->error_code |= POWERPC_EXCP_FP_VXVC;
900 }
901 if (fpscr_vxsoft) {
902 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
903 }
904 if (fpscr_vxsqrt) {
905 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
906 }
907 if (fpscr_vxcvi) {
908 env->error_code |= POWERPC_EXCP_FP_VXCVI;
909 }
910 goto raise_excp;
911 }
912 break;
913 case FPSCR_OE:
914 if (fpscr_ox != 0) {
915 raise_oe:
916 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
917 goto raise_excp;
918 }
919 break;
920 case FPSCR_UE:
921 if (fpscr_ux != 0) {
922 raise_ue:
923 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
924 goto raise_excp;
925 }
926 break;
927 case FPSCR_ZE:
928 if (fpscr_zx != 0) {
929 raise_ze:
930 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
931 goto raise_excp;
932 }
933 break;
934 case FPSCR_XE:
935 if (fpscr_xx != 0) {
936 raise_xe:
937 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
938 goto raise_excp;
939 }
940 break;
941 case FPSCR_RN1:
942 case FPSCR_RN:
943 fpscr_set_rounding_mode();
944 break;
945 default:
946 break;
947 raise_excp:
948 /* Update the floating-point enabled exception summary */
949 env->fpscr |= 1 << FPSCR_FEX;
950 /* We have to update Rc1 before raising the exception */
951 env->exception_index = POWERPC_EXCP_PROGRAM;
952 break;
953 }
954 }
955 }
956
957 void helper_store_fpscr(uint64_t arg, uint32_t mask)
958 {
959 /*
960 * We use only the 32 LSB of the incoming fpr
961 */
962 uint32_t prev, new;
963 int i;
964
965 prev = env->fpscr;
966 new = (uint32_t)arg;
967 new &= ~0x60000000;
968 new |= prev & 0x60000000;
969 for (i = 0; i < 8; i++) {
970 if (mask & (1 << i)) {
971 env->fpscr &= ~(0xF << (4 * i));
972 env->fpscr |= new & (0xF << (4 * i));
973 }
974 }
975 /* Update VX and FEX */
976 if (fpscr_ix != 0) {
977 env->fpscr |= 1 << FPSCR_VX;
978 } else {
979 env->fpscr &= ~(1 << FPSCR_VX);
980 }
981 if ((fpscr_ex & fpscr_eex) != 0) {
982 env->fpscr |= 1 << FPSCR_FEX;
983 env->exception_index = POWERPC_EXCP_PROGRAM;
984 /* XXX: we should compute it properly */
985 env->error_code = POWERPC_EXCP_FP;
986 } else {
987 env->fpscr &= ~(1 << FPSCR_FEX);
988 }
989 fpscr_set_rounding_mode();
990 }
991
992 void helper_float_check_status(void)
993 {
994 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
995 (env->error_code & POWERPC_EXCP_FP)) {
996 /* Differred floating-point exception after target FPR update */
997 if (msr_fe0 != 0 || msr_fe1 != 0) {
998 helper_raise_exception_err(env, env->exception_index,
999 env->error_code);
1000 }
1001 } else {
1002 int status = get_float_exception_flags(&env->fp_status);
1003 if (status & float_flag_divbyzero) {
1004 float_zero_divide_excp();
1005 } else if (status & float_flag_overflow) {
1006 float_overflow_excp();
1007 } else if (status & float_flag_underflow) {
1008 float_underflow_excp();
1009 } else if (status & float_flag_inexact) {
1010 float_inexact_excp();
1011 }
1012 }
1013 }
1014
1015 void helper_reset_fpstatus(void)
1016 {
1017 set_float_exception_flags(0, &env->fp_status);
1018 }
1019
1020 /* fadd - fadd. */
1021 uint64_t helper_fadd(uint64_t arg1, uint64_t arg2)
1022 {
1023 CPU_DoubleU farg1, farg2;
1024
1025 farg1.ll = arg1;
1026 farg2.ll = arg2;
1027
1028 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1029 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
1030 /* Magnitude subtraction of infinities */
1031 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1032 } else {
1033 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1034 float64_is_signaling_nan(farg2.d))) {
1035 /* sNaN addition */
1036 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1037 }
1038 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1039 }
1040
1041 return farg1.ll;
1042 }
1043
1044 /* fsub - fsub. */
1045 uint64_t helper_fsub(uint64_t arg1, uint64_t arg2)
1046 {
1047 CPU_DoubleU farg1, farg2;
1048
1049 farg1.ll = arg1;
1050 farg2.ll = arg2;
1051
1052 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1053 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
1054 /* Magnitude subtraction of infinities */
1055 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1056 } else {
1057 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1058 float64_is_signaling_nan(farg2.d))) {
1059 /* sNaN subtraction */
1060 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1061 }
1062 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1063 }
1064
1065 return farg1.ll;
1066 }
1067
1068 /* fmul - fmul. */
1069 uint64_t helper_fmul(uint64_t arg1, uint64_t arg2)
1070 {
1071 CPU_DoubleU farg1, farg2;
1072
1073 farg1.ll = arg1;
1074 farg2.ll = arg2;
1075
1076 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1077 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1078 /* Multiplication of zero by infinity */
1079 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1080 } else {
1081 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1082 float64_is_signaling_nan(farg2.d))) {
1083 /* sNaN multiplication */
1084 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1085 }
1086 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1087 }
1088
1089 return farg1.ll;
1090 }
1091
1092 /* fdiv - fdiv. */
1093 uint64_t helper_fdiv(uint64_t arg1, uint64_t arg2)
1094 {
1095 CPU_DoubleU farg1, farg2;
1096
1097 farg1.ll = arg1;
1098 farg2.ll = arg2;
1099
1100 if (unlikely(float64_is_infinity(farg1.d) &&
1101 float64_is_infinity(farg2.d))) {
1102 /* Division of infinity by infinity */
1103 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
1104 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1105 /* Division of zero by zero */
1106 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
1107 } else {
1108 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1109 float64_is_signaling_nan(farg2.d))) {
1110 /* sNaN division */
1111 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1112 }
1113 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1114 }
1115
1116 return farg1.ll;
1117 }
1118
1119 /* fabs */
1120 uint64_t helper_fabs(uint64_t arg)
1121 {
1122 CPU_DoubleU farg;
1123
1124 farg.ll = arg;
1125 farg.d = float64_abs(farg.d);
1126 return farg.ll;
1127 }
1128
1129 /* fnabs */
1130 uint64_t helper_fnabs(uint64_t arg)
1131 {
1132 CPU_DoubleU farg;
1133
1134 farg.ll = arg;
1135 farg.d = float64_abs(farg.d);
1136 farg.d = float64_chs(farg.d);
1137 return farg.ll;
1138 }
1139
1140 /* fneg */
1141 uint64_t helper_fneg(uint64_t arg)
1142 {
1143 CPU_DoubleU farg;
1144
1145 farg.ll = arg;
1146 farg.d = float64_chs(farg.d);
1147 return farg.ll;
1148 }
1149
1150 /* fctiw - fctiw. */
1151 uint64_t helper_fctiw(uint64_t arg)
1152 {
1153 CPU_DoubleU farg;
1154
1155 farg.ll = arg;
1156
1157 if (unlikely(float64_is_signaling_nan(farg.d))) {
1158 /* sNaN conversion */
1159 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1160 POWERPC_EXCP_FP_VXCVI);
1161 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
1162 float64_is_infinity(farg.d))) {
1163 /* qNan / infinity conversion */
1164 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1165 } else {
1166 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1167 /* XXX: higher bits are not supposed to be significant.
1168 * to make tests easier, return the same as a real PowerPC 750
1169 */
1170 farg.ll |= 0xFFF80000ULL << 32;
1171 }
1172 return farg.ll;
1173 }
1174
1175 /* fctiwz - fctiwz. */
1176 uint64_t helper_fctiwz(uint64_t arg)
1177 {
1178 CPU_DoubleU farg;
1179
1180 farg.ll = arg;
1181
1182 if (unlikely(float64_is_signaling_nan(farg.d))) {
1183 /* sNaN conversion */
1184 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1185 POWERPC_EXCP_FP_VXCVI);
1186 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
1187 float64_is_infinity(farg.d))) {
1188 /* qNan / infinity conversion */
1189 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1190 } else {
1191 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1192 /* XXX: higher bits are not supposed to be significant.
1193 * to make tests easier, return the same as a real PowerPC 750
1194 */
1195 farg.ll |= 0xFFF80000ULL << 32;
1196 }
1197 return farg.ll;
1198 }
1199
1200 #if defined(TARGET_PPC64)
1201 /* fcfid - fcfid. */
1202 uint64_t helper_fcfid(uint64_t arg)
1203 {
1204 CPU_DoubleU farg;
1205
1206 farg.d = int64_to_float64(arg, &env->fp_status);
1207 return farg.ll;
1208 }
1209
1210 /* fctid - fctid. */
1211 uint64_t helper_fctid(uint64_t arg)
1212 {
1213 CPU_DoubleU farg;
1214
1215 farg.ll = arg;
1216
1217 if (unlikely(float64_is_signaling_nan(farg.d))) {
1218 /* sNaN conversion */
1219 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1220 POWERPC_EXCP_FP_VXCVI);
1221 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
1222 float64_is_infinity(farg.d))) {
1223 /* qNan / infinity conversion */
1224 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1225 } else {
1226 farg.ll = float64_to_int64(farg.d, &env->fp_status);
1227 }
1228 return farg.ll;
1229 }
1230
1231 /* fctidz - fctidz. */
1232 uint64_t helper_fctidz(uint64_t arg)
1233 {
1234 CPU_DoubleU farg;
1235
1236 farg.ll = arg;
1237
1238 if (unlikely(float64_is_signaling_nan(farg.d))) {
1239 /* sNaN conversion */
1240 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1241 POWERPC_EXCP_FP_VXCVI);
1242 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
1243 float64_is_infinity(farg.d))) {
1244 /* qNan / infinity conversion */
1245 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1246 } else {
1247 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
1248 }
1249 return farg.ll;
1250 }
1251
1252 #endif
1253
1254 static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
1255 {
1256 CPU_DoubleU farg;
1257
1258 farg.ll = arg;
1259
1260 if (unlikely(float64_is_signaling_nan(farg.d))) {
1261 /* sNaN round */
1262 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1263 POWERPC_EXCP_FP_VXCVI);
1264 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
1265 float64_is_infinity(farg.d))) {
1266 /* qNan / infinity round */
1267 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
1268 } else {
1269 set_float_rounding_mode(rounding_mode, &env->fp_status);
1270 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
1271 /* Restore rounding mode from FPSCR */
1272 fpscr_set_rounding_mode();
1273 }
1274 return farg.ll;
1275 }
1276
1277 uint64_t helper_frin(uint64_t arg)
1278 {
1279 return do_fri(arg, float_round_nearest_even);
1280 }
1281
1282 uint64_t helper_friz(uint64_t arg)
1283 {
1284 return do_fri(arg, float_round_to_zero);
1285 }
1286
1287 uint64_t helper_frip(uint64_t arg)
1288 {
1289 return do_fri(arg, float_round_up);
1290 }
1291
1292 uint64_t helper_frim(uint64_t arg)
1293 {
1294 return do_fri(arg, float_round_down);
1295 }
1296
1297 /* fmadd - fmadd. */
1298 uint64_t helper_fmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
1299 {
1300 CPU_DoubleU farg1, farg2, farg3;
1301
1302 farg1.ll = arg1;
1303 farg2.ll = arg2;
1304 farg3.ll = arg3;
1305
1306 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1307 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1308 /* Multiplication of zero by infinity */
1309 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1310 } else {
1311 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1312 float64_is_signaling_nan(farg2.d) ||
1313 float64_is_signaling_nan(farg3.d))) {
1314 /* sNaN operation */
1315 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1316 }
1317 /* This is the way the PowerPC specification defines it */
1318 float128 ft0_128, ft1_128;
1319
1320 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1321 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1322 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1323 if (unlikely(float128_is_infinity(ft0_128) &&
1324 float64_is_infinity(farg3.d) &&
1325 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1326 /* Magnitude subtraction of infinities */
1327 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1328 } else {
1329 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1330 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1331 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1332 }
1333 }
1334
1335 return farg1.ll;
1336 }
1337
1338 /* fmsub - fmsub. */
1339 uint64_t helper_fmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
1340 {
1341 CPU_DoubleU farg1, farg2, farg3;
1342
1343 farg1.ll = arg1;
1344 farg2.ll = arg2;
1345 farg3.ll = arg3;
1346
1347 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1348 (float64_is_zero(farg1.d) &&
1349 float64_is_infinity(farg2.d)))) {
1350 /* Multiplication of zero by infinity */
1351 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1352 } else {
1353 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1354 float64_is_signaling_nan(farg2.d) ||
1355 float64_is_signaling_nan(farg3.d))) {
1356 /* sNaN operation */
1357 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1358 }
1359 /* This is the way the PowerPC specification defines it */
1360 float128 ft0_128, ft1_128;
1361
1362 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1363 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1364 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1365 if (unlikely(float128_is_infinity(ft0_128) &&
1366 float64_is_infinity(farg3.d) &&
1367 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1368 /* Magnitude subtraction of infinities */
1369 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1370 } else {
1371 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1372 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1373 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1374 }
1375 }
1376 return farg1.ll;
1377 }
1378
1379 /* fnmadd - fnmadd. */
1380 uint64_t helper_fnmadd(uint64_t arg1, uint64_t arg2, uint64_t arg3)
1381 {
1382 CPU_DoubleU farg1, farg2, farg3;
1383
1384 farg1.ll = arg1;
1385 farg2.ll = arg2;
1386 farg3.ll = arg3;
1387
1388 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1389 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1390 /* Multiplication of zero by infinity */
1391 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1392 } else {
1393 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1394 float64_is_signaling_nan(farg2.d) ||
1395 float64_is_signaling_nan(farg3.d))) {
1396 /* sNaN operation */
1397 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1398 }
1399 /* This is the way the PowerPC specification defines it */
1400 float128 ft0_128, ft1_128;
1401
1402 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1403 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1404 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1405 if (unlikely(float128_is_infinity(ft0_128) &&
1406 float64_is_infinity(farg3.d) &&
1407 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1408 /* Magnitude subtraction of infinities */
1409 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1410 } else {
1411 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1412 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1413 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1414 }
1415 if (likely(!float64_is_any_nan(farg1.d))) {
1416 farg1.d = float64_chs(farg1.d);
1417 }
1418 }
1419 return farg1.ll;
1420 }
1421
1422 /* fnmsub - fnmsub. */
1423 uint64_t helper_fnmsub(uint64_t arg1, uint64_t arg2, uint64_t arg3)
1424 {
1425 CPU_DoubleU farg1, farg2, farg3;
1426
1427 farg1.ll = arg1;
1428 farg2.ll = arg2;
1429 farg3.ll = arg3;
1430
1431 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1432 (float64_is_zero(farg1.d) &&
1433 float64_is_infinity(farg2.d)))) {
1434 /* Multiplication of zero by infinity */
1435 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
1436 } else {
1437 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1438 float64_is_signaling_nan(farg2.d) ||
1439 float64_is_signaling_nan(farg3.d))) {
1440 /* sNaN operation */
1441 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1442 }
1443 /* This is the way the PowerPC specification defines it */
1444 float128 ft0_128, ft1_128;
1445
1446 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1447 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
1448 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
1449 if (unlikely(float128_is_infinity(ft0_128) &&
1450 float64_is_infinity(farg3.d) &&
1451 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1452 /* Magnitude subtraction of infinities */
1453 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1454 } else {
1455 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1456 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1457 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1458 }
1459 if (likely(!float64_is_any_nan(farg1.d))) {
1460 farg1.d = float64_chs(farg1.d);
1461 }
1462 }
1463 return farg1.ll;
1464 }
1465
1466 /* frsp - frsp. */
1467 uint64_t helper_frsp(uint64_t arg)
1468 {
1469 CPU_DoubleU farg;
1470 float32 f32;
1471
1472 farg.ll = arg;
1473
1474 if (unlikely(float64_is_signaling_nan(farg.d))) {
1475 /* sNaN square root */
1476 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1477 }
1478 f32 = float64_to_float32(farg.d, &env->fp_status);
1479 farg.d = float32_to_float64(f32, &env->fp_status);
1480
1481 return farg.ll;
1482 }
1483
1484 /* fsqrt - fsqrt. */
1485 uint64_t helper_fsqrt(uint64_t arg)
1486 {
1487 CPU_DoubleU farg;
1488
1489 farg.ll = arg;
1490
1491 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1492 /* Square root of a negative nonzero number */
1493 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1494 } else {
1495 if (unlikely(float64_is_signaling_nan(farg.d))) {
1496 /* sNaN square root */
1497 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1498 }
1499 farg.d = float64_sqrt(farg.d, &env->fp_status);
1500 }
1501 return farg.ll;
1502 }
1503
1504 /* fre - fre. */
1505 uint64_t helper_fre(uint64_t arg)
1506 {
1507 CPU_DoubleU farg;
1508
1509 farg.ll = arg;
1510
1511 if (unlikely(float64_is_signaling_nan(farg.d))) {
1512 /* sNaN reciprocal */
1513 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1514 }
1515 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1516 return farg.d;
1517 }
1518
1519 /* fres - fres. */
1520 uint64_t helper_fres(uint64_t arg)
1521 {
1522 CPU_DoubleU farg;
1523 float32 f32;
1524
1525 farg.ll = arg;
1526
1527 if (unlikely(float64_is_signaling_nan(farg.d))) {
1528 /* sNaN reciprocal */
1529 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1530 }
1531 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1532 f32 = float64_to_float32(farg.d, &env->fp_status);
1533 farg.d = float32_to_float64(f32, &env->fp_status);
1534
1535 return farg.ll;
1536 }
1537
1538 /* frsqrte - frsqrte. */
1539 uint64_t helper_frsqrte(uint64_t arg)
1540 {
1541 CPU_DoubleU farg;
1542 float32 f32;
1543
1544 farg.ll = arg;
1545
1546 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1547 /* Reciprocal square root of a negative nonzero number */
1548 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1549 } else {
1550 if (unlikely(float64_is_signaling_nan(farg.d))) {
1551 /* sNaN reciprocal square root */
1552 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1553 }
1554 farg.d = float64_sqrt(farg.d, &env->fp_status);
1555 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1556 f32 = float64_to_float32(farg.d, &env->fp_status);
1557 farg.d = float32_to_float64(f32, &env->fp_status);
1558 }
1559 return farg.ll;
1560 }
1561
1562 /* fsel - fsel. */
1563 uint64_t helper_fsel(uint64_t arg1, uint64_t arg2, uint64_t arg3)
1564 {
1565 CPU_DoubleU farg1;
1566
1567 farg1.ll = arg1;
1568
1569 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
1570 !float64_is_any_nan(farg1.d)) {
1571 return arg2;
1572 } else {
1573 return arg3;
1574 }
1575 }
1576
1577 void helper_fcmpu(uint64_t arg1, uint64_t arg2, uint32_t crfD)
1578 {
1579 CPU_DoubleU farg1, farg2;
1580 uint32_t ret = 0;
1581
1582 farg1.ll = arg1;
1583 farg2.ll = arg2;
1584
1585 if (unlikely(float64_is_any_nan(farg1.d) ||
1586 float64_is_any_nan(farg2.d))) {
1587 ret = 0x01UL;
1588 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1589 ret = 0x08UL;
1590 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1591 ret = 0x04UL;
1592 } else {
1593 ret = 0x02UL;
1594 }
1595
1596 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1597 env->fpscr |= ret << FPSCR_FPRF;
1598 env->crf[crfD] = ret;
1599 if (unlikely(ret == 0x01UL
1600 && (float64_is_signaling_nan(farg1.d) ||
1601 float64_is_signaling_nan(farg2.d)))) {
1602 /* sNaN comparison */
1603 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1604 }
1605 }
1606
1607 void helper_fcmpo(uint64_t arg1, uint64_t arg2, uint32_t crfD)
1608 {
1609 CPU_DoubleU farg1, farg2;
1610 uint32_t ret = 0;
1611
1612 farg1.ll = arg1;
1613 farg2.ll = arg2;
1614
1615 if (unlikely(float64_is_any_nan(farg1.d) ||
1616 float64_is_any_nan(farg2.d))) {
1617 ret = 0x01UL;
1618 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1619 ret = 0x08UL;
1620 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1621 ret = 0x04UL;
1622 } else {
1623 ret = 0x02UL;
1624 }
1625
1626 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1627 env->fpscr |= ret << FPSCR_FPRF;
1628 env->crf[crfD] = ret;
1629 if (unlikely(ret == 0x01UL)) {
1630 if (float64_is_signaling_nan(farg1.d) ||
1631 float64_is_signaling_nan(farg2.d)) {
1632 /* sNaN comparison */
1633 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1634 POWERPC_EXCP_FP_VXVC);
1635 } else {
1636 /* qNaN comparison */
1637 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1638 }
1639 }
1640 }
1641
1642 /*****************************************************************************/
1643 /* PowerPC 601 specific instructions (POWER bridge) */
1644
1645 target_ulong helper_clcs(uint32_t arg)
1646 {
1647 switch (arg) {
1648 case 0x0CUL:
1649 /* Instruction cache line size */
1650 return env->icache_line_size;
1651 break;
1652 case 0x0DUL:
1653 /* Data cache line size */
1654 return env->dcache_line_size;
1655 break;
1656 case 0x0EUL:
1657 /* Minimum cache line size */
1658 return (env->icache_line_size < env->dcache_line_size) ?
1659 env->icache_line_size : env->dcache_line_size;
1660 break;
1661 case 0x0FUL:
1662 /* Maximum cache line size */
1663 return (env->icache_line_size > env->dcache_line_size) ?
1664 env->icache_line_size : env->dcache_line_size;
1665 break;
1666 default:
1667 /* Undefined */
1668 return 0;
1669 break;
1670 }
1671 }
1672
1673 target_ulong helper_div(target_ulong arg1, target_ulong arg2)
1674 {
1675 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1676
1677 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1678 (int32_t)arg2 == 0) {
1679 env->spr[SPR_MQ] = 0;
1680 return INT32_MIN;
1681 } else {
1682 env->spr[SPR_MQ] = tmp % arg2;
1683 return tmp / (int32_t)arg2;
1684 }
1685 }
1686
1687 target_ulong helper_divo(target_ulong arg1, target_ulong arg2)
1688 {
1689 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
1690
1691 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1692 (int32_t)arg2 == 0) {
1693 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1694 env->spr[SPR_MQ] = 0;
1695 return INT32_MIN;
1696 } else {
1697 env->spr[SPR_MQ] = tmp % arg2;
1698 tmp /= (int32_t)arg2;
1699 if ((int32_t)tmp != tmp) {
1700 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1701 } else {
1702 env->xer &= ~(1 << XER_OV);
1703 }
1704 return tmp;
1705 }
1706 }
1707
1708 target_ulong helper_divs(target_ulong arg1, target_ulong arg2)
1709 {
1710 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1711 (int32_t)arg2 == 0) {
1712 env->spr[SPR_MQ] = 0;
1713 return INT32_MIN;
1714 } else {
1715 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1716 return (int32_t)arg1 / (int32_t)arg2;
1717 }
1718 }
1719
1720 target_ulong helper_divso(target_ulong arg1, target_ulong arg2)
1721 {
1722 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1723 (int32_t)arg2 == 0) {
1724 env->xer |= (1 << XER_OV) | (1 << XER_SO);
1725 env->spr[SPR_MQ] = 0;
1726 return INT32_MIN;
1727 } else {
1728 env->xer &= ~(1 << XER_OV);
1729 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1730 return (int32_t)arg1 / (int32_t)arg2;
1731 }
1732 }
1733
1734 #if !defined(CONFIG_USER_ONLY)
1735 target_ulong helper_rac(target_ulong addr)
1736 {
1737 mmu_ctx_t ctx;
1738 int nb_BATs;
1739 target_ulong ret = 0;
1740
1741 /* We don't have to generate many instances of this instruction,
1742 * as rac is supervisor only.
1743 */
1744 /* XXX: FIX THIS: Pretend we have no BAT */
1745 nb_BATs = env->nb_BATs;
1746 env->nb_BATs = 0;
1747 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
1748 ret = ctx.raddr;
1749 }
1750 env->nb_BATs = nb_BATs;
1751 return ret;
1752 }
1753 #endif
1754
1755 /*****************************************************************************/
1756 /* 602 specific instructions */
1757 /* mfrom is the most crazy instruction ever seen, imho ! */
1758 /* Real implementation uses a ROM table. Do the same */
1759 /* Extremely decomposed:
1760 * -arg / 256
1761 * return 256 * log10(10 + 1.0) + 0.5
1762 */
1763 #if !defined(CONFIG_USER_ONLY)
1764 target_ulong helper_602_mfrom(target_ulong arg)
1765 {
1766 if (likely(arg < 602)) {
1767 #include "mfrom_table.c"
1768 return mfrom_ROM_table[arg];
1769 } else {
1770 return 0;
1771 }
1772 }
1773 #endif
1774
1775 /*****************************************************************************/
1776 /* Embedded PowerPC specific helpers */
1777
1778 /* XXX: to be improved to check access rights when in user-mode */
1779 target_ulong helper_load_dcr(target_ulong dcrn)
1780 {
1781 uint32_t val = 0;
1782
1783 if (unlikely(env->dcr_env == NULL)) {
1784 qemu_log("No DCR environment\n");
1785 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1786 POWERPC_EXCP_INVAL |
1787 POWERPC_EXCP_INVAL_INVAL);
1788 } else if (unlikely(ppc_dcr_read(env->dcr_env,
1789 (uint32_t)dcrn, &val) != 0)) {
1790 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1791 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1792 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1793 }
1794 return val;
1795 }
1796
1797 void helper_store_dcr(target_ulong dcrn, target_ulong val)
1798 {
1799 if (unlikely(env->dcr_env == NULL)) {
1800 qemu_log("No DCR environment\n");
1801 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1802 POWERPC_EXCP_INVAL |
1803 POWERPC_EXCP_INVAL_INVAL);
1804 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn,
1805 (uint32_t)val) != 0)) {
1806 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
1807 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1808 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
1809 }
1810 }
1811
1812 /* 440 specific */
1813 target_ulong helper_dlmzb(target_ulong high, target_ulong low,
1814 uint32_t update_Rc)
1815 {
1816 target_ulong mask;
1817 int i;
1818
1819 i = 1;
1820 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1821 if ((high & mask) == 0) {
1822 if (update_Rc) {
1823 env->crf[0] = 0x4;
1824 }
1825 goto done;
1826 }
1827 i++;
1828 }
1829 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1830 if ((low & mask) == 0) {
1831 if (update_Rc) {
1832 env->crf[0] = 0x8;
1833 }
1834 goto done;
1835 }
1836 i++;
1837 }
1838 if (update_Rc) {
1839 env->crf[0] = 0x2;
1840 }
1841 done:
1842 env->xer = (env->xer & ~0x7F) | i;
1843 if (update_Rc) {
1844 env->crf[0] |= xer_so;
1845 }
1846 return i;
1847 }
1848
1849 /*****************************************************************************/
1850 /* Altivec extension helpers */
1851 #if defined(HOST_WORDS_BIGENDIAN)
1852 #define HI_IDX 0
1853 #define LO_IDX 1
1854 #else
1855 #define HI_IDX 1
1856 #define LO_IDX 0
1857 #endif
1858
1859 #if defined(HOST_WORDS_BIGENDIAN)
1860 #define VECTOR_FOR_INORDER_I(index, element) \
1861 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1862 #else
1863 #define VECTOR_FOR_INORDER_I(index, element) \
1864 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1865 #endif
1866
1867 /* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1868 * execute the following block. */
1869 #define DO_HANDLE_NAN(result, x) \
1870 if (float32_is_any_nan(x)) { \
1871 CPU_FloatU __f; \
1872 __f.f = x; \
1873 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1874 result = __f.f; \
1875 } else
1876
1877 #define HANDLE_NAN1(result, x) \
1878 DO_HANDLE_NAN(result, x)
1879 #define HANDLE_NAN2(result, x, y) \
1880 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1881 #define HANDLE_NAN3(result, x, y, z) \
1882 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1883
1884 /* Saturating arithmetic helpers. */
1885 #define SATCVT(from, to, from_type, to_type, min, max) \
1886 static inline to_type cvt##from##to(from_type x, int *sat) \
1887 { \
1888 to_type r; \
1889 \
1890 if (x < (from_type)min) { \
1891 r = min; \
1892 *sat = 1; \
1893 } else if (x > (from_type)max) { \
1894 r = max; \
1895 *sat = 1; \
1896 } else { \
1897 r = x; \
1898 } \
1899 return r; \
1900 }
1901 #define SATCVTU(from, to, from_type, to_type, min, max) \
1902 static inline to_type cvt##from##to(from_type x, int *sat) \
1903 { \
1904 to_type r; \
1905 \
1906 if (x > (from_type)max) { \
1907 r = max; \
1908 *sat = 1; \
1909 } else { \
1910 r = x; \
1911 } \
1912 return r; \
1913 }
1914 SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1915 SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1916 SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1917
1918 SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1919 SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1920 SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1921 SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1922 SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1923 SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
1924 #undef SATCVT
1925 #undef SATCVTU
1926
1927 #define LVE(name, access, swap, element) \
1928 void helper_##name(ppc_avr_t *r, target_ulong addr) \
1929 { \
1930 size_t n_elems = ARRAY_SIZE(r->element); \
1931 int adjust = HI_IDX*(n_elems - 1); \
1932 int sh = sizeof(r->element[0]) >> 1; \
1933 int index = (addr & 0xf) >> sh; \
1934 \
1935 if (msr_le) { \
1936 r->element[LO_IDX ? index : (adjust - index)] = \
1937 swap(access(addr)); \
1938 } else { \
1939 r->element[LO_IDX ? index : (adjust - index)] = \
1940 access(addr); \
1941 } \
1942 }
1943 #define I(x) (x)
1944 LVE(lvebx, ldub, I, u8)
1945 LVE(lvehx, lduw, bswap16, u16)
1946 LVE(lvewx, ldl, bswap32, u32)
1947 #undef I
1948 #undef LVE
1949
1950 void helper_lvsl(ppc_avr_t *r, target_ulong sh)
1951 {
1952 int i, j = (sh & 0xf);
1953
1954 VECTOR_FOR_INORDER_I(i, u8) {
1955 r->u8[i] = j++;
1956 }
1957 }
1958
1959 void helper_lvsr(ppc_avr_t *r, target_ulong sh)
1960 {
1961 int i, j = 0x10 - (sh & 0xf);
1962
1963 VECTOR_FOR_INORDER_I(i, u8) {
1964 r->u8[i] = j++;
1965 }
1966 }
1967
1968 #define STVE(name, access, swap, element) \
1969 void helper_##name(ppc_avr_t *r, target_ulong addr) \
1970 { \
1971 size_t n_elems = ARRAY_SIZE(r->element); \
1972 int adjust = HI_IDX * (n_elems - 1); \
1973 int sh = sizeof(r->element[0]) >> 1; \
1974 int index = (addr & 0xf) >> sh; \
1975 \
1976 if (msr_le) { \
1977 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
1978 } else { \
1979 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
1980 } \
1981 }
1982 #define I(x) (x)
1983 STVE(stvebx, stb, I, u8)
1984 STVE(stvehx, stw, bswap16, u16)
1985 STVE(stvewx, stl, bswap32, u32)
1986 #undef I
1987 #undef LVE
1988
1989 void helper_mtvscr(ppc_avr_t *r)
1990 {
1991 #if defined(HOST_WORDS_BIGENDIAN)
1992 env->vscr = r->u32[3];
1993 #else
1994 env->vscr = r->u32[0];
1995 #endif
1996 set_flush_to_zero(vscr_nj, &env->vec_status);
1997 }
1998
1999 void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2000 {
2001 int i;
2002
2003 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2004 r->u32[i] = ~a->u32[i] < b->u32[i];
2005 }
2006 }
2007
2008 #define VARITH_DO(name, op, element) \
2009 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2010 { \
2011 int i; \
2012 \
2013 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2014 r->element[i] = a->element[i] op b->element[i]; \
2015 } \
2016 }
2017 #define VARITH(suffix, element) \
2018 VARITH_DO(add##suffix, +, element) \
2019 VARITH_DO(sub##suffix, -, element)
2020 VARITH(ubm, u8)
2021 VARITH(uhm, u16)
2022 VARITH(uwm, u32)
2023 #undef VARITH_DO
2024 #undef VARITH
2025
2026 #define VARITHFP(suffix, func) \
2027 void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2028 { \
2029 int i; \
2030 \
2031 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2032 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2033 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2034 } \
2035 } \
2036 }
2037 VARITHFP(addfp, float32_add)
2038 VARITHFP(subfp, float32_sub)
2039 #undef VARITHFP
2040
2041 #define VARITHSAT_CASE(type, op, cvt, element) \
2042 { \
2043 type result = (type)a->element[i] op (type)b->element[i]; \
2044 r->element[i] = cvt(result, &sat); \
2045 }
2046
2047 #define VARITHSAT_DO(name, op, optype, cvt, element) \
2048 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2049 { \
2050 int sat = 0; \
2051 int i; \
2052 \
2053 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2054 switch (sizeof(r->element[0])) { \
2055 case 1: \
2056 VARITHSAT_CASE(optype, op, cvt, element); \
2057 break; \
2058 case 2: \
2059 VARITHSAT_CASE(optype, op, cvt, element); \
2060 break; \
2061 case 4: \
2062 VARITHSAT_CASE(optype, op, cvt, element); \
2063 break; \
2064 } \
2065 } \
2066 if (sat) { \
2067 env->vscr |= (1 << VSCR_SAT); \
2068 } \
2069 }
2070 #define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2071 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2072 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2073 #define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2074 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2075 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2076 VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2077 VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2078 VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2079 VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2080 VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2081 VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2082 #undef VARITHSAT_CASE
2083 #undef VARITHSAT_DO
2084 #undef VARITHSAT_SIGNED
2085 #undef VARITHSAT_UNSIGNED
2086
2087 #define VAVG_DO(name, element, etype) \
2088 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2089 { \
2090 int i; \
2091 \
2092 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2093 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2094 r->element[i] = x >> 1; \
2095 } \
2096 }
2097
2098 #define VAVG(type, signed_element, signed_type, unsigned_element, \
2099 unsigned_type) \
2100 VAVG_DO(avgs##type, signed_element, signed_type) \
2101 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2102 VAVG(b, s8, int16_t, u8, uint16_t)
2103 VAVG(h, s16, int32_t, u16, uint32_t)
2104 VAVG(w, s32, int64_t, u32, uint64_t)
2105 #undef VAVG_DO
2106 #undef VAVG
2107
2108 #define VCF(suffix, cvt, element) \
2109 void helper_vcf##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2110 { \
2111 int i; \
2112 \
2113 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2114 float32 t = cvt(b->element[i], &env->vec_status); \
2115 r->f[i] = float32_scalbn(t, -uim, &env->vec_status); \
2116 } \
2117 }
2118 VCF(ux, uint32_to_float32, u32)
2119 VCF(sx, int32_to_float32, s32)
2120 #undef VCF
2121
2122 #define VCMP_DO(suffix, compare, element, record) \
2123 void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2124 { \
2125 uint32_t ones = (uint32_t)-1; \
2126 uint32_t all = ones; \
2127 uint32_t none = 0; \
2128 int i; \
2129 \
2130 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2131 uint32_t result = (a->element[i] compare b->element[i] ? \
2132 ones : 0x0); \
2133 switch (sizeof(a->element[0])) { \
2134 case 4: \
2135 r->u32[i] = result; \
2136 break; \
2137 case 2: \
2138 r->u16[i] = result; \
2139 break; \
2140 case 1: \
2141 r->u8[i] = result; \
2142 break; \
2143 } \
2144 all &= result; \
2145 none |= result; \
2146 } \
2147 if (record) { \
2148 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2149 } \
2150 }
2151 #define VCMP(suffix, compare, element) \
2152 VCMP_DO(suffix, compare, element, 0) \
2153 VCMP_DO(suffix##_dot, compare, element, 1)
2154 VCMP(equb, ==, u8)
2155 VCMP(equh, ==, u16)
2156 VCMP(equw, ==, u32)
2157 VCMP(gtub, >, u8)
2158 VCMP(gtuh, >, u16)
2159 VCMP(gtuw, >, u32)
2160 VCMP(gtsb, >, s8)
2161 VCMP(gtsh, >, s16)
2162 VCMP(gtsw, >, s32)
2163 #undef VCMP_DO
2164 #undef VCMP
2165
2166 #define VCMPFP_DO(suffix, compare, order, record) \
2167 void helper_vcmp##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2168 { \
2169 uint32_t ones = (uint32_t)-1; \
2170 uint32_t all = ones; \
2171 uint32_t none = 0; \
2172 int i; \
2173 \
2174 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2175 uint32_t result; \
2176 int rel = float32_compare_quiet(a->f[i], b->f[i], \
2177 &env->vec_status); \
2178 if (rel == float_relation_unordered) { \
2179 result = 0; \
2180 } else if (rel compare order) { \
2181 result = ones; \
2182 } else { \
2183 result = 0; \
2184 } \
2185 r->u32[i] = result; \
2186 all &= result; \
2187 none |= result; \
2188 } \
2189 if (record) { \
2190 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2191 } \
2192 }
2193 #define VCMPFP(suffix, compare, order) \
2194 VCMPFP_DO(suffix, compare, order, 0) \
2195 VCMPFP_DO(suffix##_dot, compare, order, 1)
2196 VCMPFP(eqfp, ==, float_relation_equal)
2197 VCMPFP(gefp, !=, float_relation_less)
2198 VCMPFP(gtfp, ==, float_relation_greater)
2199 #undef VCMPFP_DO
2200 #undef VCMPFP
2201
2202 static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
2203 int record)
2204 {
2205 int i;
2206 int all_in = 0;
2207
2208 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2209 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2210 if (le_rel == float_relation_unordered) {
2211 r->u32[i] = 0xc0000000;
2212 /* ALL_IN does not need to be updated here. */
2213 } else {
2214 float32 bneg = float32_chs(b->f[i]);
2215 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2216 int le = le_rel != float_relation_greater;
2217 int ge = ge_rel != float_relation_less;
2218
2219 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2220 all_in |= (!le | !ge);
2221 }
2222 }
2223 if (record) {
2224 env->crf[6] = (all_in == 0) << 1;
2225 }
2226 }
2227
2228 void helper_vcmpbfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2229 {
2230 vcmpbfp_internal(r, a, b, 0);
2231 }
2232
2233 void helper_vcmpbfp_dot(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2234 {
2235 vcmpbfp_internal(r, a, b, 1);
2236 }
2237
2238 #define VCT(suffix, satcvt, element) \
2239 void helper_vct##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2240 { \
2241 int i; \
2242 int sat = 0; \
2243 float_status s = env->vec_status; \
2244 \
2245 set_float_rounding_mode(float_round_to_zero, &s); \
2246 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2247 if (float32_is_any_nan(b->f[i])) { \
2248 r->element[i] = 0; \
2249 } else { \
2250 float64 t = float32_to_float64(b->f[i], &s); \
2251 int64_t j; \
2252 \
2253 t = float64_scalbn(t, uim, &s); \
2254 j = float64_to_int64(t, &s); \
2255 r->element[i] = satcvt(j, &sat); \
2256 } \
2257 } \
2258 if (sat) { \
2259 env->vscr |= (1 << VSCR_SAT); \
2260 } \
2261 }
2262 VCT(uxs, cvtsduw, u32)
2263 VCT(sxs, cvtsdsw, s32)
2264 #undef VCT
2265
2266 void helper_vmaddfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2267 {
2268 int i;
2269
2270 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2271 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2272 /* Need to do the computation in higher precision and round
2273 * once at the end. */
2274 float64 af, bf, cf, t;
2275
2276 af = float32_to_float64(a->f[i], &env->vec_status);
2277 bf = float32_to_float64(b->f[i], &env->vec_status);
2278 cf = float32_to_float64(c->f[i], &env->vec_status);
2279 t = float64_mul(af, cf, &env->vec_status);
2280 t = float64_add(t, bf, &env->vec_status);
2281 r->f[i] = float64_to_float32(t, &env->vec_status);
2282 }
2283 }
2284 }
2285
2286 void helper_vmhaddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2287 {
2288 int sat = 0;
2289 int i;
2290
2291 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2292 int32_t prod = a->s16[i] * b->s16[i];
2293 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2294
2295 r->s16[i] = cvtswsh(t, &sat);
2296 }
2297
2298 if (sat) {
2299 env->vscr |= (1 << VSCR_SAT);
2300 }
2301 }
2302
2303 void helper_vmhraddshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2304 {
2305 int sat = 0;
2306 int i;
2307
2308 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2309 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2310 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2311 r->s16[i] = cvtswsh(t, &sat);
2312 }
2313
2314 if (sat) {
2315 env->vscr |= (1 << VSCR_SAT);
2316 }
2317 }
2318
2319 #define VMINMAX_DO(name, compare, element) \
2320 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2321 { \
2322 int i; \
2323 \
2324 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2325 if (a->element[i] compare b->element[i]) { \
2326 r->element[i] = b->element[i]; \
2327 } else { \
2328 r->element[i] = a->element[i]; \
2329 } \
2330 } \
2331 }
2332 #define VMINMAX(suffix, element) \
2333 VMINMAX_DO(min##suffix, >, element) \
2334 VMINMAX_DO(max##suffix, <, element)
2335 VMINMAX(sb, s8)
2336 VMINMAX(sh, s16)
2337 VMINMAX(sw, s32)
2338 VMINMAX(ub, u8)
2339 VMINMAX(uh, u16)
2340 VMINMAX(uw, u32)
2341 #undef VMINMAX_DO
2342 #undef VMINMAX
2343
2344 #define VMINMAXFP(suffix, rT, rF) \
2345 void helper_v##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2346 { \
2347 int i; \
2348 \
2349 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2350 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2351 if (float32_lt_quiet(a->f[i], b->f[i], \
2352 &env->vec_status)) { \
2353 r->f[i] = rT->f[i]; \
2354 } else { \
2355 r->f[i] = rF->f[i]; \
2356 } \
2357 } \
2358 } \
2359 }
2360 VMINMAXFP(minfp, a, b)
2361 VMINMAXFP(maxfp, b, a)
2362 #undef VMINMAXFP
2363
2364 void helper_vmladduhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2365 {
2366 int i;
2367
2368 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2369 int32_t prod = a->s16[i] * b->s16[i];
2370 r->s16[i] = (int16_t) (prod + c->s16[i]);
2371 }
2372 }
2373
2374 #define VMRG_DO(name, element, highp) \
2375 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2376 { \
2377 ppc_avr_t result; \
2378 int i; \
2379 size_t n_elems = ARRAY_SIZE(r->element); \
2380 \
2381 for (i = 0; i < n_elems / 2; i++) { \
2382 if (highp) { \
2383 result.element[i*2+HI_IDX] = a->element[i]; \
2384 result.element[i*2+LO_IDX] = b->element[i]; \
2385 } else { \
2386 result.element[n_elems - i * 2 - (1 + HI_IDX)] = \
2387 b->element[n_elems - i - 1]; \
2388 result.element[n_elems - i * 2 - (1 + LO_IDX)] = \
2389 a->element[n_elems - i - 1]; \
2390 } \
2391 } \
2392 *r = result; \
2393 }
2394 #if defined(HOST_WORDS_BIGENDIAN)
2395 #define MRGHI 0
2396 #define MRGLO 1
2397 #else
2398 #define MRGHI 1
2399 #define MRGLO 0
2400 #endif
2401 #define VMRG(suffix, element) \
2402 VMRG_DO(mrgl##suffix, element, MRGHI) \
2403 VMRG_DO(mrgh##suffix, element, MRGLO)
2404 VMRG(b, u8)
2405 VMRG(h, u16)
2406 VMRG(w, u32)
2407 #undef VMRG_DO
2408 #undef VMRG
2409 #undef MRGHI
2410 #undef MRGLO
2411
2412 void helper_vmsummbm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2413 {
2414 int32_t prod[16];
2415 int i;
2416
2417 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2418 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2419 }
2420
2421 VECTOR_FOR_INORDER_I(i, s32) {
2422 r->s32[i] = c->s32[i] + prod[4 * i] + prod[4 * i + 1] +
2423 prod[4 * i + 2] + prod[4 * i + 3];
2424 }
2425 }
2426
2427 void helper_vmsumshm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2428 {
2429 int32_t prod[8];
2430 int i;
2431
2432 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2433 prod[i] = a->s16[i] * b->s16[i];
2434 }
2435
2436 VECTOR_FOR_INORDER_I(i, s32) {
2437 r->s32[i] = c->s32[i] + prod[2 * i] + prod[2 * i + 1];
2438 }
2439 }
2440
2441 void helper_vmsumshs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2442 {
2443 int32_t prod[8];
2444 int i;
2445 int sat = 0;
2446
2447 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2448 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2449 }
2450
2451 VECTOR_FOR_INORDER_I(i, s32) {
2452 int64_t t = (int64_t)c->s32[i] + prod[2 * i] + prod[2 * i + 1];
2453
2454 r->u32[i] = cvtsdsw(t, &sat);
2455 }
2456
2457 if (sat) {
2458 env->vscr |= (1 << VSCR_SAT);
2459 }
2460 }
2461
2462 void helper_vmsumubm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2463 {
2464 uint16_t prod[16];
2465 int i;
2466
2467 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2468 prod[i] = a->u8[i] * b->u8[i];
2469 }
2470
2471 VECTOR_FOR_INORDER_I(i, u32) {
2472 r->u32[i] = c->u32[i] + prod[4 * i] + prod[4 * i + 1] +
2473 prod[4 * i + 2] + prod[4 * i + 3];
2474 }
2475 }
2476
2477 void helper_vmsumuhm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2478 {
2479 uint32_t prod[8];
2480 int i;
2481
2482 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2483 prod[i] = a->u16[i] * b->u16[i];
2484 }
2485
2486 VECTOR_FOR_INORDER_I(i, u32) {
2487 r->u32[i] = c->u32[i] + prod[2 * i] + prod[2 * i + 1];
2488 }
2489 }
2490
2491 void helper_vmsumuhs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2492 {
2493 uint32_t prod[8];
2494 int i;
2495 int sat = 0;
2496
2497 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2498 prod[i] = a->u16[i] * b->u16[i];
2499 }
2500
2501 VECTOR_FOR_INORDER_I(i, s32) {
2502 uint64_t t = (uint64_t)c->u32[i] + prod[2 * i] + prod[2 * i + 1];
2503
2504 r->u32[i] = cvtuduw(t, &sat);
2505 }
2506
2507 if (sat) {
2508 env->vscr |= (1 << VSCR_SAT);
2509 }
2510 }
2511
2512 #define VMUL_DO(name, mul_element, prod_element, evenp) \
2513 void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2514 { \
2515 int i; \
2516 \
2517 VECTOR_FOR_INORDER_I(i, prod_element) { \
2518 if (evenp) { \
2519 r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
2520 b->mul_element[i * 2 + HI_IDX]; \
2521 } else { \
2522 r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
2523 b->mul_element[i * 2 + LO_IDX]; \
2524 } \
2525 } \
2526 }
2527 #define VMUL(suffix, mul_element, prod_element) \
2528 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2529 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2530 VMUL(sb, s8, s16)
2531 VMUL(sh, s16, s32)
2532 VMUL(ub, u8, u16)
2533 VMUL(uh, u16, u32)
2534 #undef VMUL_DO
2535 #undef VMUL
2536
2537 void helper_vnmsubfp(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2538 {
2539 int i;
2540
2541 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2542 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2543 /* Need to do the computation is higher precision and round
2544 * once at the end. */
2545 float64 af, bf, cf, t;
2546
2547 af = float32_to_float64(a->f[i], &env->vec_status);
2548 bf = float32_to_float64(b->f[i], &env->vec_status);
2549 cf = float32_to_float64(c->f[i], &env->vec_status);
2550 t = float64_mul(af, cf, &env->vec_status);
2551 t = float64_sub(t, bf, &env->vec_status);
2552 t = float64_chs(t);
2553 r->f[i] = float64_to_float32(t, &env->vec_status);
2554 }
2555 }
2556 }
2557
2558 void helper_vperm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2559 {
2560 ppc_avr_t result;
2561 int i;
2562
2563 VECTOR_FOR_INORDER_I(i, u8) {
2564 int s = c->u8[i] & 0x1f;
2565 #if defined(HOST_WORDS_BIGENDIAN)
2566 int index = s & 0xf;
2567 #else
2568 int index = 15 - (s & 0xf);
2569 #endif
2570
2571 if (s & 0x10) {
2572 result.u8[i] = b->u8[index];
2573 } else {
2574 result.u8[i] = a->u8[index];
2575 }
2576 }
2577 *r = result;
2578 }
2579
2580 #if defined(HOST_WORDS_BIGENDIAN)
2581 #define PKBIG 1
2582 #else
2583 #define PKBIG 0
2584 #endif
2585 void helper_vpkpx(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2586 {
2587 int i, j;
2588 ppc_avr_t result;
2589 #if defined(HOST_WORDS_BIGENDIAN)
2590 const ppc_avr_t *x[2] = { a, b };
2591 #else
2592 const ppc_avr_t *x[2] = { b, a };
2593 #endif
2594
2595 VECTOR_FOR_INORDER_I(i, u64) {
2596 VECTOR_FOR_INORDER_I(j, u32) {
2597 uint32_t e = x[i]->u32[j];
2598
2599 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2600 ((e >> 6) & 0x3e0) |
2601 ((e >> 3) & 0x1f));
2602 }
2603 }
2604 *r = result;
2605 }
2606
2607 #define VPK(suffix, from, to, cvt, dosat) \
2608 void helper_vpk##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2609 { \
2610 int i; \
2611 int sat = 0; \
2612 ppc_avr_t result; \
2613 ppc_avr_t *a0 = PKBIG ? a : b; \
2614 ppc_avr_t *a1 = PKBIG ? b : a; \
2615 \
2616 VECTOR_FOR_INORDER_I(i, from) { \
2617 result.to[i] = cvt(a0->from[i], &sat); \
2618 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2619 } \
2620 *r = result; \
2621 if (dosat && sat) { \
2622 env->vscr |= (1 << VSCR_SAT); \
2623 } \
2624 }
2625 #define I(x, y) (x)
2626 VPK(shss, s16, s8, cvtshsb, 1)
2627 VPK(shus, s16, u8, cvtshub, 1)
2628 VPK(swss, s32, s16, cvtswsh, 1)
2629 VPK(swus, s32, u16, cvtswuh, 1)
2630 VPK(uhus, u16, u8, cvtuhub, 1)
2631 VPK(uwus, u32, u16, cvtuwuh, 1)
2632 VPK(uhum, u16, u8, I, 0)
2633 VPK(uwum, u32, u16, I, 0)
2634 #undef I
2635 #undef VPK
2636 #undef PKBIG
2637
2638 void helper_vrefp(ppc_avr_t *r, ppc_avr_t *b)
2639 {
2640 int i;
2641
2642 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2643 HANDLE_NAN1(r->f[i], b->f[i]) {
2644 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2645 }
2646 }
2647 }
2648
2649 #define VRFI(suffix, rounding) \
2650 void helper_vrfi##suffix(ppc_avr_t *r, ppc_avr_t *b) \
2651 { \
2652 int i; \
2653 float_status s = env->vec_status; \
2654 \
2655 set_float_rounding_mode(rounding, &s); \
2656 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2657 HANDLE_NAN1(r->f[i], b->f[i]) { \
2658 r->f[i] = float32_round_to_int (b->f[i], &s); \
2659 } \
2660 } \
2661 }
2662 VRFI(n, float_round_nearest_even)
2663 VRFI(m, float_round_down)
2664 VRFI(p, float_round_up)
2665 VRFI(z, float_round_to_zero)
2666 #undef VRFI
2667
2668 #define VROTATE(suffix, element) \
2669 void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2670 { \
2671 int i; \
2672 \
2673 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2674 unsigned int mask = ((1 << \
2675 (3 + (sizeof(a->element[0]) >> 1))) \
2676 - 1); \
2677 unsigned int shift = b->element[i] & mask; \
2678 r->element[i] = (a->element[i] << shift) | \
2679 (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2680 } \
2681 }
2682 VROTATE(b, u8)
2683 VROTATE(h, u16)
2684 VROTATE(w, u32)
2685 #undef VROTATE
2686
2687 void helper_vrsqrtefp(ppc_avr_t *r, ppc_avr_t *b)
2688 {
2689 int i;
2690
2691 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2692 HANDLE_NAN1(r->f[i], b->f[i]) {
2693 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2694
2695 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2696 }
2697 }
2698 }
2699
2700 void helper_vsel(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2701 {
2702 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2703 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2704 }
2705
2706 void helper_vexptefp(ppc_avr_t *r, ppc_avr_t *b)
2707 {
2708 int i;
2709
2710 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2711 HANDLE_NAN1(r->f[i], b->f[i]) {
2712 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2713 }
2714 }
2715 }
2716
2717 void helper_vlogefp(ppc_avr_t *r, ppc_avr_t *b)
2718 {
2719 int i;
2720
2721 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2722 HANDLE_NAN1(r->f[i], b->f[i]) {
2723 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2724 }
2725 }
2726 }
2727
2728 #if defined(HOST_WORDS_BIGENDIAN)
2729 #define LEFT 0
2730 #define RIGHT 1
2731 #else
2732 #define LEFT 1
2733 #define RIGHT 0
2734 #endif
2735 /* The specification says that the results are undefined if all of the
2736 * shift counts are not identical. We check to make sure that they are
2737 * to conform to what real hardware appears to do. */
2738 #define VSHIFT(suffix, leftp) \
2739 void helper_vs##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2740 { \
2741 int shift = b->u8[LO_IDX*15] & 0x7; \
2742 int doit = 1; \
2743 int i; \
2744 \
2745 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2746 doit = doit && ((b->u8[i] & 0x7) == shift); \
2747 } \
2748 if (doit) { \
2749 if (shift == 0) { \
2750 *r = *a; \
2751 } else if (leftp) { \
2752 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2753 \
2754 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2755 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2756 } else { \
2757 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2758 \
2759 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2760 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2761 } \
2762 } \
2763 }
2764 VSHIFT(l, LEFT)
2765 VSHIFT(r, RIGHT)
2766 #undef VSHIFT
2767 #undef LEFT
2768 #undef RIGHT
2769
2770 #define VSL(suffix, element) \
2771 void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2772 { \
2773 int i; \
2774 \
2775 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2776 unsigned int mask = ((1 << \
2777 (3 + (sizeof(a->element[0]) >> 1))) \
2778 - 1); \
2779 unsigned int shift = b->element[i] & mask; \
2780 \
2781 r->element[i] = a->element[i] << shift; \
2782 } \
2783 }
2784 VSL(b, u8)
2785 VSL(h, u16)
2786 VSL(w, u32)
2787 #undef VSL
2788
2789 void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2790 {
2791 int sh = shift & 0xf;
2792 int i;
2793 ppc_avr_t result;
2794
2795 #if defined(HOST_WORDS_BIGENDIAN)
2796 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2797 int index = sh + i;
2798 if (index > 0xf) {
2799 result.u8[i] = b->u8[index - 0x10];
2800 } else {
2801 result.u8[i] = a->u8[index];
2802 }
2803 }
2804 #else
2805 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2806 int index = (16 - sh) + i;
2807 if (index > 0xf) {
2808 result.u8[i] = a->u8[index - 0x10];
2809 } else {
2810 result.u8[i] = b->u8[index];
2811 }
2812 }
2813 #endif
2814 *r = result;
2815 }
2816
2817 void helper_vslo(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2818 {
2819 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2820
2821 #if defined(HOST_WORDS_BIGENDIAN)
2822 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
2823 memset(&r->u8[16-sh], 0, sh);
2824 #else
2825 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
2826 memset(&r->u8[0], 0, sh);
2827 #endif
2828 }
2829
2830 /* Experimental testing shows that hardware masks the immediate. */
2831 #define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2832 #if defined(HOST_WORDS_BIGENDIAN)
2833 #define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2834 #else
2835 #define SPLAT_ELEMENT(element) \
2836 (ARRAY_SIZE(r->element) - 1 - _SPLAT_MASKED(element))
2837 #endif
2838 #define VSPLT(suffix, element) \
2839 void helper_vsplt##suffix(ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2840 { \
2841 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2842 int i; \
2843 \
2844 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2845 r->element[i] = s; \
2846 } \
2847 }
2848 VSPLT(b, u8)
2849 VSPLT(h, u16)
2850 VSPLT(w, u32)
2851 #undef VSPLT
2852 #undef SPLAT_ELEMENT
2853 #undef _SPLAT_MASKED
2854
2855 #define VSPLTI(suffix, element, splat_type) \
2856 void helper_vspltis##suffix(ppc_avr_t *r, uint32_t splat) \
2857 { \
2858 splat_type x = (int8_t)(splat << 3) >> 3; \
2859 int i; \
2860 \
2861 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2862 r->element[i] = x; \
2863 } \
2864 }
2865 VSPLTI(b, s8, int8_t)
2866 VSPLTI(h, s16, int16_t)
2867 VSPLTI(w, s32, int32_t)
2868 #undef VSPLTI
2869
2870 #define VSR(suffix, element) \
2871 void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2872 { \
2873 int i; \
2874 \
2875 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2876 unsigned int mask = ((1 << \
2877 (3 + (sizeof(a->element[0]) >> 1))) \
2878 - 1); \
2879 unsigned int shift = b->element[i] & mask; \
2880 \
2881 r->element[i] = a->element[i] >> shift; \
2882 } \
2883 }
2884 VSR(ab, s8)
2885 VSR(ah, s16)
2886 VSR(aw, s32)
2887 VSR(b, u8)
2888 VSR(h, u16)
2889 VSR(w, u32)
2890 #undef VSR
2891
2892 void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2893 {
2894 int sh = (b->u8[LO_IDX * 0xf] >> 3) & 0xf;
2895
2896 #if defined(HOST_WORDS_BIGENDIAN)
2897 memmove(&r->u8[sh], &a->u8[0], 16 - sh);
2898 memset(&r->u8[0], 0, sh);
2899 #else
2900 memmove(&r->u8[0], &a->u8[sh], 16 - sh);
2901 memset(&r->u8[16 - sh], 0, sh);
2902 #endif
2903 }
2904
2905 void helper_vsubcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2906 {
2907 int i;
2908
2909 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2910 r->u32[i] = a->u32[i] >= b->u32[i];
2911 }
2912 }
2913
2914 void helper_vsumsws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2915 {
2916 int64_t t;
2917 int i, upper;
2918 ppc_avr_t result;
2919 int sat = 0;
2920
2921 #if defined(HOST_WORDS_BIGENDIAN)
2922 upper = ARRAY_SIZE(r->s32)-1;
2923 #else
2924 upper = 0;
2925 #endif
2926 t = (int64_t)b->s32[upper];
2927 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2928 t += a->s32[i];
2929 result.s32[i] = 0;
2930 }
2931 result.s32[upper] = cvtsdsw(t, &sat);
2932 *r = result;
2933
2934 if (sat) {
2935 env->vscr |= (1 << VSCR_SAT);
2936 }
2937 }
2938
2939 void helper_vsum2sws(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2940 {
2941 int i, j, upper;
2942 ppc_avr_t result;
2943 int sat = 0;
2944
2945 #if defined(HOST_WORDS_BIGENDIAN)
2946 upper = 1;
2947 #else
2948 upper = 0;
2949 #endif
2950 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2951 int64_t t = (int64_t)b->s32[upper + i * 2];
2952
2953 result.u64[i] = 0;
2954 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2955 t += a->s32[2 * i + j];
2956 }
2957 result.s32[upper + i * 2] = cvtsdsw(t, &sat);
2958 }
2959
2960 *r = result;
2961 if (sat) {
2962 env->vscr |= (1 << VSCR_SAT);
2963 }
2964 }
2965
2966 void helper_vsum4sbs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2967 {
2968 int i, j;
2969 int sat = 0;
2970
2971 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2972 int64_t t = (int64_t)b->s32[i];
2973
2974 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2975 t += a->s8[4 * i + j];
2976 }
2977 r->s32[i] = cvtsdsw(t, &sat);
2978 }
2979
2980 if (sat) {
2981 env->vscr |= (1 << VSCR_SAT);
2982 }
2983 }
2984
2985 void helper_vsum4shs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2986 {
2987 int sat = 0;
2988 int i;
2989
2990 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2991 int64_t t = (int64_t)b->s32[i];
2992
2993 t += a->s16[2 * i] + a->s16[2 * i + 1];
2994 r->s32[i] = cvtsdsw(t, &sat);
2995 }
2996
2997 if (sat) {
2998 env->vscr |= (1 << VSCR_SAT);
2999 }
3000 }
3001
3002 void helper_vsum4ubs(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
3003 {
3004 int i, j;
3005 int sat = 0;
3006
3007 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
3008 uint64_t t = (uint64_t)b->u32[i];
3009
3010 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
3011 t += a->u8[4 * i + j];
3012 }
3013 r->u32[i] = cvtuduw(t, &sat);
3014 }
3015
3016 if (sat) {
3017 env->vscr |= (1 << VSCR_SAT);
3018 }
3019 }
3020
3021 #if defined(HOST_WORDS_BIGENDIAN)
3022 #define UPKHI 1
3023 #define UPKLO 0
3024 #else
3025 #define UPKHI 0
3026 #define UPKLO 1
3027 #endif
3028 #define VUPKPX(suffix, hi) \
3029 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
3030 { \
3031 int i; \
3032 ppc_avr_t result; \
3033 \
3034 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
3035 uint16_t e = b->u16[hi ? i : i+4]; \
3036 uint8_t a = (e >> 15) ? 0xff : 0; \
3037 uint8_t r = (e >> 10) & 0x1f; \
3038 uint8_t g = (e >> 5) & 0x1f; \
3039 uint8_t b = e & 0x1f; \
3040 \
3041 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3042 } \
3043 *r = result; \
3044 }
3045 VUPKPX(lpx, UPKLO)
3046 VUPKPX(hpx, UPKHI)
3047 #undef VUPKPX
3048
3049 #define VUPK(suffix, unpacked, packee, hi) \
3050 void helper_vupk##suffix(ppc_avr_t *r, ppc_avr_t *b) \
3051 { \
3052 int i; \
3053 ppc_avr_t result; \
3054 \
3055 if (hi) { \
3056 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3057 result.unpacked[i] = b->packee[i]; \
3058 } \
3059 } else { \
3060 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); \
3061 i++) { \
3062 result.unpacked[i - ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3063 } \
3064 } \
3065 *r = result; \
3066 }
3067 VUPK(hsb, s16, s8, UPKHI)
3068 VUPK(hsh, s32, s16, UPKHI)
3069 VUPK(lsb, s16, s8, UPKLO)
3070 VUPK(lsh, s32, s16, UPKLO)
3071 #undef VUPK
3072 #undef UPKHI
3073 #undef UPKLO
3074
3075 #undef DO_HANDLE_NAN
3076 #undef HANDLE_NAN1
3077 #undef HANDLE_NAN2
3078 #undef HANDLE_NAN3
3079 #undef VECTOR_FOR_INORDER_I
3080 #undef HI_IDX
3081 #undef LO_IDX
3082
3083 /*****************************************************************************/
3084 /* SPE extension helpers */
3085 /* Use a table to make this quicker */
3086 static uint8_t hbrev[16] = {
3087 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3088 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3089 };
3090
3091 static inline uint8_t byte_reverse(uint8_t val)
3092 {
3093 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3094 }
3095
3096 static inline uint32_t word_reverse(uint32_t val)
3097 {
3098 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3099 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3100 }
3101
3102 #define MASKBITS 16 /* Random value - to be fixed (implementation dependent) */
3103 target_ulong helper_brinc(target_ulong arg1, target_ulong arg2)
3104 {
3105 uint32_t a, b, d, mask;
3106
3107 mask = UINT32_MAX >> (32 - MASKBITS);
3108 a = arg1 & mask;
3109 b = arg2 & mask;
3110 d = word_reverse(1 + word_reverse(a | ~b));
3111 return (arg1 & ~mask) | (d & b);
3112 }
3113
3114 uint32_t helper_cntlsw32(uint32_t val)
3115 {
3116 if (val & 0x80000000) {
3117 return clz32(~val);
3118 } else {
3119 return clz32(val);
3120 }
3121 }
3122
3123 uint32_t helper_cntlzw32(uint32_t val)
3124 {
3125 return clz32(val);
3126 }
3127
3128 /* Single-precision floating-point conversions */
3129 static inline uint32_t efscfsi(uint32_t val)
3130 {
3131 CPU_FloatU u;
3132
3133 u.f = int32_to_float32(val, &env->vec_status);
3134
3135 return u.l;
3136 }
3137
3138 static inline uint32_t efscfui(uint32_t val)
3139 {
3140 CPU_FloatU u;
3141
3142 u.f = uint32_to_float32(val, &env->vec_status);
3143
3144 return u.l;
3145 }
3146
3147 static inline int32_t efsctsi(uint32_t val)
3148 {
3149 CPU_FloatU u;
3150
3151 u.l = val;
3152 /* NaN are not treated the same way IEEE 754 does */
3153 if (unlikely(float32_is_quiet_nan(u.f))) {
3154 return 0;
3155 }
3156
3157 return float32_to_int32(u.f, &env->vec_status);
3158 }
3159
3160 static inline uint32_t efsctui(uint32_t val)
3161 {
3162 CPU_FloatU u;
3163
3164 u.l = val;
3165 /* NaN are not treated the same way IEEE 754 does */
3166 if (unlikely(float32_is_quiet_nan(u.f))) {
3167 return 0;
3168 }
3169
3170 return float32_to_uint32(u.f, &env->vec_status);
3171 }
3172
3173 static inline uint32_t efsctsiz(uint32_t val)
3174 {
3175 CPU_FloatU u;
3176
3177 u.l = val;
3178 /* NaN are not treated the same way IEEE 754 does */
3179 if (unlikely(float32_is_quiet_nan(u.f))) {
3180 return 0;
3181 }
3182
3183 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
3184 }
3185
3186 static inline uint32_t efsctuiz(uint32_t val)
3187 {
3188 CPU_FloatU u;
3189
3190 u.l = val;
3191 /* NaN are not treated the same way IEEE 754 does */
3192 if (unlikely(float32_is_quiet_nan(u.f))) {
3193 return 0;
3194 }
3195
3196 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
3197 }
3198
3199 static inline uint32_t efscfsf(uint32_t val)
3200 {
3201 CPU_FloatU u;
3202 float32 tmp;
3203
3204 u.f = int32_to_float32(val, &env->vec_status);
3205 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3206 u.f = float32_div(u.f, tmp, &env->vec_status);
3207
3208 return u.l;
3209 }
3210
3211 static inline uint32_t efscfuf(uint32_t val)
3212 {
3213 CPU_FloatU u;
3214 float32 tmp;
3215
3216 u.f = uint32_to_float32(val, &env->vec_status);
3217 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3218 u.f = float32_div(u.f, tmp, &env->vec_status);
3219
3220 return u.l;
3221 }
3222
3223 static inline uint32_t efsctsf(uint32_t val)
3224 {
3225 CPU_FloatU u;
3226 float32 tmp;
3227
3228 u.l = val;
3229 /* NaN are not treated the same way IEEE 754 does */
3230 if (unlikely(float32_is_quiet_nan(u.f))) {
3231 return 0;
3232 }
3233 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3234 u.f = float32_mul(u.f, tmp, &env->vec_status);
3235
3236 return float32_to_int32(u.f, &env->vec_status);
3237 }
3238
3239 static inline uint32_t efsctuf(uint32_t val)
3240 {
3241 CPU_FloatU u;
3242 float32 tmp;
3243
3244 u.l = val;
3245 /* NaN are not treated the same way IEEE 754 does */
3246 if (unlikely(float32_is_quiet_nan(u.f))) {
3247 return 0;
3248 }
3249 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3250 u.f = float32_mul(u.f, tmp, &env->vec_status);
3251
3252 return float32_to_uint32(u.f, &env->vec_status);
3253 }
3254
3255 #define HELPER_SPE_SINGLE_CONV(name) \
3256 uint32_t helper_e##name(uint32_t val) \
3257 { \
3258 return e##name(val); \
3259 }
3260 /* efscfsi */
3261 HELPER_SPE_SINGLE_CONV(fscfsi);
3262 /* efscfui */
3263 HELPER_SPE_SINGLE_CONV(fscfui);
3264 /* efscfuf */
3265 HELPER_SPE_SINGLE_CONV(fscfuf);
3266 /* efscfsf */
3267 HELPER_SPE_SINGLE_CONV(fscfsf);
3268 /* efsctsi */
3269 HELPER_SPE_SINGLE_CONV(fsctsi);
3270 /* efsctui */
3271 HELPER_SPE_SINGLE_CONV(fsctui);
3272 /* efsctsiz */
3273 HELPER_SPE_SINGLE_CONV(fsctsiz);
3274 /* efsctuiz */
3275 HELPER_SPE_SINGLE_CONV(fsctuiz);
3276 /* efsctsf */
3277 HELPER_SPE_SINGLE_CONV(fsctsf);
3278 /* efsctuf */
3279 HELPER_SPE_SINGLE_CONV(fsctuf);
3280
3281 #define HELPER_SPE_VECTOR_CONV(name) \
3282 uint64_t helper_ev##name(uint64_t val) \
3283 { \
3284 return ((uint64_t)e##name(val >> 32) << 32) | \
3285 (uint64_t)e##name(val); \
3286 }
3287 /* evfscfsi */
3288 HELPER_SPE_VECTOR_CONV(fscfsi);
3289 /* evfscfui */
3290 HELPER_SPE_VECTOR_CONV(fscfui);
3291 /* evfscfuf */
3292 HELPER_SPE_VECTOR_CONV(fscfuf);
3293 /* evfscfsf */
3294 HELPER_SPE_VECTOR_CONV(fscfsf);
3295 /* evfsctsi */
3296 HELPER_SPE_VECTOR_CONV(fsctsi);
3297 /* evfsctui */
3298 HELPER_SPE_VECTOR_CONV(fsctui);
3299 /* evfsctsiz */
3300 HELPER_SPE_VECTOR_CONV(fsctsiz);
3301 /* evfsctuiz */
3302 HELPER_SPE_VECTOR_CONV(fsctuiz);
3303 /* evfsctsf */
3304 HELPER_SPE_VECTOR_CONV(fsctsf);
3305 /* evfsctuf */
3306 HELPER_SPE_VECTOR_CONV(fsctuf);
3307
3308 /* Single-precision floating-point arithmetic */
3309 static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
3310 {
3311 CPU_FloatU u1, u2;
3312
3313 u1.l = op1;
3314 u2.l = op2;
3315 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
3316 return u1.l;
3317 }
3318
3319 static inline uint32_t efssub(uint32_t op1, uint32_t op2)
3320 {
3321 CPU_FloatU u1, u2;
3322
3323 u1.l = op1;
3324 u2.l = op2;
3325 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
3326 return u1.l;
3327 }
3328
3329 static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
3330 {
3331 CPU_FloatU u1, u2;
3332
3333 u1.l = op1;
3334 u2.l = op2;
3335 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
3336 return u1.l;
3337 }
3338
3339 static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
3340 {
3341 CPU_FloatU u1, u2;
3342
3343 u1.l = op1;
3344 u2.l = op2;
3345 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
3346 return u1.l;
3347 }
3348
3349 #define HELPER_SPE_SINGLE_ARITH(name) \
3350 uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
3351 { \
3352 return e##name(op1, op2); \
3353 }
3354 /* efsadd */
3355 HELPER_SPE_SINGLE_ARITH(fsadd);
3356 /* efssub */
3357 HELPER_SPE_SINGLE_ARITH(fssub);
3358 /* efsmul */
3359 HELPER_SPE_SINGLE_ARITH(fsmul);
3360 /* efsdiv */
3361 HELPER_SPE_SINGLE_ARITH(fsdiv);
3362
3363 #define HELPER_SPE_VECTOR_ARITH(name) \
3364 uint64_t helper_ev##name(uint64_t op1, uint64_t op2) \
3365 { \
3366 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3367 (uint64_t)e##name(op1, op2); \
3368 }
3369 /* evfsadd */
3370 HELPER_SPE_VECTOR_ARITH(fsadd);
3371 /* evfssub */
3372 HELPER_SPE_VECTOR_ARITH(fssub);
3373 /* evfsmul */
3374 HELPER_SPE_VECTOR_ARITH(fsmul);
3375 /* evfsdiv */
3376 HELPER_SPE_VECTOR_ARITH(fsdiv);
3377
3378 /* Single-precision floating-point comparisons */
3379 static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
3380 {
3381 CPU_FloatU u1, u2;
3382
3383 u1.l = op1;
3384 u2.l = op2;
3385 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3386 }
3387
3388 static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
3389 {
3390 CPU_FloatU u1, u2;
3391
3392 u1.l = op1;
3393 u2.l = op2;
3394 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
3395 }
3396
3397 static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
3398 {
3399 CPU_FloatU u1, u2;
3400
3401 u1.l = op1;
3402 u2.l = op2;
3403 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
3404 }
3405
3406 static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
3407 {
3408 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3409 return efscmplt(op1, op2);
3410 }
3411
3412 static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
3413 {
3414 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3415 return efscmpgt(op1, op2);
3416 }
3417
3418 static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
3419 {
3420 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3421 return efscmpeq(op1, op2);
3422 }
3423
3424 #define HELPER_SINGLE_SPE_CMP(name) \
3425 uint32_t helper_e##name(uint32_t op1, uint32_t op2) \
3426 { \
3427 return e##name(op1, op2) << 2; \
3428 }
3429 /* efststlt */
3430 HELPER_SINGLE_SPE_CMP(fststlt);
3431 /* efststgt */
3432 HELPER_SINGLE_SPE_CMP(fststgt);
3433 /* efststeq */
3434 HELPER_SINGLE_SPE_CMP(fststeq);
3435 /* efscmplt */
3436 HELPER_SINGLE_SPE_CMP(fscmplt);
3437 /* efscmpgt */
3438 HELPER_SINGLE_SPE_CMP(fscmpgt);
3439 /* efscmpeq */
3440 HELPER_SINGLE_SPE_CMP(fscmpeq);
3441
3442 static inline uint32_t evcmp_merge(int t0, int t1)
3443 {
3444 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
3445 }
3446
3447 #define HELPER_VECTOR_SPE_CMP(name) \
3448 uint32_t helper_ev##name(uint64_t op1, uint64_t op2) \
3449 { \
3450 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3451 }
3452 /* evfststlt */
3453 HELPER_VECTOR_SPE_CMP(fststlt);
3454 /* evfststgt */
3455 HELPER_VECTOR_SPE_CMP(fststgt);
3456 /* evfststeq */
3457 HELPER_VECTOR_SPE_CMP(fststeq);
3458 /* evfscmplt */
3459 HELPER_VECTOR_SPE_CMP(fscmplt);
3460 /* evfscmpgt */
3461 HELPER_VECTOR_SPE_CMP(fscmpgt);
3462 /* evfscmpeq */
3463 HELPER_VECTOR_SPE_CMP(fscmpeq);
3464
3465 /* Double-precision floating-point conversion */
3466 uint64_t helper_efdcfsi(uint32_t val)
3467 {
3468 CPU_DoubleU u;
3469
3470 u.d = int32_to_float64(val, &env->vec_status);
3471
3472 return u.ll;
3473 }
3474
3475 uint64_t helper_efdcfsid(uint64_t val)
3476 {
3477 CPU_DoubleU u;
3478
3479 u.d = int64_to_float64(val, &env->vec_status);
3480
3481 return u.ll;
3482 }
3483
3484 uint64_t helper_efdcfui(uint32_t val)
3485 {
3486 CPU_DoubleU u;
3487
3488 u.d = uint32_to_float64(val, &env->vec_status);
3489
3490 return u.ll;
3491 }
3492
3493 uint64_t helper_efdcfuid(uint64_t val)
3494 {
3495 CPU_DoubleU u;
3496
3497 u.d = uint64_to_float64(val, &env->vec_status);
3498
3499 return u.ll;
3500 }
3501
3502 uint32_t helper_efdctsi(uint64_t val)
3503 {
3504 CPU_DoubleU u;
3505
3506 u.ll = val;
3507 /* NaN are not treated the same way IEEE 754 does */
3508 if (unlikely(float64_is_any_nan(u.d))) {
3509 return 0;
3510 }
3511
3512 return float64_to_int32(u.d, &env->vec_status);
3513 }
3514
3515 uint32_t helper_efdctui(uint64_t val)
3516 {
3517 CPU_DoubleU u;
3518
3519 u.ll = val;
3520 /* NaN are not treated the same way IEEE 754 does */
3521 if (unlikely(float64_is_any_nan(u.d))) {
3522 return 0;
3523 }
3524
3525 return float64_to_uint32(u.d, &env->vec_status);
3526 }
3527
3528 uint32_t helper_efdctsiz(uint64_t val)
3529 {
3530 CPU_DoubleU u;
3531
3532 u.ll = val;
3533 /* NaN are not treated the same way IEEE 754 does */
3534 if (unlikely(float64_is_any_nan(u.d))) {
3535 return 0;
3536 }
3537
3538 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
3539 }
3540
3541 uint64_t helper_efdctsidz(uint64_t val)
3542 {
3543 CPU_DoubleU u;
3544
3545 u.ll = val;
3546 /* NaN are not treated the same way IEEE 754 does */
3547 if (unlikely(float64_is_any_nan(u.d))) {
3548 return 0;
3549 }
3550
3551 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
3552 }
3553
3554 uint32_t helper_efdctuiz(uint64_t val)
3555 {
3556 CPU_DoubleU u;
3557
3558 u.ll = val;
3559 /* NaN are not treated the same way IEEE 754 does */
3560 if (unlikely(float64_is_any_nan(u.d))) {
3561 return 0;
3562 }
3563
3564 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
3565 }
3566
3567 uint64_t helper_efdctuidz(uint64_t val)
3568 {
3569 CPU_DoubleU u;
3570
3571 u.ll = val;
3572 /* NaN are not treated the same way IEEE 754 does */
3573 if (unlikely(float64_is_any_nan(u.d))) {
3574 return 0;
3575 }
3576
3577 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
3578 }
3579
3580 uint64_t helper_efdcfsf(uint32_t val)
3581 {
3582 CPU_DoubleU u;
3583 float64 tmp;
3584
3585 u.d = int32_to_float64(val, &env->vec_status);
3586 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3587 u.d = float64_div(u.d, tmp, &env->vec_status);
3588
3589 return u.ll;
3590 }
3591
3592 uint64_t helper_efdcfuf(uint32_t val)
3593 {
3594 CPU_DoubleU u;
3595 float64 tmp;
3596
3597 u.d = uint32_to_float64(val, &env->vec_status);
3598 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3599 u.d = float64_div(u.d, tmp, &env->vec_status);
3600
3601 return u.ll;
3602 }
3603
3604 uint32_t helper_efdctsf(uint64_t val)
3605 {
3606 CPU_DoubleU u;
3607 float64 tmp;
3608
3609 u.ll = val;
3610 /* NaN are not treated the same way IEEE 754 does */
3611 if (unlikely(float64_is_any_nan(u.d))) {
3612 return 0;
3613 }
3614 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3615 u.d = float64_mul(u.d, tmp, &env->vec_status);
3616
3617 return float64_to_int32(u.d, &env->vec_status);
3618 }
3619
3620 uint32_t helper_efdctuf(uint64_t val)
3621 {
3622 CPU_DoubleU u;
3623 float64 tmp;
3624
3625 u.ll = val;
3626 /* NaN are not treated the same way IEEE 754 does */
3627 if (unlikely(float64_is_any_nan(u.d))) {
3628 return 0;
3629 }
3630 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3631 u.d = float64_mul(u.d, tmp, &env->vec_status);
3632
3633 return float64_to_uint32(u.d, &env->vec_status);
3634 }
3635
3636 uint32_t helper_efscfd(uint64_t val)
3637 {
3638 CPU_DoubleU u1;
3639 CPU_FloatU u2;
3640
3641 u1.ll = val;
3642 u2.f = float64_to_float32(u1.d, &env->vec_status);
3643
3644 return u2.l;
3645 }
3646
3647 uint64_t helper_efdcfs(uint32_t val)
3648 {
3649 CPU_DoubleU u2;
3650 CPU_FloatU u1;
3651
3652 u1.l = val;
3653 u2.d = float32_to_float64(u1.f, &env->vec_status);
3654
3655 return u2.ll;
3656 }
3657
3658 /* Double precision fixed-point arithmetic */
3659 uint64_t helper_efdadd(uint64_t op1, uint64_t op2)
3660 {
3661 CPU_DoubleU u1, u2;
3662
3663 u1.ll = op1;
3664 u2.ll = op2;
3665 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
3666 return u1.ll;
3667 }
3668
3669 uint64_t helper_efdsub(uint64_t op1, uint64_t op2)
3670 {
3671 CPU_DoubleU u1, u2;
3672
3673 u1.ll = op1;
3674 u2.ll = op2;
3675 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
3676 return u1.ll;
3677 }
3678
3679 uint64_t helper_efdmul(uint64_t op1, uint64_t op2)
3680 {
3681 CPU_DoubleU u1, u2;
3682
3683 u1.ll = op1;
3684 u2.ll = op2;
3685 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
3686 return u1.ll;
3687 }
3688
3689 uint64_t helper_efddiv(uint64_t op1, uint64_t op2)
3690 {
3691 CPU_DoubleU u1, u2;
3692
3693 u1.ll = op1;
3694 u2.ll = op2;
3695 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
3696 return u1.ll;
3697 }
3698
3699 /* Double precision floating point helpers */
3700 uint32_t helper_efdtstlt(uint64_t op1, uint64_t op2)
3701 {
3702 CPU_DoubleU u1, u2;
3703
3704 u1.ll = op1;
3705 u2.ll = op2;
3706 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3707 }
3708
3709 uint32_t helper_efdtstgt(uint64_t op1, uint64_t op2)
3710 {
3711 CPU_DoubleU u1, u2;
3712
3713 u1.ll = op1;
3714 u2.ll = op2;
3715 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
3716 }
3717
3718 uint32_t helper_efdtsteq(uint64_t op1, uint64_t op2)
3719 {
3720 CPU_DoubleU u1, u2;
3721
3722 u1.ll = op1;
3723 u2.ll = op2;
3724 return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
3725 }
3726
3727 uint32_t helper_efdcmplt(uint64_t op1, uint64_t op2)
3728 {
3729 /* XXX: TODO: test special values (NaN, infinites, ...) */
3730 return helper_efdtstlt(op1, op2);
3731 }
3732
3733 uint32_t helper_efdcmpgt(uint64_t op1, uint64_t op2)
3734 {
3735 /* XXX: TODO: test special values (NaN, infinites, ...) */
3736 return helper_efdtstgt(op1, op2);
3737 }
3738
3739 uint32_t helper_efdcmpeq(uint64_t op1, uint64_t op2)
3740 {
3741 /* XXX: TODO: test special values (NaN, infinites, ...) */
3742 return helper_efdtsteq(op1, op2);
3743 }
3744
3745 /*****************************************************************************/
3746 /* Softmmu support */
3747 #if !defined(CONFIG_USER_ONLY)
3748
3749 #define MMUSUFFIX _mmu
3750
3751 #define SHIFT 0
3752 #include "softmmu_template.h"
3753
3754 #define SHIFT 1
3755 #include "softmmu_template.h"
3756
3757 #define SHIFT 2
3758 #include "softmmu_template.h"
3759
3760 #define SHIFT 3
3761 #include "softmmu_template.h"
3762
3763 /* try to fill the TLB and return an exception if error. If retaddr is
3764 NULL, it means that the function was called in C code (i.e. not
3765 from generated code or from helper.c) */
3766 /* XXX: fix it to restore all registers */
3767 void tlb_fill(CPUPPCState *env1, target_ulong addr, int is_write, int mmu_idx,
3768 uintptr_t retaddr)
3769 {
3770 TranslationBlock *tb;
3771 CPUPPCState *saved_env;
3772 int ret;
3773
3774 saved_env = env;
3775 env = env1;
3776 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
3777 if (unlikely(ret != 0)) {
3778 if (likely(retaddr)) {
3779 /* now we have a real cpu fault */
3780 tb = tb_find_pc(retaddr);
3781 if (likely(tb)) {
3782 /* the PC is inside the translated code. It means that we have
3783 a virtual CPU fault */
3784 cpu_restore_state(tb, env, retaddr);
3785 }
3786 }
3787 helper_raise_exception_err(env, env->exception_index, env->error_code);
3788 }
3789 env = saved_env;
3790 }
3791
3792 /* Segment registers load and store */
3793 target_ulong helper_load_sr(target_ulong sr_num)
3794 {
3795 #if defined(TARGET_PPC64)
3796 if (env->mmu_model & POWERPC_MMU_64) {
3797 return ppc_load_sr(env, sr_num);
3798 }
3799 #endif
3800 return env->sr[sr_num];
3801 }
3802
3803 void helper_store_sr(target_ulong sr_num, target_ulong val)
3804 {
3805 ppc_store_sr(env, sr_num, val);
3806 }
3807
3808 /* SLB management */
3809 #if defined(TARGET_PPC64)
3810 void helper_store_slb(target_ulong rb, target_ulong rs)
3811 {
3812 if (ppc_store_slb(env, rb, rs) < 0) {
3813 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3814 POWERPC_EXCP_INVAL);
3815 }
3816 }
3817
3818 target_ulong helper_load_slb_esid(target_ulong rb)
3819 {
3820 target_ulong rt;
3821
3822 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
3823 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3824 POWERPC_EXCP_INVAL);
3825 }
3826 return rt;
3827 }
3828
3829 target_ulong helper_load_slb_vsid(target_ulong rb)
3830 {
3831 target_ulong rt;
3832
3833 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
3834 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3835 POWERPC_EXCP_INVAL);
3836 }
3837 return rt;
3838 }
3839
3840 void helper_slbia(void)
3841 {
3842 ppc_slb_invalidate_all(env);
3843 }
3844
3845 void helper_slbie(target_ulong addr)
3846 {
3847 ppc_slb_invalidate_one(env, addr);
3848 }
3849
3850 #endif /* defined(TARGET_PPC64) */
3851
3852 /* TLB management */
3853 void helper_tlbia(void)
3854 {
3855 ppc_tlb_invalidate_all(env);
3856 }
3857
3858 void helper_tlbie(target_ulong addr)
3859 {
3860 ppc_tlb_invalidate_one(env, addr);
3861 }
3862
3863 /* Software driven TLBs management */
3864 /* PowerPC 602/603 software TLB load instructions helpers */
3865 static void do_6xx_tlb(target_ulong new_EPN, int is_code)
3866 {
3867 target_ulong RPN, CMP, EPN;
3868 int way;
3869
3870 RPN = env->spr[SPR_RPA];
3871 if (is_code) {
3872 CMP = env->spr[SPR_ICMP];
3873 EPN = env->spr[SPR_IMISS];
3874 } else {
3875 CMP = env->spr[SPR_DCMP];
3876 EPN = env->spr[SPR_DMISS];
3877 }
3878 way = (env->spr[SPR_SRR1] >> 17) & 1;
3879 (void)EPN; /* avoid a compiler warning */
3880 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3881 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3882 RPN, way);
3883 /* Store this TLB */
3884 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3885 way, is_code, CMP, RPN);
3886 }
3887
3888 void helper_6xx_tlbd(target_ulong EPN)
3889 {
3890 do_6xx_tlb(EPN, 0);
3891 }
3892
3893 void helper_6xx_tlbi(target_ulong EPN)
3894 {
3895 do_6xx_tlb(EPN, 1);
3896 }
3897
3898 /* PowerPC 74xx software TLB load instructions helpers */
3899 static void do_74xx_tlb(target_ulong new_EPN, int is_code)
3900 {
3901 target_ulong RPN, CMP, EPN;
3902 int way;
3903
3904 RPN = env->spr[SPR_PTELO];
3905 CMP = env->spr[SPR_PTEHI];
3906 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3907 way = env->spr[SPR_TLBMISS] & 0x3;
3908 (void)EPN; /* avoid a compiler warning */
3909 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3910 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3911 RPN, way);
3912 /* Store this TLB */
3913 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
3914 way, is_code, CMP, RPN);
3915 }
3916
3917 void helper_74xx_tlbd(target_ulong EPN)
3918 {
3919 do_74xx_tlb(EPN, 0);
3920 }
3921
3922 void helper_74xx_tlbi(target_ulong EPN)
3923 {
3924 do_74xx_tlb(EPN, 1);
3925 }
3926
3927 static inline target_ulong booke_tlb_to_page_size(int size)
3928 {
3929 return 1024 << (2 * size);
3930 }
3931
3932 static inline int booke_page_size_to_tlb(target_ulong page_size)
3933 {
3934 int size;
3935
3936 switch (page_size) {
3937 case 0x00000400UL:
3938 size = 0x0;
3939 break;
3940 case 0x00001000UL:
3941 size = 0x1;
3942 break;
3943 case 0x00004000UL:
3944 size = 0x2;
3945 break;
3946 case 0x00010000UL:
3947 size = 0x3;
3948 break;
3949 case 0x00040000UL:
3950 size = 0x4;
3951 break;
3952 case 0x00100000UL:
3953 size = 0x5;
3954 break;
3955 case 0x00400000UL:
3956 size = 0x6;
3957 break;
3958 case 0x01000000UL:
3959 size = 0x7;
3960 break;
3961 case 0x04000000UL:
3962 size = 0x8;
3963 break;
3964 case 0x10000000UL:
3965 size = 0x9;
3966 break;
3967 case 0x40000000UL:
3968 size = 0xA;
3969 break;
3970 #if defined(TARGET_PPC64)
3971 case 0x000100000000ULL:
3972 size = 0xB;
3973 break;
3974 case 0x000400000000ULL:
3975 size = 0xC;
3976 break;
3977 case 0x001000000000ULL:
3978 size = 0xD;
3979 break;
3980 case 0x004000000000ULL:
3981 size = 0xE;
3982 break;
3983 case 0x010000000000ULL:
3984 size = 0xF;
3985 break;
3986 #endif
3987 default:
3988 size = -1;
3989 break;
3990 }
3991
3992 return size;
3993 }
3994
3995 /* Helpers for 4xx TLB management */
3996 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
3997
3998 #define PPC4XX_TLBHI_V 0x00000040
3999 #define PPC4XX_TLBHI_E 0x00000020
4000 #define PPC4XX_TLBHI_SIZE_MIN 0
4001 #define PPC4XX_TLBHI_SIZE_MAX 7
4002 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
4003 #define PPC4XX_TLBHI_SIZE_SHIFT 7
4004 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
4005
4006 #define PPC4XX_TLBLO_EX 0x00000200
4007 #define PPC4XX_TLBLO_WR 0x00000100
4008 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
4009 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
4010
4011 target_ulong helper_4xx_tlbre_hi(target_ulong entry)
4012 {
4013 ppcemb_tlb_t *tlb;
4014 target_ulong ret;
4015 int size;
4016
4017 entry &= PPC4XX_TLB_ENTRY_MASK;
4018 tlb = &env->tlb.tlbe[entry];
4019 ret = tlb->EPN;
4020 if (tlb->prot & PAGE_VALID) {
4021 ret |= PPC4XX_TLBHI_V;
4022 }
4023 size = booke_page_size_to_tlb(tlb->size);
4024 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
4025 size = PPC4XX_TLBHI_SIZE_DEFAULT;
4026 }
4027 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
4028 env->spr[SPR_40x_PID] = tlb->PID;
4029 return ret;
4030 }
4031
4032 target_ulong helper_4xx_tlbre_lo(target_ulong entry)
4033 {
4034 ppcemb_tlb_t *tlb;
4035 target_ulong ret;
4036
4037 entry &= PPC4XX_TLB_ENTRY_MASK;
4038 tlb = &env->tlb.tlbe[entry];
4039 ret = tlb->RPN;
4040 if (tlb->prot & PAGE_EXEC) {
4041 ret |= PPC4XX_TLBLO_EX;
4042 }
4043 if (tlb->prot & PAGE_WRITE) {
4044 ret |= PPC4XX_TLBLO_WR;
4045 }
4046 return ret;
4047 }
4048
4049 void helper_4xx_tlbwe_hi(target_ulong entry, target_ulong val)
4050 {
4051 ppcemb_tlb_t *tlb;
4052 target_ulong page, end;
4053
4054 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
4055 val);
4056 entry &= PPC4XX_TLB_ENTRY_MASK;
4057 tlb = &env->tlb.tlbe[entry];
4058 /* Invalidate previous TLB (if it's valid) */
4059 if (tlb->prot & PAGE_VALID) {
4060 end = tlb->EPN + tlb->size;
4061 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
4062 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4063 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4064 tlb_flush_page(env, page);
4065 }
4066 }
4067 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4068 & PPC4XX_TLBHI_SIZE_MASK);
4069 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4070 * If this ever occurs, one should use the ppcemb target instead
4071 * of the ppc or ppc64 one
4072 */
4073 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
4074 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4075 "are not supported (%d)\n",
4076 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
4077 }
4078 tlb->EPN = val & ~(tlb->size - 1);
4079 if (val & PPC4XX_TLBHI_V) {
4080 tlb->prot |= PAGE_VALID;
4081 if (val & PPC4XX_TLBHI_E) {
4082 /* XXX: TO BE FIXED */
4083 cpu_abort(env,
4084 "Little-endian TLB entries are not supported by now\n");
4085 }
4086 } else {
4087 tlb->prot &= ~PAGE_VALID;
4088 }
4089 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
4090 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4091 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4092 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4093 tlb->prot & PAGE_READ ? 'r' : '-',
4094 tlb->prot & PAGE_WRITE ? 'w' : '-',
4095 tlb->prot & PAGE_EXEC ? 'x' : '-',
4096 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4097 /* Invalidate new TLB (if valid) */
4098 if (tlb->prot & PAGE_VALID) {
4099 end = tlb->EPN + tlb->size;
4100 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4101 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
4102 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
4103 tlb_flush_page(env, page);
4104 }
4105 }
4106 }
4107
4108 void helper_4xx_tlbwe_lo(target_ulong entry, target_ulong val)
4109 {
4110 ppcemb_tlb_t *tlb;
4111
4112 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4113 val);
4114 entry &= PPC4XX_TLB_ENTRY_MASK;
4115 tlb = &env->tlb.tlbe[entry];
4116 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4117 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
4118 tlb->prot = PAGE_READ;
4119 if (val & PPC4XX_TLBLO_EX) {
4120 tlb->prot |= PAGE_EXEC;
4121 }
4122 if (val & PPC4XX_TLBLO_WR) {
4123 tlb->prot |= PAGE_WRITE;
4124 }
4125 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4126 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4127 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4128 tlb->prot & PAGE_READ ? 'r' : '-',
4129 tlb->prot & PAGE_WRITE ? 'w' : '-',
4130 tlb->prot & PAGE_EXEC ? 'x' : '-',
4131 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
4132 }
4133
4134 target_ulong helper_4xx_tlbsx(target_ulong address)
4135 {
4136 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4137 }
4138
4139 /* PowerPC 440 TLB management */
4140 void helper_440_tlbwe(uint32_t word, target_ulong entry, target_ulong value)
4141 {
4142 ppcemb_tlb_t *tlb;
4143 target_ulong EPN, RPN, size;
4144 int do_flush_tlbs;
4145
4146 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4147 __func__, word, (int)entry, value);
4148 do_flush_tlbs = 0;
4149 entry &= 0x3F;
4150 tlb = &env->tlb.tlbe[entry];
4151 switch (word) {
4152 default:
4153 /* Just here to please gcc */
4154 case 0:
4155 EPN = value & 0xFFFFFC00;
4156 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
4157 do_flush_tlbs = 1;
4158 }
4159 tlb->EPN = EPN;
4160 size = booke_tlb_to_page_size((value >> 4) & 0xF);
4161 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
4162 do_flush_tlbs = 1;
4163 }
4164 tlb->size = size;
4165 tlb->attr &= ~0x1;
4166 tlb->attr |= (value >> 8) & 1;
4167 if (value & 0x200) {
4168 tlb->prot |= PAGE_VALID;
4169 } else {
4170 if (tlb->prot & PAGE_VALID) {
4171 tlb->prot &= ~PAGE_VALID;
4172 do_flush_tlbs = 1;
4173 }
4174 }
4175 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4176 if (do_flush_tlbs) {
4177 tlb_flush(env, 1);
4178 }
4179 break;
4180 case 1:
4181 RPN = value & 0xFFFFFC0F;
4182 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
4183 tlb_flush(env, 1);
4184 }
4185 tlb->RPN = RPN;
4186 break;
4187 case 2:
4188 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
4189 tlb->prot = tlb->prot & PAGE_VALID;
4190 if (value & 0x1) {
4191 tlb->prot |= PAGE_READ << 4;
4192 }
4193 if (value & 0x2) {
4194 tlb->prot |= PAGE_WRITE << 4;
4195 }
4196 if (value & 0x4) {
4197 tlb->prot |= PAGE_EXEC << 4;
4198 }
4199 if (value & 0x8) {
4200 tlb->prot |= PAGE_READ;
4201 }
4202 if (value & 0x10) {
4203 tlb->prot |= PAGE_WRITE;
4204 }
4205 if (value & 0x20) {
4206 tlb->prot |= PAGE_EXEC;
4207 }
4208 break;
4209 }
4210 }
4211
4212 target_ulong helper_440_tlbre(uint32_t word, target_ulong entry)
4213 {
4214 ppcemb_tlb_t *tlb;
4215 target_ulong ret;
4216 int size;
4217
4218 entry &= 0x3F;
4219 tlb = &env->tlb.tlbe[entry];
4220 switch (word) {
4221 default:
4222 /* Just here to please gcc */
4223 case 0:
4224 ret = tlb->EPN;
4225 size = booke_page_size_to_tlb(tlb->size);
4226 if (size < 0 || size > 0xF) {
4227 size = 1;
4228 }
4229 ret |= size << 4;
4230 if (tlb->attr & 0x1) {
4231 ret |= 0x100;
4232 }
4233 if (tlb->prot & PAGE_VALID) {
4234 ret |= 0x200;
4235 }
4236 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4237 env->spr[SPR_440_MMUCR] |= tlb->PID;
4238 break;
4239 case 1:
4240 ret = tlb->RPN;
4241 break;
4242 case 2:
4243 ret = tlb->attr & ~0x1;
4244 if (tlb->prot & (PAGE_READ << 4)) {
4245 ret |= 0x1;
4246 }
4247 if (tlb->prot & (PAGE_WRITE << 4)) {
4248 ret |= 0x2;
4249 }
4250 if (tlb->prot & (PAGE_EXEC << 4)) {
4251 ret |= 0x4;
4252 }
4253 if (tlb->prot & PAGE_READ) {
4254 ret |= 0x8;
4255 }
4256 if (tlb->prot & PAGE_WRITE) {
4257 ret |= 0x10;
4258 }
4259 if (tlb->prot & PAGE_EXEC) {
4260 ret |= 0x20;
4261 }
4262 break;
4263 }
4264 return ret;
4265 }
4266
4267 target_ulong helper_440_tlbsx(target_ulong address)
4268 {
4269 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4270 }
4271
4272 /* PowerPC BookE 2.06 TLB management */
4273
4274 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
4275 {
4276 uint32_t tlbncfg = 0;
4277 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
4278 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
4279 int tlb;
4280
4281 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4282 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
4283
4284 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
4285 cpu_abort(env, "we don't support HES yet\n");
4286 }
4287
4288 return booke206_get_tlbm(env, tlb, ea, esel);
4289 }
4290
4291 void helper_booke_setpid(uint32_t pidn, target_ulong pid)
4292 {
4293 env->spr[pidn] = pid;
4294 /* changing PIDs mean we're in a different address space now */
4295 tlb_flush(env, 1);
4296 }
4297
4298 void helper_booke206_tlbwe(void)
4299 {
4300 uint32_t tlbncfg, tlbn;
4301 ppcmas_tlb_t *tlb;
4302 uint32_t size_tlb, size_ps;
4303
4304 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
4305 case MAS0_WQ_ALWAYS:
4306 /* good to go, write that entry */
4307 break;
4308 case MAS0_WQ_COND:
4309 /* XXX check if reserved */
4310 if (0) {
4311 return;
4312 }
4313 break;
4314 case MAS0_WQ_CLR_RSRV:
4315 /* XXX clear entry */
4316 return;
4317 default:
4318 /* no idea what to do */
4319 return;
4320 }
4321
4322 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
4323 !msr_gs) {
4324 /* XXX we don't support direct LRAT setting yet */
4325 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
4326 return;
4327 }
4328
4329 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
4330 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
4331
4332 tlb = booke206_cur_tlb(env);
4333
4334 if (!tlb) {
4335 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
4336 POWERPC_EXCP_INVAL |
4337 POWERPC_EXCP_INVAL_INVAL);
4338 }
4339
4340 /* check that we support the targeted size */
4341 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
4342 size_ps = booke206_tlbnps(env, tlbn);
4343 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
4344 !(size_ps & (1 << size_tlb))) {
4345 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
4346 POWERPC_EXCP_INVAL |
4347 POWERPC_EXCP_INVAL_INVAL);
4348 }
4349
4350 if (msr_gs) {
4351 cpu_abort(env, "missing HV implementation\n");
4352 }
4353 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
4354 env->spr[SPR_BOOKE_MAS3];
4355 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
4356
4357 /* MAV 1.0 only */
4358 if (!(tlbncfg & TLBnCFG_AVAIL)) {
4359 /* force !AVAIL TLB entries to correct page size */
4360 tlb->mas1 &= ~MAS1_TSIZE_MASK;
4361 /* XXX can be configured in MMUCSR0 */
4362 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
4363 }
4364
4365 /* XXX needs to change when supporting 64-bit e500 */
4366 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
4367
4368 if (!(tlbncfg & TLBnCFG_IPROT)) {
4369 /* no IPROT supported by TLB */
4370 tlb->mas1 &= ~MAS1_IPROT;
4371 }
4372
4373 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
4374 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
4375 } else {
4376 tlb_flush(env, 1);
4377 }
4378 }
4379
4380 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
4381 {
4382 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
4383 int way = booke206_tlbm_to_way(env, tlb);
4384
4385 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
4386 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
4387 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4388
4389 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
4390 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
4391 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
4392 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
4393 }
4394
4395 void helper_booke206_tlbre(void)
4396 {
4397 ppcmas_tlb_t *tlb = NULL;
4398
4399 tlb = booke206_cur_tlb(env);
4400 if (!tlb) {
4401 env->spr[SPR_BOOKE_MAS1] = 0;
4402 } else {
4403 booke206_tlb_to_mas(env, tlb);
4404 }
4405 }
4406
4407 void helper_booke206_tlbsx(target_ulong address)
4408 {
4409 ppcmas_tlb_t *tlb = NULL;
4410 int i, j;
4411 target_phys_addr_t raddr;
4412 uint32_t spid, sas;
4413
4414 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
4415 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
4416
4417 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4418 int ways = booke206_tlb_ways(env, i);
4419
4420 for (j = 0; j < ways; j++) {
4421 tlb = booke206_get_tlbm(env, i, address, j);
4422
4423 if (!tlb) {
4424 continue;
4425 }
4426
4427 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
4428 continue;
4429 }
4430
4431 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
4432 continue;
4433 }
4434
4435 booke206_tlb_to_mas(env, tlb);
4436 return;
4437 }
4438 }
4439
4440 /* no entry found, fill with defaults */
4441 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
4442 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
4443 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
4444 env->spr[SPR_BOOKE_MAS3] = 0;
4445 env->spr[SPR_BOOKE_MAS7] = 0;
4446
4447 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
4448 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
4449 }
4450
4451 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
4452 << MAS1_TID_SHIFT;
4453
4454 /* next victim logic */
4455 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
4456 env->last_way++;
4457 env->last_way &= booke206_tlb_ways(env, 0) - 1;
4458 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
4459 }
4460
4461 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
4462 uint32_t ea)
4463 {
4464 int i;
4465 int ways = booke206_tlb_ways(env, tlbn);
4466 target_ulong mask;
4467
4468 for (i = 0; i < ways; i++) {
4469 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
4470 if (!tlb) {
4471 continue;
4472 }
4473 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
4474 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
4475 !(tlb->mas1 & MAS1_IPROT)) {
4476 tlb->mas1 &= ~MAS1_VALID;
4477 }
4478 }
4479 }
4480
4481 void helper_booke206_tlbivax(target_ulong address)
4482 {
4483 if (address & 0x4) {
4484 /* flush all entries */
4485 if (address & 0x8) {
4486 /* flush all of TLB1 */
4487 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
4488 } else {
4489 /* flush all of TLB0 */
4490 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
4491 }
4492 return;
4493 }
4494
4495 if (address & 0x8) {
4496 /* flush TLB1 entries */
4497 booke206_invalidate_ea_tlb(env, 1, address);
4498 tlb_flush(env, 1);
4499 } else {
4500 /* flush TLB0 entries */
4501 booke206_invalidate_ea_tlb(env, 0, address);
4502 tlb_flush_page(env, address & MAS2_EPN_MASK);
4503 }
4504 }
4505
4506 void helper_booke206_tlbilx0(target_ulong address)
4507 {
4508 /* XXX missing LPID handling */
4509 booke206_flush_tlb(env, -1, 1);
4510 }
4511
4512 void helper_booke206_tlbilx1(target_ulong address)
4513 {
4514 int i, j;
4515 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4516 ppcmas_tlb_t *tlb = env->tlb.tlbm;
4517 int tlb_size;
4518
4519 /* XXX missing LPID handling */
4520 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4521 tlb_size = booke206_tlb_size(env, i);
4522 for (j = 0; j < tlb_size; j++) {
4523 if (!(tlb[j].mas1 & MAS1_IPROT) &&
4524 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
4525 tlb[j].mas1 &= ~MAS1_VALID;
4526 }
4527 }
4528 tlb += booke206_tlb_size(env, i);
4529 }
4530 tlb_flush(env, 1);
4531 }
4532
4533 void helper_booke206_tlbilx3(target_ulong address)
4534 {
4535 int i, j;
4536 ppcmas_tlb_t *tlb;
4537 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
4538 int pid = tid >> MAS6_SPID_SHIFT;
4539 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
4540 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
4541 /* XXX check for unsupported isize and raise an invalid opcode then */
4542 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
4543 /* XXX implement MAV2 handling */
4544 bool mav2 = false;
4545
4546 /* XXX missing LPID handling */
4547 /* flush by pid and ea */
4548 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
4549 int ways = booke206_tlb_ways(env, i);
4550
4551 for (j = 0; j < ways; j++) {
4552 tlb = booke206_get_tlbm(env, i, address, j);
4553 if (!tlb) {
4554 continue;
4555 }
4556 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
4557 (tlb->mas1 & MAS1_IPROT) ||
4558 ((tlb->mas1 & MAS1_IND) != ind) ||
4559 ((tlb->mas8 & MAS8_TGS) != sgs)) {
4560 continue;
4561 }
4562 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
4563 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
4564 continue;
4565 }
4566 /* XXX e500mc doesn't match SAS, but other cores might */
4567 tlb->mas1 &= ~MAS1_VALID;
4568 }
4569 }
4570 tlb_flush(env, 1);
4571 }
4572
4573 void helper_booke206_tlbflush(uint32_t type)
4574 {
4575 int flags = 0;
4576
4577 if (type & 2) {
4578 flags |= BOOKE206_FLUSH_TLB1;
4579 }
4580
4581 if (type & 4) {
4582 flags |= BOOKE206_FLUSH_TLB0;
4583 }
4584
4585 booke206_flush_tlb(env, flags, 1);
4586 }
4587 #endif /* !CONFIG_USER_ONLY */