]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/fpu_helper.c
target-ppc: VSX Stage 4: Add xsdivsp
[mirror_qemu.git] / target-ppc / fpu_helper.c
CommitLineData
bd23cd45
BS
1/*
2 * PowerPC floating point and SPE 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 "cpu.h"
bd23cd45
BS
20#include "helper.h"
21
22/*****************************************************************************/
23/* Floating point operations helpers */
8e703949 24uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg)
bd23cd45
BS
25{
26 CPU_FloatU f;
27 CPU_DoubleU d;
28
29 f.l = arg;
30 d.d = float32_to_float64(f.f, &env->fp_status);
31 return d.ll;
32}
33
8e703949 34uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
35{
36 CPU_FloatU f;
37 CPU_DoubleU d;
38
39 d.ll = arg;
40 f.f = float64_to_float32(d.d, &env->fp_status);
41 return f.l;
42}
43
44static inline int isden(float64 d)
45{
46 CPU_DoubleU u;
47
48 u.d = d;
49
50 return ((u.ll >> 52) & 0x7FF) == 0;
51}
52
8e703949 53uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf)
bd23cd45
BS
54{
55 CPU_DoubleU farg;
56 int isneg;
57 int ret;
58
59 farg.ll = arg;
60 isneg = float64_is_neg(farg.d);
61 if (unlikely(float64_is_any_nan(farg.d))) {
62 if (float64_is_signaling_nan(farg.d)) {
63 /* Signaling NaN: flags are undefined */
64 ret = 0x00;
65 } else {
66 /* Quiet NaN */
67 ret = 0x11;
68 }
69 } else if (unlikely(float64_is_infinity(farg.d))) {
70 /* +/- infinity */
71 if (isneg) {
72 ret = 0x09;
73 } else {
74 ret = 0x05;
75 }
76 } else {
77 if (float64_is_zero(farg.d)) {
78 /* +/- zero */
79 if (isneg) {
80 ret = 0x12;
81 } else {
82 ret = 0x02;
83 }
84 } else {
85 if (isden(farg.d)) {
86 /* Denormalized numbers */
87 ret = 0x10;
88 } else {
89 /* Normalized numbers */
90 ret = 0x00;
91 }
92 if (isneg) {
93 ret |= 0x08;
94 } else {
95 ret |= 0x04;
96 }
97 }
98 }
99 if (set_fprf) {
100 /* We update FPSCR_FPRF */
101 env->fpscr &= ~(0x1F << FPSCR_FPRF);
102 env->fpscr |= ret << FPSCR_FPRF;
103 }
104 /* We just need fpcc to update Rc1 */
105 return ret & 0xF;
106}
107
108/* Floating-point invalid operations exception */
59800ec8
TM
109static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
110 int set_fpcc)
bd23cd45
BS
111{
112 uint64_t ret = 0;
113 int ve;
114
115 ve = fpscr_ve;
116 switch (op) {
117 case POWERPC_EXCP_FP_VXSNAN:
118 env->fpscr |= 1 << FPSCR_VXSNAN;
119 break;
120 case POWERPC_EXCP_FP_VXSOFT:
121 env->fpscr |= 1 << FPSCR_VXSOFT;
122 break;
123 case POWERPC_EXCP_FP_VXISI:
124 /* Magnitude subtraction of infinities */
125 env->fpscr |= 1 << FPSCR_VXISI;
126 goto update_arith;
127 case POWERPC_EXCP_FP_VXIDI:
128 /* Division of infinity by infinity */
129 env->fpscr |= 1 << FPSCR_VXIDI;
130 goto update_arith;
131 case POWERPC_EXCP_FP_VXZDZ:
132 /* Division of zero by zero */
133 env->fpscr |= 1 << FPSCR_VXZDZ;
134 goto update_arith;
135 case POWERPC_EXCP_FP_VXIMZ:
136 /* Multiplication of zero by infinity */
137 env->fpscr |= 1 << FPSCR_VXIMZ;
138 goto update_arith;
139 case POWERPC_EXCP_FP_VXVC:
140 /* Ordered comparison of NaN */
141 env->fpscr |= 1 << FPSCR_VXVC;
59800ec8
TM
142 if (set_fpcc) {
143 env->fpscr &= ~(0xF << FPSCR_FPCC);
144 env->fpscr |= 0x11 << FPSCR_FPCC;
145 }
bd23cd45
BS
146 /* We must update the target FPR before raising the exception */
147 if (ve != 0) {
148 env->exception_index = POWERPC_EXCP_PROGRAM;
149 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
150 /* Update the floating-point enabled exception summary */
151 env->fpscr |= 1 << FPSCR_FEX;
152 /* Exception is differed */
153 ve = 0;
154 }
155 break;
156 case POWERPC_EXCP_FP_VXSQRT:
157 /* Square root of a negative number */
158 env->fpscr |= 1 << FPSCR_VXSQRT;
159 update_arith:
160 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
161 if (ve == 0) {
162 /* Set the result to quiet NaN */
163 ret = 0x7FF8000000000000ULL;
59800ec8
TM
164 if (set_fpcc) {
165 env->fpscr &= ~(0xF << FPSCR_FPCC);
166 env->fpscr |= 0x11 << FPSCR_FPCC;
167 }
bd23cd45
BS
168 }
169 break;
170 case POWERPC_EXCP_FP_VXCVI:
171 /* Invalid conversion */
172 env->fpscr |= 1 << FPSCR_VXCVI;
173 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
174 if (ve == 0) {
175 /* Set the result to quiet NaN */
176 ret = 0x7FF8000000000000ULL;
59800ec8
TM
177 if (set_fpcc) {
178 env->fpscr &= ~(0xF << FPSCR_FPCC);
179 env->fpscr |= 0x11 << FPSCR_FPCC;
180 }
bd23cd45
BS
181 }
182 break;
183 }
184 /* Update the floating-point invalid operation summary */
185 env->fpscr |= 1 << FPSCR_VX;
186 /* Update the floating-point exception summary */
187 env->fpscr |= 1 << FPSCR_FX;
188 if (ve != 0) {
189 /* Update the floating-point enabled exception summary */
190 env->fpscr |= 1 << FPSCR_FEX;
191 if (msr_fe0 != 0 || msr_fe1 != 0) {
192 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
193 POWERPC_EXCP_FP | op);
194 }
195 }
196 return ret;
197}
198
8e703949 199static inline void float_zero_divide_excp(CPUPPCState *env)
bd23cd45
BS
200{
201 env->fpscr |= 1 << FPSCR_ZX;
202 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
203 /* Update the floating-point exception summary */
204 env->fpscr |= 1 << FPSCR_FX;
205 if (fpscr_ze != 0) {
206 /* Update the floating-point enabled exception summary */
207 env->fpscr |= 1 << FPSCR_FEX;
208 if (msr_fe0 != 0 || msr_fe1 != 0) {
209 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
210 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
211 }
212 }
213}
214
8e703949 215static inline void float_overflow_excp(CPUPPCState *env)
bd23cd45
BS
216{
217 env->fpscr |= 1 << FPSCR_OX;
218 /* Update the floating-point exception summary */
219 env->fpscr |= 1 << FPSCR_FX;
220 if (fpscr_oe != 0) {
221 /* XXX: should adjust the result */
222 /* Update the floating-point enabled exception summary */
223 env->fpscr |= 1 << FPSCR_FEX;
224 /* We must update the target FPR before raising the exception */
225 env->exception_index = POWERPC_EXCP_PROGRAM;
226 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
227 } else {
228 env->fpscr |= 1 << FPSCR_XX;
229 env->fpscr |= 1 << FPSCR_FI;
230 }
231}
232
8e703949 233static inline void float_underflow_excp(CPUPPCState *env)
bd23cd45
BS
234{
235 env->fpscr |= 1 << FPSCR_UX;
236 /* Update the floating-point exception summary */
237 env->fpscr |= 1 << FPSCR_FX;
238 if (fpscr_ue != 0) {
239 /* XXX: should adjust the result */
240 /* Update the floating-point enabled exception summary */
241 env->fpscr |= 1 << FPSCR_FEX;
242 /* We must update the target FPR before raising the exception */
243 env->exception_index = POWERPC_EXCP_PROGRAM;
244 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
245 }
246}
247
8e703949 248static inline void float_inexact_excp(CPUPPCState *env)
bd23cd45
BS
249{
250 env->fpscr |= 1 << FPSCR_XX;
251 /* Update the floating-point exception summary */
252 env->fpscr |= 1 << FPSCR_FX;
253 if (fpscr_xe != 0) {
254 /* Update the floating-point enabled exception summary */
255 env->fpscr |= 1 << FPSCR_FEX;
256 /* We must update the target FPR before raising the exception */
257 env->exception_index = POWERPC_EXCP_PROGRAM;
258 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
259 }
260}
261
8e703949 262static inline void fpscr_set_rounding_mode(CPUPPCState *env)
bd23cd45
BS
263{
264 int rnd_type;
265
266 /* Set rounding mode */
267 switch (fpscr_rn) {
268 case 0:
269 /* Best approximation (round to nearest) */
270 rnd_type = float_round_nearest_even;
271 break;
272 case 1:
273 /* Smaller magnitude (round toward zero) */
274 rnd_type = float_round_to_zero;
275 break;
276 case 2:
277 /* Round toward +infinite */
278 rnd_type = float_round_up;
279 break;
280 default:
281 case 3:
282 /* Round toward -infinite */
283 rnd_type = float_round_down;
284 break;
285 }
286 set_float_rounding_mode(rnd_type, &env->fp_status);
287}
288
8e703949 289void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
bd23cd45
BS
290{
291 int prev;
292
293 prev = (env->fpscr >> bit) & 1;
294 env->fpscr &= ~(1 << bit);
295 if (prev == 1) {
296 switch (bit) {
297 case FPSCR_RN1:
298 case FPSCR_RN:
8e703949 299 fpscr_set_rounding_mode(env);
bd23cd45
BS
300 break;
301 default:
302 break;
303 }
304 }
305}
306
8e703949 307void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
bd23cd45
BS
308{
309 int prev;
310
311 prev = (env->fpscr >> bit) & 1;
312 env->fpscr |= 1 << bit;
313 if (prev == 0) {
314 switch (bit) {
315 case FPSCR_VX:
316 env->fpscr |= 1 << FPSCR_FX;
317 if (fpscr_ve) {
318 goto raise_ve;
319 }
90638255 320 break;
bd23cd45
BS
321 case FPSCR_OX:
322 env->fpscr |= 1 << FPSCR_FX;
323 if (fpscr_oe) {
324 goto raise_oe;
325 }
326 break;
327 case FPSCR_UX:
328 env->fpscr |= 1 << FPSCR_FX;
329 if (fpscr_ue) {
330 goto raise_ue;
331 }
332 break;
333 case FPSCR_ZX:
334 env->fpscr |= 1 << FPSCR_FX;
335 if (fpscr_ze) {
336 goto raise_ze;
337 }
338 break;
339 case FPSCR_XX:
340 env->fpscr |= 1 << FPSCR_FX;
341 if (fpscr_xe) {
342 goto raise_xe;
343 }
344 break;
345 case FPSCR_VXSNAN:
346 case FPSCR_VXISI:
347 case FPSCR_VXIDI:
348 case FPSCR_VXZDZ:
349 case FPSCR_VXIMZ:
350 case FPSCR_VXVC:
351 case FPSCR_VXSOFT:
352 case FPSCR_VXSQRT:
353 case FPSCR_VXCVI:
354 env->fpscr |= 1 << FPSCR_VX;
355 env->fpscr |= 1 << FPSCR_FX;
356 if (fpscr_ve != 0) {
357 goto raise_ve;
358 }
359 break;
360 case FPSCR_VE:
361 if (fpscr_vx != 0) {
362 raise_ve:
363 env->error_code = POWERPC_EXCP_FP;
364 if (fpscr_vxsnan) {
365 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
366 }
367 if (fpscr_vxisi) {
368 env->error_code |= POWERPC_EXCP_FP_VXISI;
369 }
370 if (fpscr_vxidi) {
371 env->error_code |= POWERPC_EXCP_FP_VXIDI;
372 }
373 if (fpscr_vxzdz) {
374 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
375 }
376 if (fpscr_vximz) {
377 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
378 }
379 if (fpscr_vxvc) {
380 env->error_code |= POWERPC_EXCP_FP_VXVC;
381 }
382 if (fpscr_vxsoft) {
383 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
384 }
385 if (fpscr_vxsqrt) {
386 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
387 }
388 if (fpscr_vxcvi) {
389 env->error_code |= POWERPC_EXCP_FP_VXCVI;
390 }
391 goto raise_excp;
392 }
393 break;
394 case FPSCR_OE:
395 if (fpscr_ox != 0) {
396 raise_oe:
397 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
398 goto raise_excp;
399 }
400 break;
401 case FPSCR_UE:
402 if (fpscr_ux != 0) {
403 raise_ue:
404 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
405 goto raise_excp;
406 }
407 break;
408 case FPSCR_ZE:
409 if (fpscr_zx != 0) {
410 raise_ze:
411 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
412 goto raise_excp;
413 }
414 break;
415 case FPSCR_XE:
416 if (fpscr_xx != 0) {
417 raise_xe:
418 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
419 goto raise_excp;
420 }
421 break;
422 case FPSCR_RN1:
423 case FPSCR_RN:
8e703949 424 fpscr_set_rounding_mode(env);
bd23cd45
BS
425 break;
426 default:
427 break;
428 raise_excp:
429 /* Update the floating-point enabled exception summary */
430 env->fpscr |= 1 << FPSCR_FEX;
431 /* We have to update Rc1 before raising the exception */
432 env->exception_index = POWERPC_EXCP_PROGRAM;
433 break;
434 }
435 }
436}
437
8e703949 438void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
bd23cd45 439{
7d08d856 440 target_ulong prev, new;
bd23cd45
BS
441 int i;
442
443 prev = env->fpscr;
7d08d856
AJ
444 new = (target_ulong)arg;
445 new &= ~0x60000000LL;
446 new |= prev & 0x60000000LL;
447 for (i = 0; i < sizeof(target_ulong) * 2; i++) {
bd23cd45 448 if (mask & (1 << i)) {
7d08d856
AJ
449 env->fpscr &= ~(0xFLL << (4 * i));
450 env->fpscr |= new & (0xFLL << (4 * i));
bd23cd45
BS
451 }
452 }
453 /* Update VX and FEX */
454 if (fpscr_ix != 0) {
455 env->fpscr |= 1 << FPSCR_VX;
456 } else {
457 env->fpscr &= ~(1 << FPSCR_VX);
458 }
459 if ((fpscr_ex & fpscr_eex) != 0) {
460 env->fpscr |= 1 << FPSCR_FEX;
461 env->exception_index = POWERPC_EXCP_PROGRAM;
462 /* XXX: we should compute it properly */
463 env->error_code = POWERPC_EXCP_FP;
464 } else {
465 env->fpscr &= ~(1 << FPSCR_FEX);
466 }
8e703949 467 fpscr_set_rounding_mode(env);
bd23cd45
BS
468}
469
d6478bc7
FC
470void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
471{
472 helper_store_fpscr(env, arg, mask);
473}
474
8e703949 475void helper_float_check_status(CPUPPCState *env)
bd23cd45 476{
db72c9f2
TG
477 int status = get_float_exception_flags(&env->fp_status);
478
479 if (status & float_flag_divbyzero) {
480 float_zero_divide_excp(env);
481 } else if (status & float_flag_overflow) {
482 float_overflow_excp(env);
483 } else if (status & float_flag_underflow) {
484 float_underflow_excp(env);
485 } else if (status & float_flag_inexact) {
486 float_inexact_excp(env);
487 }
488
bd23cd45
BS
489 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
490 (env->error_code & POWERPC_EXCP_FP)) {
491 /* Differred floating-point exception after target FPR update */
492 if (msr_fe0 != 0 || msr_fe1 != 0) {
493 helper_raise_exception_err(env, env->exception_index,
494 env->error_code);
495 }
bd23cd45
BS
496 }
497}
498
8e703949 499void helper_reset_fpstatus(CPUPPCState *env)
bd23cd45
BS
500{
501 set_float_exception_flags(0, &env->fp_status);
502}
503
504/* fadd - fadd. */
8e703949 505uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
bd23cd45
BS
506{
507 CPU_DoubleU farg1, farg2;
508
509 farg1.ll = arg1;
510 farg2.ll = arg2;
511
512 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
513 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
514 /* Magnitude subtraction of infinities */
59800ec8 515 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
bd23cd45
BS
516 } else {
517 if (unlikely(float64_is_signaling_nan(farg1.d) ||
518 float64_is_signaling_nan(farg2.d))) {
519 /* sNaN addition */
59800ec8 520 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
521 }
522 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
523 }
524
525 return farg1.ll;
526}
527
528/* fsub - fsub. */
8e703949 529uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
bd23cd45
BS
530{
531 CPU_DoubleU farg1, farg2;
532
533 farg1.ll = arg1;
534 farg2.ll = arg2;
535
536 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
537 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
538 /* Magnitude subtraction of infinities */
59800ec8 539 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
bd23cd45
BS
540 } else {
541 if (unlikely(float64_is_signaling_nan(farg1.d) ||
542 float64_is_signaling_nan(farg2.d))) {
543 /* sNaN subtraction */
59800ec8 544 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
545 }
546 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
547 }
548
549 return farg1.ll;
550}
551
552/* fmul - fmul. */
8e703949 553uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
bd23cd45
BS
554{
555 CPU_DoubleU farg1, farg2;
556
557 farg1.ll = arg1;
558 farg2.ll = arg2;
559
560 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
561 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
562 /* Multiplication of zero by infinity */
59800ec8 563 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
bd23cd45
BS
564 } else {
565 if (unlikely(float64_is_signaling_nan(farg1.d) ||
566 float64_is_signaling_nan(farg2.d))) {
567 /* sNaN multiplication */
59800ec8 568 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
569 }
570 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
571 }
572
573 return farg1.ll;
574}
575
576/* fdiv - fdiv. */
8e703949 577uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
bd23cd45
BS
578{
579 CPU_DoubleU farg1, farg2;
580
581 farg1.ll = arg1;
582 farg2.ll = arg2;
583
584 if (unlikely(float64_is_infinity(farg1.d) &&
585 float64_is_infinity(farg2.d))) {
586 /* Division of infinity by infinity */
59800ec8 587 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
bd23cd45
BS
588 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
589 /* Division of zero by zero */
59800ec8 590 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
bd23cd45
BS
591 } else {
592 if (unlikely(float64_is_signaling_nan(farg1.d) ||
593 float64_is_signaling_nan(farg2.d))) {
594 /* sNaN division */
59800ec8 595 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
596 }
597 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
598 }
599
600 return farg1.ll;
601}
602
bd23cd45 603/* fctiw - fctiw. */
8e703949 604uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
605{
606 CPU_DoubleU farg;
607
608 farg.ll = arg;
609
610 if (unlikely(float64_is_signaling_nan(farg.d))) {
611 /* sNaN conversion */
8e703949 612 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
59800ec8 613 POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
614 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
615 float64_is_infinity(farg.d))) {
616 /* qNan / infinity conversion */
59800ec8 617 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
618 } else {
619 farg.ll = float64_to_int32(farg.d, &env->fp_status);
620 /* XXX: higher bits are not supposed to be significant.
621 * to make tests easier, return the same as a real PowerPC 750
622 */
623 farg.ll |= 0xFFF80000ULL << 32;
624 }
625 return farg.ll;
626}
627
628/* fctiwz - fctiwz. */
8e703949 629uint64_t helper_fctiwz(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
630{
631 CPU_DoubleU farg;
632
633 farg.ll = arg;
634
635 if (unlikely(float64_is_signaling_nan(farg.d))) {
636 /* sNaN conversion */
8e703949 637 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
59800ec8 638 POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
639 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
640 float64_is_infinity(farg.d))) {
641 /* qNan / infinity conversion */
59800ec8 642 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
643 } else {
644 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
645 /* XXX: higher bits are not supposed to be significant.
646 * to make tests easier, return the same as a real PowerPC 750
647 */
648 farg.ll |= 0xFFF80000ULL << 32;
649 }
650 return farg.ll;
651}
652
653#if defined(TARGET_PPC64)
654/* fcfid - fcfid. */
8e703949 655uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
656{
657 CPU_DoubleU farg;
658
659 farg.d = int64_to_float64(arg, &env->fp_status);
660 return farg.ll;
661}
662
663/* fctid - fctid. */
8e703949 664uint64_t helper_fctid(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
665{
666 CPU_DoubleU farg;
667
668 farg.ll = arg;
669
670 if (unlikely(float64_is_signaling_nan(farg.d))) {
671 /* sNaN conversion */
8e703949 672 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
59800ec8 673 POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
674 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
675 float64_is_infinity(farg.d))) {
676 /* qNan / infinity conversion */
59800ec8 677 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
678 } else {
679 farg.ll = float64_to_int64(farg.d, &env->fp_status);
680 }
681 return farg.ll;
682}
683
684/* fctidz - fctidz. */
8e703949 685uint64_t helper_fctidz(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
686{
687 CPU_DoubleU farg;
688
689 farg.ll = arg;
690
691 if (unlikely(float64_is_signaling_nan(farg.d))) {
692 /* sNaN conversion */
8e703949 693 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
59800ec8 694 POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
695 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
696 float64_is_infinity(farg.d))) {
697 /* qNan / infinity conversion */
59800ec8 698 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
699 } else {
700 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
701 }
702 return farg.ll;
703}
704
705#endif
706
8e703949
BS
707static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
708 int rounding_mode)
bd23cd45
BS
709{
710 CPU_DoubleU farg;
711
712 farg.ll = arg;
713
714 if (unlikely(float64_is_signaling_nan(farg.d))) {
715 /* sNaN round */
8e703949 716 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
59800ec8 717 POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
718 } else if (unlikely(float64_is_quiet_nan(farg.d) ||
719 float64_is_infinity(farg.d))) {
720 /* qNan / infinity round */
59800ec8 721 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);
bd23cd45
BS
722 } else {
723 set_float_rounding_mode(rounding_mode, &env->fp_status);
724 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
725 /* Restore rounding mode from FPSCR */
8e703949 726 fpscr_set_rounding_mode(env);
bd23cd45
BS
727 }
728 return farg.ll;
729}
730
8e703949 731uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
bd23cd45 732{
8e703949 733 return do_fri(env, arg, float_round_nearest_even);
bd23cd45
BS
734}
735
8e703949 736uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
bd23cd45 737{
8e703949 738 return do_fri(env, arg, float_round_to_zero);
bd23cd45
BS
739}
740
8e703949 741uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
bd23cd45 742{
8e703949 743 return do_fri(env, arg, float_round_up);
bd23cd45
BS
744}
745
8e703949 746uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
bd23cd45 747{
8e703949 748 return do_fri(env, arg, float_round_down);
bd23cd45
BS
749}
750
751/* fmadd - fmadd. */
8e703949
BS
752uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
753 uint64_t arg3)
bd23cd45
BS
754{
755 CPU_DoubleU farg1, farg2, farg3;
756
757 farg1.ll = arg1;
758 farg2.ll = arg2;
759 farg3.ll = arg3;
760
761 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
762 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
763 /* Multiplication of zero by infinity */
59800ec8 764 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
bd23cd45
BS
765 } else {
766 if (unlikely(float64_is_signaling_nan(farg1.d) ||
767 float64_is_signaling_nan(farg2.d) ||
768 float64_is_signaling_nan(farg3.d))) {
769 /* sNaN operation */
59800ec8 770 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
771 }
772 /* This is the way the PowerPC specification defines it */
773 float128 ft0_128, ft1_128;
774
775 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
776 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
777 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
778 if (unlikely(float128_is_infinity(ft0_128) &&
779 float64_is_infinity(farg3.d) &&
780 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
781 /* Magnitude subtraction of infinities */
59800ec8 782 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
bd23cd45
BS
783 } else {
784 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
785 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
786 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
787 }
788 }
789
790 return farg1.ll;
791}
792
793/* fmsub - fmsub. */
8e703949
BS
794uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
795 uint64_t arg3)
bd23cd45
BS
796{
797 CPU_DoubleU farg1, farg2, farg3;
798
799 farg1.ll = arg1;
800 farg2.ll = arg2;
801 farg3.ll = arg3;
802
803 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
804 (float64_is_zero(farg1.d) &&
805 float64_is_infinity(farg2.d)))) {
806 /* Multiplication of zero by infinity */
59800ec8 807 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
bd23cd45
BS
808 } else {
809 if (unlikely(float64_is_signaling_nan(farg1.d) ||
810 float64_is_signaling_nan(farg2.d) ||
811 float64_is_signaling_nan(farg3.d))) {
812 /* sNaN operation */
59800ec8 813 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
814 }
815 /* This is the way the PowerPC specification defines it */
816 float128 ft0_128, ft1_128;
817
818 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
819 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
820 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
821 if (unlikely(float128_is_infinity(ft0_128) &&
822 float64_is_infinity(farg3.d) &&
823 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
824 /* Magnitude subtraction of infinities */
59800ec8 825 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
bd23cd45
BS
826 } else {
827 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
828 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
829 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
830 }
831 }
832 return farg1.ll;
833}
834
835/* fnmadd - fnmadd. */
8e703949
BS
836uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
837 uint64_t arg3)
bd23cd45
BS
838{
839 CPU_DoubleU farg1, farg2, farg3;
840
841 farg1.ll = arg1;
842 farg2.ll = arg2;
843 farg3.ll = arg3;
844
845 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
846 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
847 /* Multiplication of zero by infinity */
59800ec8 848 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
bd23cd45
BS
849 } else {
850 if (unlikely(float64_is_signaling_nan(farg1.d) ||
851 float64_is_signaling_nan(farg2.d) ||
852 float64_is_signaling_nan(farg3.d))) {
853 /* sNaN operation */
59800ec8 854 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
855 }
856 /* This is the way the PowerPC specification defines it */
857 float128 ft0_128, ft1_128;
858
859 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
860 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
861 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
862 if (unlikely(float128_is_infinity(ft0_128) &&
863 float64_is_infinity(farg3.d) &&
864 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
865 /* Magnitude subtraction of infinities */
59800ec8 866 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
bd23cd45
BS
867 } else {
868 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
869 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
870 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
871 }
872 if (likely(!float64_is_any_nan(farg1.d))) {
873 farg1.d = float64_chs(farg1.d);
874 }
875 }
876 return farg1.ll;
877}
878
879/* fnmsub - fnmsub. */
8e703949
BS
880uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
881 uint64_t arg3)
bd23cd45
BS
882{
883 CPU_DoubleU farg1, farg2, farg3;
884
885 farg1.ll = arg1;
886 farg2.ll = arg2;
887 farg3.ll = arg3;
888
889 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
890 (float64_is_zero(farg1.d) &&
891 float64_is_infinity(farg2.d)))) {
892 /* Multiplication of zero by infinity */
59800ec8 893 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
bd23cd45
BS
894 } else {
895 if (unlikely(float64_is_signaling_nan(farg1.d) ||
896 float64_is_signaling_nan(farg2.d) ||
897 float64_is_signaling_nan(farg3.d))) {
898 /* sNaN operation */
59800ec8 899 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
900 }
901 /* This is the way the PowerPC specification defines it */
902 float128 ft0_128, ft1_128;
903
904 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
905 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
906 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
907 if (unlikely(float128_is_infinity(ft0_128) &&
908 float64_is_infinity(farg3.d) &&
909 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
910 /* Magnitude subtraction of infinities */
59800ec8 911 farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
bd23cd45
BS
912 } else {
913 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
914 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
915 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
916 }
917 if (likely(!float64_is_any_nan(farg1.d))) {
918 farg1.d = float64_chs(farg1.d);
919 }
920 }
921 return farg1.ll;
922}
923
924/* frsp - frsp. */
8e703949 925uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
926{
927 CPU_DoubleU farg;
928 float32 f32;
929
930 farg.ll = arg;
931
932 if (unlikely(float64_is_signaling_nan(farg.d))) {
933 /* sNaN square root */
59800ec8 934 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
935 }
936 f32 = float64_to_float32(farg.d, &env->fp_status);
937 farg.d = float32_to_float64(f32, &env->fp_status);
938
939 return farg.ll;
940}
941
942/* fsqrt - fsqrt. */
8e703949 943uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
944{
945 CPU_DoubleU farg;
946
947 farg.ll = arg;
948
949 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
950 /* Square root of a negative nonzero number */
59800ec8 951 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
bd23cd45
BS
952 } else {
953 if (unlikely(float64_is_signaling_nan(farg.d))) {
954 /* sNaN square root */
59800ec8 955 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
956 }
957 farg.d = float64_sqrt(farg.d, &env->fp_status);
958 }
959 return farg.ll;
960}
961
962/* fre - fre. */
8e703949 963uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
964{
965 CPU_DoubleU farg;
966
967 farg.ll = arg;
968
969 if (unlikely(float64_is_signaling_nan(farg.d))) {
970 /* sNaN reciprocal */
59800ec8 971 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
972 }
973 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
974 return farg.d;
975}
976
977/* fres - fres. */
8e703949 978uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
979{
980 CPU_DoubleU farg;
981 float32 f32;
982
983 farg.ll = arg;
984
985 if (unlikely(float64_is_signaling_nan(farg.d))) {
986 /* sNaN reciprocal */
59800ec8 987 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
988 }
989 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
990 f32 = float64_to_float32(farg.d, &env->fp_status);
991 farg.d = float32_to_float64(f32, &env->fp_status);
992
993 return farg.ll;
994}
995
996/* frsqrte - frsqrte. */
8e703949 997uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
bd23cd45
BS
998{
999 CPU_DoubleU farg;
1000 float32 f32;
1001
1002 farg.ll = arg;
1003
1004 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
1005 /* Reciprocal square root of a negative nonzero number */
59800ec8 1006 farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
bd23cd45
BS
1007 } else {
1008 if (unlikely(float64_is_signaling_nan(farg.d))) {
1009 /* sNaN reciprocal square root */
59800ec8 1010 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
1011 }
1012 farg.d = float64_sqrt(farg.d, &env->fp_status);
1013 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1014 f32 = float64_to_float32(farg.d, &env->fp_status);
1015 farg.d = float32_to_float64(f32, &env->fp_status);
1016 }
1017 return farg.ll;
1018}
1019
1020/* fsel - fsel. */
8e703949
BS
1021uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
1022 uint64_t arg3)
bd23cd45
BS
1023{
1024 CPU_DoubleU farg1;
1025
1026 farg1.ll = arg1;
1027
1028 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
1029 !float64_is_any_nan(farg1.d)) {
1030 return arg2;
1031 } else {
1032 return arg3;
1033 }
1034}
1035
8e703949
BS
1036void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
1037 uint32_t crfD)
bd23cd45
BS
1038{
1039 CPU_DoubleU farg1, farg2;
1040 uint32_t ret = 0;
1041
1042 farg1.ll = arg1;
1043 farg2.ll = arg2;
1044
1045 if (unlikely(float64_is_any_nan(farg1.d) ||
1046 float64_is_any_nan(farg2.d))) {
1047 ret = 0x01UL;
1048 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1049 ret = 0x08UL;
1050 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1051 ret = 0x04UL;
1052 } else {
1053 ret = 0x02UL;
1054 }
1055
1056 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1057 env->fpscr |= ret << FPSCR_FPRF;
1058 env->crf[crfD] = ret;
1059 if (unlikely(ret == 0x01UL
1060 && (float64_is_signaling_nan(farg1.d) ||
1061 float64_is_signaling_nan(farg2.d)))) {
1062 /* sNaN comparison */
59800ec8 1063 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
bd23cd45
BS
1064 }
1065}
1066
8e703949
BS
1067void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
1068 uint32_t crfD)
bd23cd45
BS
1069{
1070 CPU_DoubleU farg1, farg2;
1071 uint32_t ret = 0;
1072
1073 farg1.ll = arg1;
1074 farg2.ll = arg2;
1075
1076 if (unlikely(float64_is_any_nan(farg1.d) ||
1077 float64_is_any_nan(farg2.d))) {
1078 ret = 0x01UL;
1079 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1080 ret = 0x08UL;
1081 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1082 ret = 0x04UL;
1083 } else {
1084 ret = 0x02UL;
1085 }
1086
1087 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1088 env->fpscr |= ret << FPSCR_FPRF;
1089 env->crf[crfD] = ret;
1090 if (unlikely(ret == 0x01UL)) {
1091 if (float64_is_signaling_nan(farg1.d) ||
1092 float64_is_signaling_nan(farg2.d)) {
1093 /* sNaN comparison */
8e703949 1094 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
59800ec8 1095 POWERPC_EXCP_FP_VXVC, 1);
bd23cd45
BS
1096 } else {
1097 /* qNaN comparison */
59800ec8 1098 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
bd23cd45
BS
1099 }
1100 }
1101}
1102
1103/* Single-precision floating-point conversions */
8e703949 1104static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1105{
1106 CPU_FloatU u;
1107
1108 u.f = int32_to_float32(val, &env->vec_status);
1109
1110 return u.l;
1111}
1112
8e703949 1113static inline uint32_t efscfui(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1114{
1115 CPU_FloatU u;
1116
1117 u.f = uint32_to_float32(val, &env->vec_status);
1118
1119 return u.l;
1120}
1121
8e703949 1122static inline int32_t efsctsi(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1123{
1124 CPU_FloatU u;
1125
1126 u.l = val;
1127 /* NaN are not treated the same way IEEE 754 does */
1128 if (unlikely(float32_is_quiet_nan(u.f))) {
1129 return 0;
1130 }
1131
1132 return float32_to_int32(u.f, &env->vec_status);
1133}
1134
8e703949 1135static inline uint32_t efsctui(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1136{
1137 CPU_FloatU u;
1138
1139 u.l = val;
1140 /* NaN are not treated the same way IEEE 754 does */
1141 if (unlikely(float32_is_quiet_nan(u.f))) {
1142 return 0;
1143 }
1144
1145 return float32_to_uint32(u.f, &env->vec_status);
1146}
1147
8e703949 1148static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1149{
1150 CPU_FloatU u;
1151
1152 u.l = val;
1153 /* NaN are not treated the same way IEEE 754 does */
1154 if (unlikely(float32_is_quiet_nan(u.f))) {
1155 return 0;
1156 }
1157
1158 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
1159}
1160
8e703949 1161static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1162{
1163 CPU_FloatU u;
1164
1165 u.l = val;
1166 /* NaN are not treated the same way IEEE 754 does */
1167 if (unlikely(float32_is_quiet_nan(u.f))) {
1168 return 0;
1169 }
1170
1171 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
1172}
1173
8e703949 1174static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1175{
1176 CPU_FloatU u;
1177 float32 tmp;
1178
1179 u.f = int32_to_float32(val, &env->vec_status);
1180 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
1181 u.f = float32_div(u.f, tmp, &env->vec_status);
1182
1183 return u.l;
1184}
1185
8e703949 1186static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1187{
1188 CPU_FloatU u;
1189 float32 tmp;
1190
1191 u.f = uint32_to_float32(val, &env->vec_status);
1192 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1193 u.f = float32_div(u.f, tmp, &env->vec_status);
1194
1195 return u.l;
1196}
1197
8e703949 1198static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1199{
1200 CPU_FloatU u;
1201 float32 tmp;
1202
1203 u.l = val;
1204 /* NaN are not treated the same way IEEE 754 does */
1205 if (unlikely(float32_is_quiet_nan(u.f))) {
1206 return 0;
1207 }
1208 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1209 u.f = float32_mul(u.f, tmp, &env->vec_status);
1210
1211 return float32_to_int32(u.f, &env->vec_status);
1212}
1213
8e703949 1214static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1215{
1216 CPU_FloatU u;
1217 float32 tmp;
1218
1219 u.l = val;
1220 /* NaN are not treated the same way IEEE 754 does */
1221 if (unlikely(float32_is_quiet_nan(u.f))) {
1222 return 0;
1223 }
1224 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1225 u.f = float32_mul(u.f, tmp, &env->vec_status);
1226
1227 return float32_to_uint32(u.f, &env->vec_status);
1228}
1229
8e703949
BS
1230#define HELPER_SPE_SINGLE_CONV(name) \
1231 uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \
1232 { \
1233 return e##name(env, val); \
bd23cd45
BS
1234 }
1235/* efscfsi */
1236HELPER_SPE_SINGLE_CONV(fscfsi);
1237/* efscfui */
1238HELPER_SPE_SINGLE_CONV(fscfui);
1239/* efscfuf */
1240HELPER_SPE_SINGLE_CONV(fscfuf);
1241/* efscfsf */
1242HELPER_SPE_SINGLE_CONV(fscfsf);
1243/* efsctsi */
1244HELPER_SPE_SINGLE_CONV(fsctsi);
1245/* efsctui */
1246HELPER_SPE_SINGLE_CONV(fsctui);
1247/* efsctsiz */
1248HELPER_SPE_SINGLE_CONV(fsctsiz);
1249/* efsctuiz */
1250HELPER_SPE_SINGLE_CONV(fsctuiz);
1251/* efsctsf */
1252HELPER_SPE_SINGLE_CONV(fsctsf);
1253/* efsctuf */
1254HELPER_SPE_SINGLE_CONV(fsctuf);
1255
8e703949
BS
1256#define HELPER_SPE_VECTOR_CONV(name) \
1257 uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \
1258 { \
1259 return ((uint64_t)e##name(env, val >> 32) << 32) | \
1260 (uint64_t)e##name(env, val); \
bd23cd45
BS
1261 }
1262/* evfscfsi */
1263HELPER_SPE_VECTOR_CONV(fscfsi);
1264/* evfscfui */
1265HELPER_SPE_VECTOR_CONV(fscfui);
1266/* evfscfuf */
1267HELPER_SPE_VECTOR_CONV(fscfuf);
1268/* evfscfsf */
1269HELPER_SPE_VECTOR_CONV(fscfsf);
1270/* evfsctsi */
1271HELPER_SPE_VECTOR_CONV(fsctsi);
1272/* evfsctui */
1273HELPER_SPE_VECTOR_CONV(fsctui);
1274/* evfsctsiz */
1275HELPER_SPE_VECTOR_CONV(fsctsiz);
1276/* evfsctuiz */
1277HELPER_SPE_VECTOR_CONV(fsctuiz);
1278/* evfsctsf */
1279HELPER_SPE_VECTOR_CONV(fsctsf);
1280/* evfsctuf */
1281HELPER_SPE_VECTOR_CONV(fsctuf);
1282
1283/* Single-precision floating-point arithmetic */
8e703949 1284static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1285{
1286 CPU_FloatU u1, u2;
1287
1288 u1.l = op1;
1289 u2.l = op2;
1290 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
1291 return u1.l;
1292}
1293
8e703949 1294static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1295{
1296 CPU_FloatU u1, u2;
1297
1298 u1.l = op1;
1299 u2.l = op2;
1300 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
1301 return u1.l;
1302}
1303
8e703949 1304static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1305{
1306 CPU_FloatU u1, u2;
1307
1308 u1.l = op1;
1309 u2.l = op2;
1310 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
1311 return u1.l;
1312}
1313
8e703949 1314static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1315{
1316 CPU_FloatU u1, u2;
1317
1318 u1.l = op1;
1319 u2.l = op2;
1320 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
1321 return u1.l;
1322}
1323
8e703949
BS
1324#define HELPER_SPE_SINGLE_ARITH(name) \
1325 uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
1326 { \
1327 return e##name(env, op1, op2); \
bd23cd45
BS
1328 }
1329/* efsadd */
1330HELPER_SPE_SINGLE_ARITH(fsadd);
1331/* efssub */
1332HELPER_SPE_SINGLE_ARITH(fssub);
1333/* efsmul */
1334HELPER_SPE_SINGLE_ARITH(fsmul);
1335/* efsdiv */
1336HELPER_SPE_SINGLE_ARITH(fsdiv);
1337
1338#define HELPER_SPE_VECTOR_ARITH(name) \
8e703949 1339 uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
bd23cd45 1340 { \
8e703949
BS
1341 return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \
1342 (uint64_t)e##name(env, op1, op2); \
bd23cd45
BS
1343 }
1344/* evfsadd */
1345HELPER_SPE_VECTOR_ARITH(fsadd);
1346/* evfssub */
1347HELPER_SPE_VECTOR_ARITH(fssub);
1348/* evfsmul */
1349HELPER_SPE_VECTOR_ARITH(fsmul);
1350/* evfsdiv */
1351HELPER_SPE_VECTOR_ARITH(fsdiv);
1352
1353/* Single-precision floating-point comparisons */
8e703949 1354static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1355{
1356 CPU_FloatU u1, u2;
1357
1358 u1.l = op1;
1359 u2.l = op2;
1360 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
1361}
1362
8e703949 1363static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1364{
1365 CPU_FloatU u1, u2;
1366
1367 u1.l = op1;
1368 u2.l = op2;
1369 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
1370}
1371
8e703949 1372static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1373{
1374 CPU_FloatU u1, u2;
1375
1376 u1.l = op1;
1377 u2.l = op2;
1378 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
1379}
1380
8e703949 1381static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1382{
1383 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
8e703949 1384 return efscmplt(env, op1, op2);
bd23cd45
BS
1385}
1386
8e703949 1387static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1388{
1389 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
8e703949 1390 return efscmpgt(env, op1, op2);
bd23cd45
BS
1391}
1392
8e703949 1393static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
bd23cd45
BS
1394{
1395 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
8e703949 1396 return efscmpeq(env, op1, op2);
bd23cd45
BS
1397}
1398
8e703949
BS
1399#define HELPER_SINGLE_SPE_CMP(name) \
1400 uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
1401 { \
1402 return e##name(env, op1, op2) << 2; \
bd23cd45
BS
1403 }
1404/* efststlt */
1405HELPER_SINGLE_SPE_CMP(fststlt);
1406/* efststgt */
1407HELPER_SINGLE_SPE_CMP(fststgt);
1408/* efststeq */
1409HELPER_SINGLE_SPE_CMP(fststeq);
1410/* efscmplt */
1411HELPER_SINGLE_SPE_CMP(fscmplt);
1412/* efscmpgt */
1413HELPER_SINGLE_SPE_CMP(fscmpgt);
1414/* efscmpeq */
1415HELPER_SINGLE_SPE_CMP(fscmpeq);
1416
1417static inline uint32_t evcmp_merge(int t0, int t1)
1418{
1419 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
1420}
1421
1422#define HELPER_VECTOR_SPE_CMP(name) \
8e703949 1423 uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
bd23cd45 1424 { \
8e703949
BS
1425 return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \
1426 e##name(env, op1, op2)); \
bd23cd45
BS
1427 }
1428/* evfststlt */
1429HELPER_VECTOR_SPE_CMP(fststlt);
1430/* evfststgt */
1431HELPER_VECTOR_SPE_CMP(fststgt);
1432/* evfststeq */
1433HELPER_VECTOR_SPE_CMP(fststeq);
1434/* evfscmplt */
1435HELPER_VECTOR_SPE_CMP(fscmplt);
1436/* evfscmpgt */
1437HELPER_VECTOR_SPE_CMP(fscmpgt);
1438/* evfscmpeq */
1439HELPER_VECTOR_SPE_CMP(fscmpeq);
1440
1441/* Double-precision floating-point conversion */
8e703949 1442uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1443{
1444 CPU_DoubleU u;
1445
1446 u.d = int32_to_float64(val, &env->vec_status);
1447
1448 return u.ll;
1449}
1450
8e703949 1451uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1452{
1453 CPU_DoubleU u;
1454
1455 u.d = int64_to_float64(val, &env->vec_status);
1456
1457 return u.ll;
1458}
1459
8e703949 1460uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1461{
1462 CPU_DoubleU u;
1463
1464 u.d = uint32_to_float64(val, &env->vec_status);
1465
1466 return u.ll;
1467}
1468
8e703949 1469uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1470{
1471 CPU_DoubleU u;
1472
1473 u.d = uint64_to_float64(val, &env->vec_status);
1474
1475 return u.ll;
1476}
1477
8e703949 1478uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1479{
1480 CPU_DoubleU u;
1481
1482 u.ll = val;
1483 /* NaN are not treated the same way IEEE 754 does */
1484 if (unlikely(float64_is_any_nan(u.d))) {
1485 return 0;
1486 }
1487
1488 return float64_to_int32(u.d, &env->vec_status);
1489}
1490
8e703949 1491uint32_t helper_efdctui(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1492{
1493 CPU_DoubleU u;
1494
1495 u.ll = val;
1496 /* NaN are not treated the same way IEEE 754 does */
1497 if (unlikely(float64_is_any_nan(u.d))) {
1498 return 0;
1499 }
1500
1501 return float64_to_uint32(u.d, &env->vec_status);
1502}
1503
8e703949 1504uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1505{
1506 CPU_DoubleU u;
1507
1508 u.ll = val;
1509 /* NaN are not treated the same way IEEE 754 does */
1510 if (unlikely(float64_is_any_nan(u.d))) {
1511 return 0;
1512 }
1513
1514 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
1515}
1516
8e703949 1517uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1518{
1519 CPU_DoubleU u;
1520
1521 u.ll = val;
1522 /* NaN are not treated the same way IEEE 754 does */
1523 if (unlikely(float64_is_any_nan(u.d))) {
1524 return 0;
1525 }
1526
1527 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
1528}
1529
8e703949 1530uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1531{
1532 CPU_DoubleU u;
1533
1534 u.ll = val;
1535 /* NaN are not treated the same way IEEE 754 does */
1536 if (unlikely(float64_is_any_nan(u.d))) {
1537 return 0;
1538 }
1539
1540 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
1541}
1542
8e703949 1543uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1544{
1545 CPU_DoubleU u;
1546
1547 u.ll = val;
1548 /* NaN are not treated the same way IEEE 754 does */
1549 if (unlikely(float64_is_any_nan(u.d))) {
1550 return 0;
1551 }
1552
1553 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
1554}
1555
8e703949 1556uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1557{
1558 CPU_DoubleU u;
1559 float64 tmp;
1560
1561 u.d = int32_to_float64(val, &env->vec_status);
1562 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
1563 u.d = float64_div(u.d, tmp, &env->vec_status);
1564
1565 return u.ll;
1566}
1567
8e703949 1568uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1569{
1570 CPU_DoubleU u;
1571 float64 tmp;
1572
1573 u.d = uint32_to_float64(val, &env->vec_status);
1574 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
1575 u.d = float64_div(u.d, tmp, &env->vec_status);
1576
1577 return u.ll;
1578}
1579
8e703949 1580uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1581{
1582 CPU_DoubleU u;
1583 float64 tmp;
1584
1585 u.ll = val;
1586 /* NaN are not treated the same way IEEE 754 does */
1587 if (unlikely(float64_is_any_nan(u.d))) {
1588 return 0;
1589 }
1590 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
1591 u.d = float64_mul(u.d, tmp, &env->vec_status);
1592
1593 return float64_to_int32(u.d, &env->vec_status);
1594}
1595
8e703949 1596uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1597{
1598 CPU_DoubleU u;
1599 float64 tmp;
1600
1601 u.ll = val;
1602 /* NaN are not treated the same way IEEE 754 does */
1603 if (unlikely(float64_is_any_nan(u.d))) {
1604 return 0;
1605 }
1606 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
1607 u.d = float64_mul(u.d, tmp, &env->vec_status);
1608
1609 return float64_to_uint32(u.d, &env->vec_status);
1610}
1611
8e703949 1612uint32_t helper_efscfd(CPUPPCState *env, uint64_t val)
bd23cd45
BS
1613{
1614 CPU_DoubleU u1;
1615 CPU_FloatU u2;
1616
1617 u1.ll = val;
1618 u2.f = float64_to_float32(u1.d, &env->vec_status);
1619
1620 return u2.l;
1621}
1622
8e703949 1623uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val)
bd23cd45
BS
1624{
1625 CPU_DoubleU u2;
1626 CPU_FloatU u1;
1627
1628 u1.l = val;
1629 u2.d = float32_to_float64(u1.f, &env->vec_status);
1630
1631 return u2.ll;
1632}
1633
1634/* Double precision fixed-point arithmetic */
8e703949 1635uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1636{
1637 CPU_DoubleU u1, u2;
1638
1639 u1.ll = op1;
1640 u2.ll = op2;
1641 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
1642 return u1.ll;
1643}
1644
8e703949 1645uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1646{
1647 CPU_DoubleU u1, u2;
1648
1649 u1.ll = op1;
1650 u2.ll = op2;
1651 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
1652 return u1.ll;
1653}
1654
8e703949 1655uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1656{
1657 CPU_DoubleU u1, u2;
1658
1659 u1.ll = op1;
1660 u2.ll = op2;
1661 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
1662 return u1.ll;
1663}
1664
8e703949 1665uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1666{
1667 CPU_DoubleU u1, u2;
1668
1669 u1.ll = op1;
1670 u2.ll = op2;
1671 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
1672 return u1.ll;
1673}
1674
1675/* Double precision floating point helpers */
8e703949 1676uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1677{
1678 CPU_DoubleU u1, u2;
1679
1680 u1.ll = op1;
1681 u2.ll = op2;
1682 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
1683}
1684
8e703949 1685uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1686{
1687 CPU_DoubleU u1, u2;
1688
1689 u1.ll = op1;
1690 u2.ll = op2;
1691 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
1692}
1693
8e703949 1694uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1695{
1696 CPU_DoubleU u1, u2;
1697
1698 u1.ll = op1;
1699 u2.ll = op2;
1700 return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
1701}
1702
8e703949 1703uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1704{
1705 /* XXX: TODO: test special values (NaN, infinites, ...) */
8e703949 1706 return helper_efdtstlt(env, op1, op2);
bd23cd45
BS
1707}
1708
8e703949 1709uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1710{
1711 /* XXX: TODO: test special values (NaN, infinites, ...) */
8e703949 1712 return helper_efdtstgt(env, op1, op2);
bd23cd45
BS
1713}
1714
8e703949 1715uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
bd23cd45
BS
1716{
1717 /* XXX: TODO: test special values (NaN, infinites, ...) */
8e703949 1718 return helper_efdtsteq(env, op1, op2);
bd23cd45 1719}
3c3cbbdc
TM
1720
1721#define DECODE_SPLIT(opcode, shift1, nb1, shift2, nb2) \
1722 (((((opcode) >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
1723 (((opcode) >> (shift2)) & ((1 << (nb2)) - 1)))
1724
1725#define xT(opcode) DECODE_SPLIT(opcode, 0, 1, 21, 5)
1726#define xA(opcode) DECODE_SPLIT(opcode, 2, 1, 16, 5)
1727#define xB(opcode) DECODE_SPLIT(opcode, 1, 1, 11, 5)
1728#define xC(opcode) DECODE_SPLIT(opcode, 3, 1, 6, 5)
1729#define BF(opcode) (((opcode) >> (31-8)) & 7)
1730
1731typedef union _ppc_vsr_t {
1732 uint64_t u64[2];
1733 uint32_t u32[4];
1734 float32 f32[4];
1735 float64 f64[2];
1736} ppc_vsr_t;
1737
1738static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
1739{
1740 if (n < 32) {
1741 vsr->f64[0] = env->fpr[n];
1742 vsr->u64[1] = env->vsr[n];
1743 } else {
1744 vsr->u64[0] = env->avr[n-32].u64[0];
1745 vsr->u64[1] = env->avr[n-32].u64[1];
1746 }
1747}
1748
1749static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
1750{
1751 if (n < 32) {
1752 env->fpr[n] = vsr->f64[0];
1753 env->vsr[n] = vsr->u64[1];
1754 } else {
1755 env->avr[n-32].u64[0] = vsr->u64[0];
1756 env->avr[n-32].u64[1] = vsr->u64[1];
1757 }
1758}
1759
1760#define float64_to_float64(x, env) x
ee6e02c0
TM
1761
1762
1763/* VSX_ADD_SUB - VSX floating point add/subract
1764 * name - instruction mnemonic
1765 * op - operation (add or sub)
1766 * nels - number of elements (1, 2 or 4)
1767 * tp - type (float32 or float64)
1768 * fld - vsr_t field (f32 or f64)
1769 * sfprf - set FPRF
1770 */
3fd0aadf 1771#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \
ee6e02c0
TM
1772void helper_##name(CPUPPCState *env, uint32_t opcode) \
1773{ \
1774 ppc_vsr_t xt, xa, xb; \
1775 int i; \
1776 \
1777 getVSR(xA(opcode), &xa, env); \
1778 getVSR(xB(opcode), &xb, env); \
1779 getVSR(xT(opcode), &xt, env); \
1780 helper_reset_fpstatus(env); \
1781 \
1782 for (i = 0; i < nels; i++) { \
1783 float_status tstat = env->fp_status; \
1784 set_float_exception_flags(0, &tstat); \
1785 xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &tstat); \
1786 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1787 \
1788 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1789 if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) {\
1790 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
1791 } else if (tp##_is_signaling_nan(xa.fld[i]) || \
1792 tp##_is_signaling_nan(xb.fld[i])) { \
1793 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
1794 } \
1795 } \
1796 \
3fd0aadf
TM
1797 if (r2sp) { \
1798 xt.fld[i] = helper_frsp(env, xt.fld[i]); \
1799 } \
1800 \
ee6e02c0
TM
1801 if (sfprf) { \
1802 helper_compute_fprf(env, xt.fld[i], sfprf); \
1803 } \
1804 } \
1805 putVSR(xT(opcode), &xt, env); \
1806 helper_float_check_status(env); \
1807}
1808
3fd0aadf
TM
1809VSX_ADD_SUB(xsadddp, add, 1, float64, f64, 1, 0)
1810VSX_ADD_SUB(xsaddsp, add, 1, float64, f64, 1, 1)
1811VSX_ADD_SUB(xvadddp, add, 2, float64, f64, 0, 0)
1812VSX_ADD_SUB(xvaddsp, add, 4, float32, f32, 0, 0)
1813VSX_ADD_SUB(xssubdp, sub, 1, float64, f64, 1, 0)
1814VSX_ADD_SUB(xssubsp, sub, 1, float64, f64, 1, 1)
1815VSX_ADD_SUB(xvsubdp, sub, 2, float64, f64, 0, 0)
1816VSX_ADD_SUB(xvsubsp, sub, 4, float32, f32, 0, 0)
5e591d88
TM
1817
1818/* VSX_MUL - VSX floating point multiply
1819 * op - instruction mnemonic
1820 * nels - number of elements (1, 2 or 4)
1821 * tp - type (float32 or float64)
1822 * fld - vsr_t field (f32 or f64)
1823 * sfprf - set FPRF
1824 */
ab9408a2 1825#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \
5e591d88
TM
1826void helper_##op(CPUPPCState *env, uint32_t opcode) \
1827{ \
1828 ppc_vsr_t xt, xa, xb; \
1829 int i; \
1830 \
1831 getVSR(xA(opcode), &xa, env); \
1832 getVSR(xB(opcode), &xb, env); \
1833 getVSR(xT(opcode), &xt, env); \
1834 helper_reset_fpstatus(env); \
1835 \
1836 for (i = 0; i < nels; i++) { \
1837 float_status tstat = env->fp_status; \
1838 set_float_exception_flags(0, &tstat); \
1839 xt.fld[i] = tp##_mul(xa.fld[i], xb.fld[i], &tstat); \
1840 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1841 \
1842 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1843 if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(xb.fld[i])) || \
1844 (tp##_is_infinity(xb.fld[i]) && tp##_is_zero(xa.fld[i]))) { \
1845 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \
1846 } else if (tp##_is_signaling_nan(xa.fld[i]) || \
1847 tp##_is_signaling_nan(xb.fld[i])) { \
1848 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
1849 } \
1850 } \
1851 \
ab9408a2
TM
1852 if (r2sp) { \
1853 xt.fld[i] = helper_frsp(env, xt.fld[i]); \
1854 } \
1855 \
5e591d88
TM
1856 if (sfprf) { \
1857 helper_compute_fprf(env, xt.fld[i], sfprf); \
1858 } \
1859 } \
1860 \
1861 putVSR(xT(opcode), &xt, env); \
1862 helper_float_check_status(env); \
1863}
1864
ab9408a2
TM
1865VSX_MUL(xsmuldp, 1, float64, f64, 1, 0)
1866VSX_MUL(xsmulsp, 1, float64, f64, 1, 1)
1867VSX_MUL(xvmuldp, 2, float64, f64, 0, 0)
1868VSX_MUL(xvmulsp, 4, float32, f32, 0, 0)
4b98eeef
TM
1869
1870/* VSX_DIV - VSX floating point divide
1871 * op - instruction mnemonic
1872 * nels - number of elements (1, 2 or 4)
1873 * tp - type (float32 or float64)
1874 * fld - vsr_t field (f32 or f64)
1875 * sfprf - set FPRF
1876 */
b24d0b47 1877#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \
4b98eeef
TM
1878void helper_##op(CPUPPCState *env, uint32_t opcode) \
1879{ \
1880 ppc_vsr_t xt, xa, xb; \
1881 int i; \
1882 \
1883 getVSR(xA(opcode), &xa, env); \
1884 getVSR(xB(opcode), &xb, env); \
1885 getVSR(xT(opcode), &xt, env); \
1886 helper_reset_fpstatus(env); \
1887 \
1888 for (i = 0; i < nels; i++) { \
1889 float_status tstat = env->fp_status; \
1890 set_float_exception_flags(0, &tstat); \
1891 xt.fld[i] = tp##_div(xa.fld[i], xb.fld[i], &tstat); \
1892 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1893 \
1894 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1895 if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) { \
1896 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \
1897 } else if (tp##_is_zero(xa.fld[i]) && \
1898 tp##_is_zero(xb.fld[i])) { \
1899 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \
1900 } else if (tp##_is_signaling_nan(xa.fld[i]) || \
1901 tp##_is_signaling_nan(xb.fld[i])) { \
1902 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
1903 } \
1904 } \
1905 \
b24d0b47
TM
1906 if (r2sp) { \
1907 xt.fld[i] = helper_frsp(env, xt.fld[i]); \
1908 } \
1909 \
4b98eeef
TM
1910 if (sfprf) { \
1911 helper_compute_fprf(env, xt.fld[i], sfprf); \
1912 } \
1913 } \
1914 \
1915 putVSR(xT(opcode), &xt, env); \
1916 helper_float_check_status(env); \
1917}
1918
b24d0b47
TM
1919VSX_DIV(xsdivdp, 1, float64, f64, 1, 0)
1920VSX_DIV(xsdivsp, 1, float64, f64, 1, 1)
1921VSX_DIV(xvdivdp, 2, float64, f64, 0, 0)
1922VSX_DIV(xvdivsp, 4, float32, f32, 0, 0)
2009227f
TM
1923
1924/* VSX_RE - VSX floating point reciprocal estimate
1925 * op - instruction mnemonic
1926 * nels - number of elements (1, 2 or 4)
1927 * tp - type (float32 or float64)
1928 * fld - vsr_t field (f32 or f64)
1929 * sfprf - set FPRF
1930 */
1931#define VSX_RE(op, nels, tp, fld, sfprf) \
1932void helper_##op(CPUPPCState *env, uint32_t opcode) \
1933{ \
1934 ppc_vsr_t xt, xb; \
1935 int i; \
1936 \
1937 getVSR(xB(opcode), &xb, env); \
1938 getVSR(xT(opcode), &xt, env); \
1939 helper_reset_fpstatus(env); \
1940 \
1941 for (i = 0; i < nels; i++) { \
1942 if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
1943 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
1944 } \
1945 xt.fld[i] = tp##_div(tp##_one, xb.fld[i], &env->fp_status); \
1946 if (sfprf) { \
1947 helper_compute_fprf(env, xt.fld[0], sfprf); \
1948 } \
1949 } \
1950 \
1951 putVSR(xT(opcode), &xt, env); \
1952 helper_float_check_status(env); \
1953}
1954
1955VSX_RE(xsredp, 1, float64, f64, 1)
1956VSX_RE(xvredp, 2, float64, f64, 0)
1957VSX_RE(xvresp, 4, float32, f32, 0)
d32404fe
TM
1958
1959/* VSX_SQRT - VSX floating point square root
1960 * op - instruction mnemonic
1961 * nels - number of elements (1, 2 or 4)
1962 * tp - type (float32 or float64)
1963 * fld - vsr_t field (f32 or f64)
1964 * sfprf - set FPRF
1965 */
1966#define VSX_SQRT(op, nels, tp, fld, sfprf) \
1967void helper_##op(CPUPPCState *env, uint32_t opcode) \
1968{ \
1969 ppc_vsr_t xt, xb; \
1970 int i; \
1971 \
1972 getVSR(xB(opcode), &xb, env); \
1973 getVSR(xT(opcode), &xt, env); \
1974 helper_reset_fpstatus(env); \
1975 \
1976 for (i = 0; i < nels; i++) { \
1977 float_status tstat = env->fp_status; \
1978 set_float_exception_flags(0, &tstat); \
1979 xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
1980 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1981 \
1982 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1983 if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
1984 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
1985 } else if (tp##_is_signaling_nan(xb.fld[i])) { \
1986 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
1987 } \
1988 } \
1989 \
1990 if (sfprf) { \
1991 helper_compute_fprf(env, xt.fld[i], sfprf); \
1992 } \
1993 } \
1994 \
1995 putVSR(xT(opcode), &xt, env); \
1996 helper_float_check_status(env); \
1997}
1998
1999VSX_SQRT(xssqrtdp, 1, float64, f64, 1)
2000VSX_SQRT(xvsqrtdp, 2, float64, f64, 0)
2001VSX_SQRT(xvsqrtsp, 4, float32, f32, 0)
d3f9df8f
TM
2002
2003/* VSX_RSQRTE - VSX floating point reciprocal square root estimate
2004 * op - instruction mnemonic
2005 * nels - number of elements (1, 2 or 4)
2006 * tp - type (float32 or float64)
2007 * fld - vsr_t field (f32 or f64)
2008 * sfprf - set FPRF
2009 */
2010#define VSX_RSQRTE(op, nels, tp, fld, sfprf) \
2011void helper_##op(CPUPPCState *env, uint32_t opcode) \
2012{ \
2013 ppc_vsr_t xt, xb; \
2014 int i; \
2015 \
2016 getVSR(xB(opcode), &xb, env); \
2017 getVSR(xT(opcode), &xt, env); \
2018 helper_reset_fpstatus(env); \
2019 \
2020 for (i = 0; i < nels; i++) { \
2021 float_status tstat = env->fp_status; \
2022 set_float_exception_flags(0, &tstat); \
2023 xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
2024 xt.fld[i] = tp##_div(tp##_one, xt.fld[i], &tstat); \
2025 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
2026 \
2027 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
2028 if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
2029 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
2030 } else if (tp##_is_signaling_nan(xb.fld[i])) { \
2031 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
2032 } \
2033 } \
2034 \
2035 if (sfprf) { \
2036 helper_compute_fprf(env, xt.fld[i], sfprf); \
2037 } \
2038 } \
2039 \
2040 putVSR(xT(opcode), &xt, env); \
2041 helper_float_check_status(env); \
2042}
2043
2044VSX_RSQRTE(xsrsqrtedp, 1, float64, f64, 1)
2045VSX_RSQRTE(xvrsqrtedp, 2, float64, f64, 0)
2046VSX_RSQRTE(xvrsqrtesp, 4, float32, f32, 0)
bc80838f
TM
2047
2048static inline int ppc_float32_get_unbiased_exp(float32 f)
2049{
2050 return ((f >> 23) & 0xFF) - 127;
2051}
2052
2053static inline int ppc_float64_get_unbiased_exp(float64 f)
2054{
2055 return ((f >> 52) & 0x7FF) - 1023;
2056}
2057
2058/* VSX_TDIV - VSX floating point test for divide
2059 * op - instruction mnemonic
2060 * nels - number of elements (1, 2 or 4)
2061 * tp - type (float32 or float64)
2062 * fld - vsr_t field (f32 or f64)
2063 * emin - minimum unbiased exponent
2064 * emax - maximum unbiased exponent
2065 * nbits - number of fraction bits
2066 */
2067#define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \
2068void helper_##op(CPUPPCState *env, uint32_t opcode) \
2069{ \
2070 ppc_vsr_t xa, xb; \
2071 int i; \
2072 int fe_flag = 0; \
2073 int fg_flag = 0; \
2074 \
2075 getVSR(xA(opcode), &xa, env); \
2076 getVSR(xB(opcode), &xb, env); \
2077 \
2078 for (i = 0; i < nels; i++) { \
2079 if (unlikely(tp##_is_infinity(xa.fld[i]) || \
2080 tp##_is_infinity(xb.fld[i]) || \
2081 tp##_is_zero(xb.fld[i]))) { \
2082 fe_flag = 1; \
2083 fg_flag = 1; \
2084 } else { \
2085 int e_a = ppc_##tp##_get_unbiased_exp(xa.fld[i]); \
2086 int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
2087 \
2088 if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
2089 tp##_is_any_nan(xb.fld[i]))) { \
2090 fe_flag = 1; \
2091 } else if ((e_b <= emin) || (e_b >= (emax-2))) { \
2092 fe_flag = 1; \
2093 } else if (!tp##_is_zero(xa.fld[i]) && \
2094 (((e_a - e_b) >= emax) || \
2095 ((e_a - e_b) <= (emin+1)) || \
2096 (e_a <= (emin+nbits)))) { \
2097 fe_flag = 1; \
2098 } \
2099 \
2100 if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
2101 /* XB is not zero because of the above check and */ \
2102 /* so must be denormalized. */ \
2103 fg_flag = 1; \
2104 } \
2105 } \
2106 } \
2107 \
2108 env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
2109}
2110
2111VSX_TDIV(xstdivdp, 1, float64, f64, -1022, 1023, 52)
2112VSX_TDIV(xvtdivdp, 2, float64, f64, -1022, 1023, 52)
2113VSX_TDIV(xvtdivsp, 4, float32, f32, -126, 127, 23)
5cb151ac
TM
2114
2115/* VSX_TSQRT - VSX floating point test for square root
2116 * op - instruction mnemonic
2117 * nels - number of elements (1, 2 or 4)
2118 * tp - type (float32 or float64)
2119 * fld - vsr_t field (f32 or f64)
2120 * emin - minimum unbiased exponent
2121 * emax - maximum unbiased exponent
2122 * nbits - number of fraction bits
2123 */
2124#define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \
2125void helper_##op(CPUPPCState *env, uint32_t opcode) \
2126{ \
2127 ppc_vsr_t xa, xb; \
2128 int i; \
2129 int fe_flag = 0; \
2130 int fg_flag = 0; \
2131 \
2132 getVSR(xA(opcode), &xa, env); \
2133 getVSR(xB(opcode), &xb, env); \
2134 \
2135 for (i = 0; i < nels; i++) { \
2136 if (unlikely(tp##_is_infinity(xb.fld[i]) || \
2137 tp##_is_zero(xb.fld[i]))) { \
2138 fe_flag = 1; \
2139 fg_flag = 1; \
2140 } else { \
2141 int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
2142 \
2143 if (unlikely(tp##_is_any_nan(xb.fld[i]))) { \
2144 fe_flag = 1; \
2145 } else if (unlikely(tp##_is_zero(xb.fld[i]))) { \
2146 fe_flag = 1; \
2147 } else if (unlikely(tp##_is_neg(xb.fld[i]))) { \
2148 fe_flag = 1; \
2149 } else if (!tp##_is_zero(xb.fld[i]) && \
2150 (e_b <= (emin+nbits))) { \
2151 fe_flag = 1; \
2152 } \
2153 \
2154 if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
2155 /* XB is not zero because of the above check and */ \
2156 /* therefore must be denormalized. */ \
2157 fg_flag = 1; \
2158 } \
2159 } \
2160 } \
2161 \
2162 env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
2163}
2164
2165VSX_TSQRT(xstsqrtdp, 1, float64, f64, -1022, 52)
2166VSX_TSQRT(xvtsqrtdp, 2, float64, f64, -1022, 52)
2167VSX_TSQRT(xvtsqrtsp, 4, float32, f32, -126, 23)
595c6eef
TM
2168
2169/* VSX_MADD - VSX floating point muliply/add variations
2170 * op - instruction mnemonic
2171 * nels - number of elements (1, 2 or 4)
2172 * tp - type (float32 or float64)
2173 * fld - vsr_t field (f32 or f64)
2174 * maddflgs - flags for the float*muladd routine that control the
2175 * various forms (madd, msub, nmadd, nmsub)
2176 * afrm - A form (1=A, 0=M)
2177 * sfprf - set FPRF
2178 */
2179#define VSX_MADD(op, nels, tp, fld, maddflgs, afrm, sfprf) \
2180void helper_##op(CPUPPCState *env, uint32_t opcode) \
2181{ \
2182 ppc_vsr_t xt_in, xa, xb, xt_out; \
2183 ppc_vsr_t *b, *c; \
2184 int i; \
2185 \
2186 if (afrm) { /* AxB + T */ \
2187 b = &xb; \
2188 c = &xt_in; \
2189 } else { /* AxT + B */ \
2190 b = &xt_in; \
2191 c = &xb; \
2192 } \
2193 \
2194 getVSR(xA(opcode), &xa, env); \
2195 getVSR(xB(opcode), &xb, env); \
2196 getVSR(xT(opcode), &xt_in, env); \
2197 \
2198 xt_out = xt_in; \
2199 \
2200 helper_reset_fpstatus(env); \
2201 \
2202 for (i = 0; i < nels; i++) { \
2203 float_status tstat = env->fp_status; \
2204 set_float_exception_flags(0, &tstat); \
2205 xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
2206 maddflgs, &tstat); \
2207 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
2208 \
2209 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
2210 if (tp##_is_signaling_nan(xa.fld[i]) || \
2211 tp##_is_signaling_nan(b->fld[i]) || \
2212 tp##_is_signaling_nan(c->fld[i])) { \
2213 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
2214 tstat.float_exception_flags &= ~float_flag_invalid; \
2215 } \
2216 if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(b->fld[i])) || \
2217 (tp##_is_zero(xa.fld[i]) && tp##_is_infinity(b->fld[i]))) { \
2218 xt_out.fld[i] = float64_to_##tp(fload_invalid_op_excp(env, \
2219 POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status); \
2220 tstat.float_exception_flags &= ~float_flag_invalid; \
2221 } \
2222 if ((tstat.float_exception_flags & float_flag_invalid) && \
2223 ((tp##_is_infinity(xa.fld[i]) || \
2224 tp##_is_infinity(b->fld[i])) && \
2225 tp##_is_infinity(c->fld[i]))) { \
2226 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
2227 } \
2228 } \
2229 if (sfprf) { \
2230 helper_compute_fprf(env, xt_out.fld[i], sfprf); \
2231 } \
2232 } \
2233 putVSR(xT(opcode), &xt_out, env); \
2234 helper_float_check_status(env); \
2235}
2236
2237#define MADD_FLGS 0
2238#define MSUB_FLGS float_muladd_negate_c
2239#define NMADD_FLGS float_muladd_negate_result
2240#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
2241
2242VSX_MADD(xsmaddadp, 1, float64, f64, MADD_FLGS, 1, 1)
2243VSX_MADD(xsmaddmdp, 1, float64, f64, MADD_FLGS, 0, 1)
2244VSX_MADD(xsmsubadp, 1, float64, f64, MSUB_FLGS, 1, 1)
2245VSX_MADD(xsmsubmdp, 1, float64, f64, MSUB_FLGS, 0, 1)
2246VSX_MADD(xsnmaddadp, 1, float64, f64, NMADD_FLGS, 1, 1)
2247VSX_MADD(xsnmaddmdp, 1, float64, f64, NMADD_FLGS, 0, 1)
2248VSX_MADD(xsnmsubadp, 1, float64, f64, NMSUB_FLGS, 1, 1)
2249VSX_MADD(xsnmsubmdp, 1, float64, f64, NMSUB_FLGS, 0, 1)
2250
2251VSX_MADD(xvmaddadp, 2, float64, f64, MADD_FLGS, 1, 0)
2252VSX_MADD(xvmaddmdp, 2, float64, f64, MADD_FLGS, 0, 0)
2253VSX_MADD(xvmsubadp, 2, float64, f64, MSUB_FLGS, 1, 0)
2254VSX_MADD(xvmsubmdp, 2, float64, f64, MSUB_FLGS, 0, 0)
2255VSX_MADD(xvnmaddadp, 2, float64, f64, NMADD_FLGS, 1, 0)
2256VSX_MADD(xvnmaddmdp, 2, float64, f64, NMADD_FLGS, 0, 0)
2257VSX_MADD(xvnmsubadp, 2, float64, f64, NMSUB_FLGS, 1, 0)
2258VSX_MADD(xvnmsubmdp, 2, float64, f64, NMSUB_FLGS, 0, 0)
2259
2260VSX_MADD(xvmaddasp, 4, float32, f32, MADD_FLGS, 1, 0)
2261VSX_MADD(xvmaddmsp, 4, float32, f32, MADD_FLGS, 0, 0)
2262VSX_MADD(xvmsubasp, 4, float32, f32, MSUB_FLGS, 1, 0)
2263VSX_MADD(xvmsubmsp, 4, float32, f32, MSUB_FLGS, 0, 0)
2264VSX_MADD(xvnmaddasp, 4, float32, f32, NMADD_FLGS, 1, 0)
2265VSX_MADD(xvnmaddmsp, 4, float32, f32, NMADD_FLGS, 0, 0)
2266VSX_MADD(xvnmsubasp, 4, float32, f32, NMSUB_FLGS, 1, 0)
2267VSX_MADD(xvnmsubmsp, 4, float32, f32, NMSUB_FLGS, 0, 0)
4f17e9c7
TM
2268
2269#define VSX_SCALAR_CMP(op, ordered) \
2270void helper_##op(CPUPPCState *env, uint32_t opcode) \
2271{ \
2272 ppc_vsr_t xa, xb; \
2273 uint32_t cc = 0; \
2274 \
2275 getVSR(xA(opcode), &xa, env); \
2276 getVSR(xB(opcode), &xb, env); \
2277 \
2278 if (unlikely(float64_is_any_nan(xa.f64[0]) || \
2279 float64_is_any_nan(xb.f64[0]))) { \
2280 if (float64_is_signaling_nan(xa.f64[0]) || \
2281 float64_is_signaling_nan(xb.f64[0])) { \
2282 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
2283 } \
2284 if (ordered) { \
2285 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
2286 } \
2287 cc = 1; \
2288 } else { \
2289 if (float64_lt(xa.f64[0], xb.f64[0], &env->fp_status)) { \
2290 cc = 8; \
2291 } else if (!float64_le(xa.f64[0], xb.f64[0], &env->fp_status)) { \
2292 cc = 4; \
2293 } else { \
2294 cc = 2; \
2295 } \
2296 } \
2297 \
2298 env->fpscr &= ~(0x0F << FPSCR_FPRF); \
2299 env->fpscr |= cc << FPSCR_FPRF; \
2300 env->crf[BF(opcode)] = cc; \
2301 \
2302 helper_float_check_status(env); \
2303}
2304
2305VSX_SCALAR_CMP(xscmpodp, 1)
2306VSX_SCALAR_CMP(xscmpudp, 0)
959e9c9d
TM
2307
2308#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ul)
2309#define float32_snan_to_qnan(x) ((x) | 0x00400000)
2310
2311/* VSX_MAX_MIN - VSX floating point maximum/minimum
2312 * name - instruction mnemonic
2313 * op - operation (max or min)
2314 * nels - number of elements (1, 2 or 4)
2315 * tp - type (float32 or float64)
2316 * fld - vsr_t field (f32 or f64)
2317 */
2318#define VSX_MAX_MIN(name, op, nels, tp, fld) \
2319void helper_##name(CPUPPCState *env, uint32_t opcode) \
2320{ \
2321 ppc_vsr_t xt, xa, xb; \
2322 int i; \
2323 \
2324 getVSR(xA(opcode), &xa, env); \
2325 getVSR(xB(opcode), &xb, env); \
2326 getVSR(xT(opcode), &xt, env); \
2327 \
2328 for (i = 0; i < nels; i++) { \
2329 xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &env->fp_status); \
2330 if (unlikely(tp##_is_signaling_nan(xa.fld[i]) || \
2331 tp##_is_signaling_nan(xb.fld[i]))) { \
2332 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
2333 } \
2334 } \
2335 \
2336 putVSR(xT(opcode), &xt, env); \
2337 helper_float_check_status(env); \
2338}
2339
2340VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, f64)
2341VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, f64)
2342VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, f32)
2343VSX_MAX_MIN(xsmindp, minnum, 1, float64, f64)
2344VSX_MAX_MIN(xvmindp, minnum, 2, float64, f64)
2345VSX_MAX_MIN(xvminsp, minnum, 4, float32, f32)
354a6dec
TM
2346
2347/* VSX_CMP - VSX floating point compare
2348 * op - instruction mnemonic
2349 * nels - number of elements (1, 2 or 4)
2350 * tp - type (float32 or float64)
2351 * fld - vsr_t field (f32 or f64)
2352 * cmp - comparison operation
2353 * svxvc - set VXVC bit
2354 */
2355#define VSX_CMP(op, nels, tp, fld, cmp, svxvc) \
2356void helper_##op(CPUPPCState *env, uint32_t opcode) \
2357{ \
2358 ppc_vsr_t xt, xa, xb; \
2359 int i; \
2360 int all_true = 1; \
2361 int all_false = 1; \
2362 \
2363 getVSR(xA(opcode), &xa, env); \
2364 getVSR(xB(opcode), &xb, env); \
2365 getVSR(xT(opcode), &xt, env); \
2366 \
2367 for (i = 0; i < nels; i++) { \
2368 if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
2369 tp##_is_any_nan(xb.fld[i]))) { \
2370 if (tp##_is_signaling_nan(xa.fld[i]) || \
2371 tp##_is_signaling_nan(xb.fld[i])) { \
2372 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
2373 } \
2374 if (svxvc) { \
2375 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
2376 } \
2377 xt.fld[i] = 0; \
2378 all_true = 0; \
2379 } else { \
2380 if (tp##_##cmp(xb.fld[i], xa.fld[i], &env->fp_status) == 1) { \
2381 xt.fld[i] = -1; \
2382 all_false = 0; \
2383 } else { \
2384 xt.fld[i] = 0; \
2385 all_true = 0; \
2386 } \
2387 } \
2388 } \
2389 \
2390 putVSR(xT(opcode), &xt, env); \
2391 if ((opcode >> (31-21)) & 1) { \
2392 env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \
2393 } \
2394 helper_float_check_status(env); \
2395 }
2396
2397VSX_CMP(xvcmpeqdp, 2, float64, f64, eq, 0)
2398VSX_CMP(xvcmpgedp, 2, float64, f64, le, 1)
2399VSX_CMP(xvcmpgtdp, 2, float64, f64, lt, 1)
2400VSX_CMP(xvcmpeqsp, 4, float32, f32, eq, 0)
2401VSX_CMP(xvcmpgesp, 4, float32, f32, le, 1)
2402VSX_CMP(xvcmpgtsp, 4, float32, f32, lt, 1)
ed8ac568
TM
2403
2404#if defined(HOST_WORDS_BIGENDIAN)
2405#define JOFFSET 0
2406#else
2407#define JOFFSET 1
2408#endif
2409
2410/* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
2411 * op - instruction mnemonic
2412 * nels - number of elements (1, 2 or 4)
2413 * stp - source type (float32 or float64)
2414 * ttp - target type (float32 or float64)
2415 * sfld - source vsr_t field
2416 * tfld - target vsr_t field (f32 or f64)
2417 * sfprf - set FPRF
2418 */
2419#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \
2420void helper_##op(CPUPPCState *env, uint32_t opcode) \
2421{ \
2422 ppc_vsr_t xt, xb; \
2423 int i; \
2424 \
2425 getVSR(xB(opcode), &xb, env); \
2426 getVSR(xT(opcode), &xt, env); \
2427 \
2428 for (i = 0; i < nels; i++) { \
2429 int j = 2*i + JOFFSET; \
2430 xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
2431 if (unlikely(stp##_is_signaling_nan(xb.sfld))) { \
2432 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
2433 xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
2434 } \
2435 if (sfprf) { \
2436 helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \
2437 &env->fp_status), sfprf); \
2438 } \
2439 } \
2440 \
2441 putVSR(xT(opcode), &xt, env); \
2442 helper_float_check_status(env); \
2443}
2444
2445VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, f64[i], f32[j], 1)
2446VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, f32[j], f64[i], 1)
2447VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, f64[i], f32[j], 0)
2448VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, f32[j], f64[i], 0)
5177d2ca
TM
2449
2450/* VSX_CVT_FP_TO_INT - VSX floating point to integer conversion
2451 * op - instruction mnemonic
2452 * nels - number of elements (1, 2 or 4)
2453 * stp - source type (float32 or float64)
2454 * ttp - target type (int32, uint32, int64 or uint64)
2455 * sfld - source vsr_t field
2456 * tfld - target vsr_t field
2457 * jdef - definition of the j index (i or 2*i)
2458 * rnan - resulting NaN
2459 */
2460#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, jdef, rnan) \
2461void helper_##op(CPUPPCState *env, uint32_t opcode) \
2462{ \
2463 ppc_vsr_t xt, xb; \
2464 int i; \
2465 \
2466 getVSR(xB(opcode), &xb, env); \
2467 getVSR(xT(opcode), &xt, env); \
2468 \
2469 for (i = 0; i < nels; i++) { \
2470 int j = jdef; \
2471 if (unlikely(stp##_is_any_nan(xb.sfld))) { \
2472 if (stp##_is_signaling_nan(xb.sfld)) { \
2473 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
2474 } \
2475 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
2476 xt.tfld = rnan; \
2477 } else { \
2478 xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
2479 if (env->fp_status.float_exception_flags & float_flag_invalid) { \
2480 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
2481 } \
2482 } \
2483 } \
2484 \
2485 putVSR(xT(opcode), &xt, env); \
2486 helper_float_check_status(env); \
2487}
2488
2489VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, f64[j], u64[i], i, \
2490 0x8000000000000000ul)
2491VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, f64[i], u32[j], \
2492 2*i + JOFFSET, 0x80000000l)
2493VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, f64[j], u64[i], i, 0ul)
2494VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, f64[i], u32[j], \
2495 2*i + JOFFSET, 0)
2496VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, f64[j], u64[i], i, \
2497 0x8000000000000000ul)
2498VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, f64[i], u32[j], \
2499 2*i + JOFFSET, 0x80000000l)
2500VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, f64[j], u64[i], i, 0ul)
2501VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, f64[i], u32[j], \
2502 2*i + JOFFSET, 0)
2503VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, f32[j], u64[i], \
2504 2*i + JOFFSET, 0x8000000000000000ul)
2505VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, f32[j], u32[j], i, \
2506 0x80000000l)
2507VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, f32[j], u64[i], \
2508 2*i + JOFFSET, 0ul)
2509VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, f32[j], u32[i], i, 0)
2510
2511/* VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
2512 * op - instruction mnemonic
2513 * nels - number of elements (1, 2 or 4)
2514 * stp - source type (int32, uint32, int64 or uint64)
2515 * ttp - target type (float32 or float64)
2516 * sfld - source vsr_t field
2517 * tfld - target vsr_t field
2518 * jdef - definition of the j index (i or 2*i)
2519 * sfprf - set FPRF
2520 */
2521#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, jdef, sfprf) \
2522void helper_##op(CPUPPCState *env, uint32_t opcode) \
2523{ \
2524 ppc_vsr_t xt, xb; \
2525 int i; \
2526 \
2527 getVSR(xB(opcode), &xb, env); \
2528 getVSR(xT(opcode), &xt, env); \
2529 \
2530 for (i = 0; i < nels; i++) { \
2531 int j = jdef; \
2532 xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
2533 if (sfprf) { \
2534 helper_compute_fprf(env, xt.tfld, sfprf); \
2535 } \
2536 } \
2537 \
2538 putVSR(xT(opcode), &xt, env); \
2539 helper_float_check_status(env); \
2540}
2541
2542VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, u64[j], f64[i], i, 1)
2543VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, u64[j], f64[i], i, 1)
2544VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, u64[j], f64[i], i, 0)
2545VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, u64[j], f64[i], i, 0)
2546VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, u32[j], f64[i], \
2547 2*i + JOFFSET, 0)
2548VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, u32[j], f64[i], \
2549 2*i + JOFFSET, 0)
2550VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, u64[i], f32[j], \
2551 2*i + JOFFSET, 0)
2552VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, u64[i], f32[j], \
2553 2*i + JOFFSET, 0)
2554VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, u32[j], f32[i], i, 0)
2555VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, u32[j], f32[i], i, 0)
88e33d08
TM
2556
2557/* For "use current rounding mode", define a value that will not be one of
2558 * the existing rounding model enums.
2559 */
2560#define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \
2561 float_round_up + float_round_to_zero)
2562
2563/* VSX_ROUND - VSX floating point round
2564 * op - instruction mnemonic
2565 * nels - number of elements (1, 2 or 4)
2566 * tp - type (float32 or float64)
2567 * fld - vsr_t field (f32 or f64)
2568 * rmode - rounding mode
2569 * sfprf - set FPRF
2570 */
2571#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \
2572void helper_##op(CPUPPCState *env, uint32_t opcode) \
2573{ \
2574 ppc_vsr_t xt, xb; \
2575 int i; \
2576 getVSR(xB(opcode), &xb, env); \
2577 getVSR(xT(opcode), &xt, env); \
2578 \
2579 if (rmode != FLOAT_ROUND_CURRENT) { \
2580 set_float_rounding_mode(rmode, &env->fp_status); \
2581 } \
2582 \
2583 for (i = 0; i < nels; i++) { \
2584 if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
2585 fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
2586 xt.fld[i] = tp##_snan_to_qnan(xb.fld[i]); \
2587 } else { \
2588 xt.fld[i] = tp##_round_to_int(xb.fld[i], &env->fp_status); \
2589 } \
2590 if (sfprf) { \
2591 helper_compute_fprf(env, xt.fld[i], sfprf); \
2592 } \
2593 } \
2594 \
2595 /* If this is not a "use current rounding mode" instruction, \
2596 * then inhibit setting of the XX bit and restore rounding \
2597 * mode from FPSCR */ \
2598 if (rmode != FLOAT_ROUND_CURRENT) { \
2599 fpscr_set_rounding_mode(env); \
2600 env->fp_status.float_exception_flags &= ~float_flag_inexact; \
2601 } \
2602 \
2603 putVSR(xT(opcode), &xt, env); \
2604 helper_float_check_status(env); \
2605}
2606
2607VSX_ROUND(xsrdpi, 1, float64, f64, float_round_nearest_even, 1)
2608VSX_ROUND(xsrdpic, 1, float64, f64, FLOAT_ROUND_CURRENT, 1)
2609VSX_ROUND(xsrdpim, 1, float64, f64, float_round_down, 1)
2610VSX_ROUND(xsrdpip, 1, float64, f64, float_round_up, 1)
2611VSX_ROUND(xsrdpiz, 1, float64, f64, float_round_to_zero, 1)
2612
2613VSX_ROUND(xvrdpi, 2, float64, f64, float_round_nearest_even, 0)
2614VSX_ROUND(xvrdpic, 2, float64, f64, FLOAT_ROUND_CURRENT, 0)
2615VSX_ROUND(xvrdpim, 2, float64, f64, float_round_down, 0)
2616VSX_ROUND(xvrdpip, 2, float64, f64, float_round_up, 0)
2617VSX_ROUND(xvrdpiz, 2, float64, f64, float_round_to_zero, 0)
2618
2619VSX_ROUND(xvrspi, 4, float32, f32, float_round_nearest_even, 0)
2620VSX_ROUND(xvrspic, 4, float32, f32, FLOAT_ROUND_CURRENT, 0)
2621VSX_ROUND(xvrspim, 4, float32, f32, float_round_down, 0)
2622VSX_ROUND(xvrspip, 4, float32, f32, float_round_up, 0)
2623VSX_ROUND(xvrspiz, 4, float32, f32, float_round_to_zero, 0)