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.1 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 "qemu/osdep.h"
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22 #include "exec/exec-all.h"
23 #include "internal.h"
24 #include "fpu/softfloat.h"
25
float128_snan_to_qnan(float128 x)26 static inline float128 float128_snan_to_qnan(float128 x)
27 {
28 float128 r;
29
30 r.high = x.high | 0x0000800000000000;
31 r.low = x.low;
32 return r;
33 }
34
35 #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
36 #define float32_snan_to_qnan(x) ((x) | 0x00400000)
37 #define float16_snan_to_qnan(x) ((x) | 0x0200)
38
bfp32_neg(float32 a)39 static inline float32 bfp32_neg(float32 a)
40 {
41 if (unlikely(float32_is_any_nan(a))) {
42 return a;
43 } else {
44 return float32_chs(a);
45 }
46 }
47
fp_exceptions_enabled(CPUPPCState * env)48 static inline bool fp_exceptions_enabled(CPUPPCState *env)
49 {
50 #ifdef CONFIG_USER_ONLY
51 return true;
52 #else
53 return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0;
54 #endif
55 }
56
57 /*****************************************************************************/
58 /* Floating point operations helpers */
59
60 /*
61 * This is the non-arithmatic conversion that happens e.g. on loads.
62 * In the Power ISA pseudocode, this is called DOUBLE.
63 */
helper_todouble(uint32_t arg)64 uint64_t helper_todouble(uint32_t arg)
65 {
66 uint32_t abs_arg = arg & 0x7fffffff;
67 uint64_t ret;
68
69 if (likely(abs_arg >= 0x00800000)) {
70 if (unlikely(extract32(arg, 23, 8) == 0xff)) {
71 /* Inf or NAN. */
72 ret = (uint64_t)extract32(arg, 31, 1) << 63;
73 ret |= (uint64_t)0x7ff << 52;
74 ret |= (uint64_t)extract32(arg, 0, 23) << 29;
75 } else {
76 /* Normalized operand. */
77 ret = (uint64_t)extract32(arg, 30, 2) << 62;
78 ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59;
79 ret |= (uint64_t)extract32(arg, 0, 30) << 29;
80 }
81 } else {
82 /* Zero or Denormalized operand. */
83 ret = (uint64_t)extract32(arg, 31, 1) << 63;
84 if (unlikely(abs_arg != 0)) {
85 /*
86 * Denormalized operand.
87 * Shift fraction so that the msb is in the implicit bit position.
88 * Thus, shift is in the range [1:23].
89 */
90 int shift = clz32(abs_arg) - 8;
91 /*
92 * The first 3 terms compute the float64 exponent. We then bias
93 * this result by -1 so that we can swallow the implicit bit below.
94 */
95 int exp = -126 - shift + 1023 - 1;
96
97 ret |= (uint64_t)exp << 52;
98 ret += (uint64_t)abs_arg << (52 - 23 + shift);
99 }
100 }
101 return ret;
102 }
103
104 /*
105 * This is the non-arithmatic conversion that happens e.g. on stores.
106 * In the Power ISA pseudocode, this is called SINGLE.
107 */
helper_tosingle(uint64_t arg)108 uint32_t helper_tosingle(uint64_t arg)
109 {
110 int exp = extract64(arg, 52, 11);
111 uint32_t ret;
112
113 if (likely(exp > 896)) {
114 /* No denormalization required (includes Inf, NaN). */
115 ret = extract64(arg, 62, 2) << 30;
116 ret |= extract64(arg, 29, 30);
117 } else {
118 /*
119 * Zero or Denormal result. If the exponent is in bounds for
120 * a single-precision denormal result, extract the proper
121 * bits. If the input is not zero, and the exponent is out of
122 * bounds, then the result is undefined; this underflows to
123 * zero.
124 */
125 ret = extract64(arg, 63, 1) << 31;
126 if (unlikely(exp >= 874)) {
127 /* Denormal result. */
128 ret |= ((1ULL << 52) | extract64(arg, 0, 52)) >> (896 + 30 - exp);
129 }
130 }
131 return ret;
132 }
133
ppc_float32_get_unbiased_exp(float32 f)134 static inline int ppc_float32_get_unbiased_exp(float32 f)
135 {
136 return ((f >> 23) & 0xFF) - 127;
137 }
138
ppc_float64_get_unbiased_exp(float64 f)139 static inline int ppc_float64_get_unbiased_exp(float64 f)
140 {
141 return ((f >> 52) & 0x7FF) - 1023;
142 }
143
144 #define COMPUTE_FPRF(tp) \
145 void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \
146 { \
147 bool neg = tp##_is_neg(arg); \
148 target_ulong fprf; \
149 if (likely(tp##_is_normal(arg))) { \
150 fprf = neg ? 0x08 << FPSCR_FPRF : 0x04 << FPSCR_FPRF; \
151 } else if (tp##_is_zero(arg)) { \
152 fprf = neg ? 0x12 << FPSCR_FPRF : 0x02 << FPSCR_FPRF; \
153 } else if (tp##_is_zero_or_denormal(arg)) { \
154 fprf = neg ? 0x18 << FPSCR_FPRF : 0x14 << FPSCR_FPRF; \
155 } else if (tp##_is_infinity(arg)) { \
156 fprf = neg ? 0x09 << FPSCR_FPRF : 0x05 << FPSCR_FPRF; \
157 } else { \
158 if (tp##_is_signaling_nan(arg, &env->fp_status)) { \
159 fprf = 0x00 << FPSCR_FPRF; \
160 } else { \
161 fprf = 0x11 << FPSCR_FPRF; \
162 } \
163 } \
164 env->fpscr = (env->fpscr & ~FP_FPRF) | fprf; \
165 }
166
167 COMPUTE_FPRF(float16)
COMPUTE_FPRF(float32)168 COMPUTE_FPRF(float32)
169 COMPUTE_FPRF(float64)
170 COMPUTE_FPRF(float128)
171
172 /* Floating-point invalid operations exception */
173 static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr)
174 {
175 /* Update the floating-point invalid operation summary */
176 env->fpscr |= FP_VX;
177 /* Update the floating-point exception summary */
178 env->fpscr |= FP_FX;
179 if (env->fpscr & FP_VE) {
180 /* Update the floating-point enabled exception summary */
181 env->fpscr |= FP_FEX;
182 if (fp_exceptions_enabled(env)) {
183 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
184 POWERPC_EXCP_FP | op, retaddr);
185 }
186 }
187 }
188
finish_invalid_op_arith(CPUPPCState * env,int op,bool set_fpcc,uintptr_t retaddr)189 static void finish_invalid_op_arith(CPUPPCState *env, int op,
190 bool set_fpcc, uintptr_t retaddr)
191 {
192 env->fpscr &= ~(FP_FR | FP_FI);
193 if (!(env->fpscr & FP_VE)) {
194 if (set_fpcc) {
195 env->fpscr &= ~FP_FPCC;
196 env->fpscr |= (FP_C | FP_FU);
197 }
198 }
199 finish_invalid_op_excp(env, op, retaddr);
200 }
201
202 /* Signalling NaN */
float_invalid_op_vxsnan(CPUPPCState * env,uintptr_t retaddr)203 static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr)
204 {
205 env->fpscr |= FP_VXSNAN;
206 finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr);
207 }
208
209 /* Magnitude subtraction of infinities */
float_invalid_op_vxisi(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)210 static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc,
211 uintptr_t retaddr)
212 {
213 env->fpscr |= FP_VXISI;
214 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr);
215 }
216
217 /* Division of infinity by infinity */
float_invalid_op_vxidi(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)218 static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc,
219 uintptr_t retaddr)
220 {
221 env->fpscr |= FP_VXIDI;
222 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr);
223 }
224
225 /* Division of zero by zero */
float_invalid_op_vxzdz(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)226 static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc,
227 uintptr_t retaddr)
228 {
229 env->fpscr |= FP_VXZDZ;
230 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr);
231 }
232
233 /* Multiplication of zero by infinity */
float_invalid_op_vximz(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)234 static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc,
235 uintptr_t retaddr)
236 {
237 env->fpscr |= FP_VXIMZ;
238 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr);
239 }
240
241 /* Square root of a negative number */
float_invalid_op_vxsqrt(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)242 static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc,
243 uintptr_t retaddr)
244 {
245 env->fpscr |= FP_VXSQRT;
246 finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr);
247 }
248
249 /* Ordered comparison of NaN */
float_invalid_op_vxvc(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)250 static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
251 uintptr_t retaddr)
252 {
253 env->fpscr |= FP_VXVC;
254 if (set_fpcc) {
255 env->fpscr &= ~FP_FPCC;
256 env->fpscr |= (FP_C | FP_FU);
257 }
258 /* Update the floating-point invalid operation summary */
259 env->fpscr |= FP_VX;
260 /* Update the floating-point exception summary */
261 env->fpscr |= FP_FX;
262 /* We must update the target FPR before raising the exception */
263 if (env->fpscr & FP_VE) {
264 CPUState *cs = env_cpu(env);
265
266 cs->exception_index = POWERPC_EXCP_PROGRAM;
267 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
268 /* Update the floating-point enabled exception summary */
269 env->fpscr |= FP_FEX;
270 /* Exception is deferred */
271 }
272 }
273
274 /* Invalid conversion */
float_invalid_op_vxcvi(CPUPPCState * env,bool set_fpcc,uintptr_t retaddr)275 static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc,
276 uintptr_t retaddr)
277 {
278 env->fpscr |= FP_VXCVI;
279 env->fpscr &= ~(FP_FR | FP_FI);
280 if (!(env->fpscr & FP_VE)) {
281 if (set_fpcc) {
282 env->fpscr &= ~FP_FPCC;
283 env->fpscr |= (FP_C | FP_FU);
284 }
285 }
286 finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr);
287 }
288
float_zero_divide_excp(CPUPPCState * env,uintptr_t raddr)289 static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
290 {
291 env->fpscr |= FP_ZX;
292 env->fpscr &= ~(FP_FR | FP_FI);
293 /* Update the floating-point exception summary */
294 env->fpscr |= FP_FX;
295 if (env->fpscr & FP_ZE) {
296 /* Update the floating-point enabled exception summary */
297 env->fpscr |= FP_FEX;
298 if (fp_exceptions_enabled(env)) {
299 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
300 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
301 raddr);
302 }
303 }
304 }
305
float_overflow_excp(CPUPPCState * env)306 static inline int float_overflow_excp(CPUPPCState *env)
307 {
308 CPUState *cs = env_cpu(env);
309
310 env->fpscr |= FP_OX;
311 /* Update the floating-point exception summary */
312 env->fpscr |= FP_FX;
313
314 bool overflow_enabled = !!(env->fpscr & FP_OE);
315 if (overflow_enabled) {
316 /* Update the floating-point enabled exception summary */
317 env->fpscr |= FP_FEX;
318 /* We must update the target FPR before raising the exception */
319 cs->exception_index = POWERPC_EXCP_PROGRAM;
320 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
321 }
322
323 return overflow_enabled ? 0 : float_flag_inexact;
324 }
325
float_underflow_excp(CPUPPCState * env)326 static inline void float_underflow_excp(CPUPPCState *env)
327 {
328 CPUState *cs = env_cpu(env);
329
330 env->fpscr |= FP_UX;
331 /* Update the floating-point exception summary */
332 env->fpscr |= FP_FX;
333 if (env->fpscr & FP_UE) {
334 /* Update the floating-point enabled exception summary */
335 env->fpscr |= FP_FEX;
336 /* We must update the target FPR before raising the exception */
337 cs->exception_index = POWERPC_EXCP_PROGRAM;
338 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
339 }
340 }
341
float_inexact_excp(CPUPPCState * env)342 static inline void float_inexact_excp(CPUPPCState *env)
343 {
344 CPUState *cs = env_cpu(env);
345
346 env->fpscr |= FP_XX;
347 /* Update the floating-point exception summary */
348 env->fpscr |= FP_FX;
349 if (env->fpscr & FP_XE) {
350 /* Update the floating-point enabled exception summary */
351 env->fpscr |= FP_FEX;
352 /* We must update the target FPR before raising the exception */
353 cs->exception_index = POWERPC_EXCP_PROGRAM;
354 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
355 }
356 }
357
helper_fpscr_clrbit(CPUPPCState * env,uint32_t bit)358 void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
359 {
360 uint32_t mask = 1u << bit;
361 if (env->fpscr & mask) {
362 ppc_store_fpscr(env, env->fpscr & ~(target_ulong)mask);
363 }
364 }
365
helper_fpscr_setbit(CPUPPCState * env,uint32_t bit)366 void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
367 {
368 uint32_t mask = 1u << bit;
369 if (!(env->fpscr & mask)) {
370 ppc_store_fpscr(env, env->fpscr | mask);
371 }
372 }
373
helper_store_fpscr(CPUPPCState * env,uint64_t val,uint32_t nibbles)374 void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles)
375 {
376 target_ulong mask = 0;
377 int i;
378
379 /* TODO: push this extension back to translation time */
380 for (i = 0; i < sizeof(target_ulong) * 2; i++) {
381 if (nibbles & (1 << i)) {
382 mask |= (target_ulong) 0xf << (4 * i);
383 }
384 }
385 val = (val & mask) | (env->fpscr & ~mask);
386 ppc_store_fpscr(env, val);
387 }
388
do_fpscr_check_status(CPUPPCState * env,uintptr_t raddr)389 static void do_fpscr_check_status(CPUPPCState *env, uintptr_t raddr)
390 {
391 CPUState *cs = env_cpu(env);
392 target_ulong fpscr = env->fpscr;
393 int error = 0;
394
395 if ((fpscr & FP_OX) && (fpscr & FP_OE)) {
396 error = POWERPC_EXCP_FP_OX;
397 } else if ((fpscr & FP_UX) && (fpscr & FP_UE)) {
398 error = POWERPC_EXCP_FP_UX;
399 } else if ((fpscr & FP_XX) && (fpscr & FP_XE)) {
400 error = POWERPC_EXCP_FP_XX;
401 } else if ((fpscr & FP_ZX) && (fpscr & FP_ZE)) {
402 error = POWERPC_EXCP_FP_ZX;
403 } else if (fpscr & FP_VE) {
404 if (fpscr & FP_VXSOFT) {
405 error = POWERPC_EXCP_FP_VXSOFT;
406 } else if (fpscr & FP_VXSNAN) {
407 error = POWERPC_EXCP_FP_VXSNAN;
408 } else if (fpscr & FP_VXISI) {
409 error = POWERPC_EXCP_FP_VXISI;
410 } else if (fpscr & FP_VXIDI) {
411 error = POWERPC_EXCP_FP_VXIDI;
412 } else if (fpscr & FP_VXZDZ) {
413 error = POWERPC_EXCP_FP_VXZDZ;
414 } else if (fpscr & FP_VXIMZ) {
415 error = POWERPC_EXCP_FP_VXIMZ;
416 } else if (fpscr & FP_VXVC) {
417 error = POWERPC_EXCP_FP_VXVC;
418 } else if (fpscr & FP_VXSQRT) {
419 error = POWERPC_EXCP_FP_VXSQRT;
420 } else if (fpscr & FP_VXCVI) {
421 error = POWERPC_EXCP_FP_VXCVI;
422 } else {
423 return;
424 }
425 } else {
426 return;
427 }
428 cs->exception_index = POWERPC_EXCP_PROGRAM;
429 env->error_code = error | POWERPC_EXCP_FP;
430 env->fpscr |= FP_FEX;
431 /* Deferred floating-point exception after target FPSCR update */
432 if (fp_exceptions_enabled(env)) {
433 raise_exception_err_ra(env, cs->exception_index,
434 env->error_code, raddr);
435 }
436 }
437
helper_fpscr_check_status(CPUPPCState * env)438 void helper_fpscr_check_status(CPUPPCState *env)
439 {
440 do_fpscr_check_status(env, GETPC());
441 }
442
do_float_check_status(CPUPPCState * env,bool change_fi,uintptr_t raddr)443 static void do_float_check_status(CPUPPCState *env, bool change_fi,
444 uintptr_t raddr)
445 {
446 CPUState *cs = env_cpu(env);
447 int status = get_float_exception_flags(&env->fp_status);
448
449 if (status & float_flag_overflow) {
450 status |= float_overflow_excp(env);
451 } else if (status & float_flag_underflow) {
452 float_underflow_excp(env);
453 }
454 if (status & float_flag_inexact) {
455 float_inexact_excp(env);
456 }
457 if (change_fi) {
458 env->fpscr = FIELD_DP64(env->fpscr, FPSCR, FI,
459 !!(status & float_flag_inexact));
460 }
461
462 if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
463 (env->error_code & POWERPC_EXCP_FP)) {
464 /* Deferred floating-point exception after target FPR update */
465 if (fp_exceptions_enabled(env)) {
466 raise_exception_err_ra(env, cs->exception_index,
467 env->error_code, raddr);
468 }
469 }
470 }
471
helper_float_check_status(CPUPPCState * env)472 void helper_float_check_status(CPUPPCState *env)
473 {
474 do_float_check_status(env, true, GETPC());
475 }
476
helper_reset_fpstatus(CPUPPCState * env)477 void helper_reset_fpstatus(CPUPPCState *env)
478 {
479 set_float_exception_flags(0, &env->fp_status);
480 }
481
float_invalid_op_addsub(CPUPPCState * env,int flags,bool set_fpcc,uintptr_t retaddr)482 static void float_invalid_op_addsub(CPUPPCState *env, int flags,
483 bool set_fpcc, uintptr_t retaddr)
484 {
485 if (flags & float_flag_invalid_isi) {
486 float_invalid_op_vxisi(env, set_fpcc, retaddr);
487 } else if (flags & float_flag_invalid_snan) {
488 float_invalid_op_vxsnan(env, retaddr);
489 }
490 }
491
addsub_flags_handler(CPUPPCState * env,int flags,uintptr_t ra)492 static inline void addsub_flags_handler(CPUPPCState *env, int flags,
493 uintptr_t ra)
494 {
495 if (unlikely(flags & float_flag_invalid)) {
496 float_invalid_op_addsub(env, flags, 1, ra);
497 }
498 }
499
float_invalid_op_mul(CPUPPCState * env,int flags,bool set_fprc,uintptr_t retaddr)500 static void float_invalid_op_mul(CPUPPCState *env, int flags,
501 bool set_fprc, uintptr_t retaddr)
502 {
503 if (flags & float_flag_invalid_imz) {
504 float_invalid_op_vximz(env, set_fprc, retaddr);
505 } else if (flags & float_flag_invalid_snan) {
506 float_invalid_op_vxsnan(env, retaddr);
507 }
508 }
509
mul_flags_handler(CPUPPCState * env,int flags,uintptr_t ra)510 static inline void mul_flags_handler(CPUPPCState *env, int flags, uintptr_t ra)
511 {
512 if (unlikely(flags & float_flag_invalid)) {
513 float_invalid_op_mul(env, flags, 1, ra);
514 }
515 }
516
float_invalid_op_div(CPUPPCState * env,int flags,bool set_fprc,uintptr_t retaddr)517 static void float_invalid_op_div(CPUPPCState *env, int flags,
518 bool set_fprc, uintptr_t retaddr)
519 {
520 if (flags & float_flag_invalid_idi) {
521 float_invalid_op_vxidi(env, set_fprc, retaddr);
522 } else if (flags & float_flag_invalid_zdz) {
523 float_invalid_op_vxzdz(env, set_fprc, retaddr);
524 } else if (flags & float_flag_invalid_snan) {
525 float_invalid_op_vxsnan(env, retaddr);
526 }
527 }
528
div_flags_handler(CPUPPCState * env,int flags,uintptr_t ra)529 static inline void div_flags_handler(CPUPPCState *env, int flags, uintptr_t ra)
530 {
531 if (unlikely(flags & float_flag_invalid)) {
532 float_invalid_op_div(env, flags, 1, ra);
533 }
534 if (unlikely(flags & float_flag_divbyzero)) {
535 float_zero_divide_excp(env, ra);
536 }
537 }
538
float_invalid_cvt(CPUPPCState * env,int flags,uint64_t ret,uint64_t ret_nan,bool set_fprc,uintptr_t retaddr)539 static uint64_t float_invalid_cvt(CPUPPCState *env, int flags,
540 uint64_t ret, uint64_t ret_nan,
541 bool set_fprc, uintptr_t retaddr)
542 {
543 /*
544 * VXCVI is different from most in that it sets two exception bits,
545 * VXCVI and VXSNAN for an SNaN input.
546 */
547 if (flags & float_flag_invalid_snan) {
548 env->fpscr |= FP_VXSNAN;
549 }
550 float_invalid_op_vxcvi(env, set_fprc, retaddr);
551
552 return flags & float_flag_invalid_cvti ? ret : ret_nan;
553 }
554
555 #define FPU_FCTI(op, cvt, nanval) \
556 uint64_t helper_##op(CPUPPCState *env, float64 arg) \
557 { \
558 uint64_t ret = float64_to_##cvt(arg, &env->fp_status); \
559 int flags = get_float_exception_flags(&env->fp_status); \
560 if (unlikely(flags & float_flag_invalid)) { \
561 ret = float_invalid_cvt(env, flags, ret, nanval, 1, GETPC()); \
562 } \
563 return ret; \
564 }
565
566 FPU_FCTI(fctiw, int32, 0x80000000U)
567 FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
568 FPU_FCTI(fctiwu, uint32, 0x00000000U)
569 FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
570 FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
571 FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
572 FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
573 FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
574
575 #define FPU_FCFI(op, cvtr, is_single) \
576 uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
577 { \
578 CPU_DoubleU farg; \
579 \
580 if (is_single) { \
581 float32 tmp = cvtr(arg, &env->fp_status); \
582 farg.d = float32_to_float64(tmp, &env->fp_status); \
583 } else { \
584 farg.d = cvtr(arg, &env->fp_status); \
585 } \
586 do_float_check_status(env, true, GETPC()); \
587 return farg.ll; \
588 }
589
590 FPU_FCFI(fcfid, int64_to_float64, 0)
591 FPU_FCFI(fcfids, int64_to_float32, 1)
592 FPU_FCFI(fcfidu, uint64_to_float64, 0)
593 FPU_FCFI(fcfidus, uint64_to_float32, 1)
594
do_fri(CPUPPCState * env,uint64_t arg,FloatRoundMode rounding_mode)595 static uint64_t do_fri(CPUPPCState *env, uint64_t arg,
596 FloatRoundMode rounding_mode)
597 {
598 FloatRoundMode old_rounding_mode = get_float_rounding_mode(&env->fp_status);
599 int flags;
600
601 set_float_rounding_mode(rounding_mode, &env->fp_status);
602 arg = float64_round_to_int(arg, &env->fp_status);
603 set_float_rounding_mode(old_rounding_mode, &env->fp_status);
604
605 flags = get_float_exception_flags(&env->fp_status);
606 if (flags & float_flag_invalid_snan) {
607 float_invalid_op_vxsnan(env, GETPC());
608 }
609
610 /* fri* does not set FPSCR[XX] */
611 set_float_exception_flags(flags & ~float_flag_inexact, &env->fp_status);
612 do_float_check_status(env, true, GETPC());
613
614 return arg;
615 }
616
helper_frin(CPUPPCState * env,uint64_t arg)617 uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
618 {
619 return do_fri(env, arg, float_round_ties_away);
620 }
621
helper_friz(CPUPPCState * env,uint64_t arg)622 uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
623 {
624 return do_fri(env, arg, float_round_to_zero);
625 }
626
helper_frip(CPUPPCState * env,uint64_t arg)627 uint64_t helper_frip(CPUPPCState *env, uint64_t arg)
628 {
629 return do_fri(env, arg, float_round_up);
630 }
631
helper_frim(CPUPPCState * env,uint64_t arg)632 uint64_t helper_frim(CPUPPCState *env, uint64_t arg)
633 {
634 return do_fri(env, arg, float_round_down);
635 }
636
float_invalid_op_madd(CPUPPCState * env,int flags,bool set_fpcc,uintptr_t retaddr)637 static void float_invalid_op_madd(CPUPPCState *env, int flags,
638 bool set_fpcc, uintptr_t retaddr)
639 {
640 if (flags & float_flag_invalid_imz) {
641 float_invalid_op_vximz(env, set_fpcc, retaddr);
642 } else {
643 float_invalid_op_addsub(env, flags, set_fpcc, retaddr);
644 }
645 }
646
do_fmadd(CPUPPCState * env,float64 a,float64 b,float64 c,int madd_flags,uintptr_t retaddr)647 static float64 do_fmadd(CPUPPCState *env, float64 a, float64 b,
648 float64 c, int madd_flags, uintptr_t retaddr)
649 {
650 float64 ret = float64_muladd(a, b, c, madd_flags, &env->fp_status);
651 int flags = get_float_exception_flags(&env->fp_status);
652
653 if (unlikely(flags & float_flag_invalid)) {
654 float_invalid_op_madd(env, flags, 1, retaddr);
655 }
656 return ret;
657 }
658
do_fmadds(CPUPPCState * env,float64 a,float64 b,float64 c,int madd_flags,uintptr_t retaddr)659 static uint64_t do_fmadds(CPUPPCState *env, float64 a, float64 b,
660 float64 c, int madd_flags, uintptr_t retaddr)
661 {
662 float64 ret = float64r32_muladd(a, b, c, madd_flags, &env->fp_status);
663 int flags = get_float_exception_flags(&env->fp_status);
664
665 if (unlikely(flags & float_flag_invalid)) {
666 float_invalid_op_madd(env, flags, 1, retaddr);
667 }
668 return ret;
669 }
670
671 #define FPU_FMADD(op, madd_flags) \
672 uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \
673 uint64_t arg2, uint64_t arg3) \
674 { return do_fmadd(env, arg1, arg2, arg3, madd_flags, GETPC()); } \
675 uint64_t helper_##op##S(CPUPPCState *env, uint64_t arg1, \
676 uint64_t arg2, uint64_t arg3) \
677 { return do_fmadds(env, arg1, arg2, arg3, madd_flags, GETPC()); }
678
679 #define MADD_FLGS 0
680 #define MSUB_FLGS float_muladd_negate_c
681 #define NMADD_FLGS float_muladd_negate_result
682 #define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
683
FPU_FMADD(FMADD,MADD_FLGS)684 FPU_FMADD(FMADD, MADD_FLGS)
685 FPU_FMADD(FNMADD, NMADD_FLGS)
686 FPU_FMADD(FMSUB, MSUB_FLGS)
687 FPU_FMADD(FNMSUB, NMSUB_FLGS)
688
689 /* frsp - frsp. */
690 static uint64_t do_frsp(CPUPPCState *env, uint64_t arg, uintptr_t retaddr)
691 {
692 float32 f32 = float64_to_float32(arg, &env->fp_status);
693 int flags = get_float_exception_flags(&env->fp_status);
694
695 if (unlikely(flags & float_flag_invalid_snan)) {
696 float_invalid_op_vxsnan(env, retaddr);
697 }
698 return helper_todouble(f32);
699 }
700
helper_frsp(CPUPPCState * env,uint64_t arg)701 uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
702 {
703 return do_frsp(env, arg, GETPC());
704 }
705
float_invalid_op_sqrt(CPUPPCState * env,int flags,bool set_fpcc,uintptr_t retaddr)706 static void float_invalid_op_sqrt(CPUPPCState *env, int flags,
707 bool set_fpcc, uintptr_t retaddr)
708 {
709 if (unlikely(flags & float_flag_invalid_sqrt)) {
710 float_invalid_op_vxsqrt(env, set_fpcc, retaddr);
711 } else if (unlikely(flags & float_flag_invalid_snan)) {
712 float_invalid_op_vxsnan(env, retaddr);
713 }
714 }
715
716 #define FPU_FSQRT(name, op) \
717 float64 helper_##name(CPUPPCState *env, float64 arg) \
718 { \
719 float64 ret = op(arg, &env->fp_status); \
720 int flags = get_float_exception_flags(&env->fp_status); \
721 \
722 if (unlikely(flags & float_flag_invalid)) { \
723 float_invalid_op_sqrt(env, flags, 1, GETPC()); \
724 } \
725 \
726 return ret; \
727 }
728
FPU_FSQRT(FSQRT,float64_sqrt)729 FPU_FSQRT(FSQRT, float64_sqrt)
730 FPU_FSQRT(FSQRTS, float64r32_sqrt)
731
732 #define FPU_FRE(name, op) \
733 float64 helper_##name(CPUPPCState *env, float64 arg) \
734 { \
735 /* "Estimate" the reciprocal with actual division. */ \
736 float64 ret = op(float64_one, arg, &env->fp_status); \
737 int flags = get_float_exception_flags(&env->fp_status); \
738 \
739 if (unlikely(flags & float_flag_invalid_snan)) { \
740 float_invalid_op_vxsnan(env, GETPC()); \
741 } \
742 if (unlikely(flags & float_flag_divbyzero)) { \
743 float_zero_divide_excp(env, GETPC()); \
744 /* For FPSCR.ZE == 0, the result is 1/2. */ \
745 ret = float64_set_sign(float64_half, float64_is_neg(arg)); \
746 } \
747 \
748 return ret; \
749 }
750
751 #define FPU_FRSQRTE(name, op) \
752 float64 helper_##name(CPUPPCState *env, float64 arg) \
753 { \
754 /* "Estimate" the reciprocal with actual division. */ \
755 float64 rets = float64_sqrt(arg, &env->fp_status); \
756 float64 retd = op(float64_one, rets, &env->fp_status); \
757 int flags = get_float_exception_flags(&env->fp_status); \
758 \
759 if (unlikely(flags & float_flag_invalid)) { \
760 float_invalid_op_sqrt(env, flags, 1, GETPC()); \
761 } \
762 if (unlikely(flags & float_flag_divbyzero)) { \
763 /* Reciprocal of (square root of) zero. */ \
764 float_zero_divide_excp(env, GETPC()); \
765 } \
766 \
767 return retd; \
768 }
769
770 #define FPU_HELPER(name, op, flags_handler) \
771 float64 helper_##name(CPUPPCState *env, float64 arg1, float64 arg2) \
772 { \
773 float64 ret = op(arg1, arg2, &env->fp_status); \
774 int flags = get_float_exception_flags(&env->fp_status); \
775 uintptr_t ra = GETPC(); \
776 flags_handler(env, flags, ra); \
777 return ret; \
778 }
779
780 FPU_FRE(FRE, float64_div)
781 FPU_FRE(FRES, float64r32_div)
782 FPU_FRSQRTE(FRSQRTE, float64_div)
783 FPU_FRSQRTE(FRSQRTES, float64r32_div)
784 FPU_HELPER(FADD, float64_add, addsub_flags_handler)
785 FPU_HELPER(FADDS, float64r32_add, addsub_flags_handler)
786 FPU_HELPER(FSUB, float64_sub, addsub_flags_handler)
787 FPU_HELPER(FSUBS, float64r32_sub, addsub_flags_handler)
788 FPU_HELPER(FMUL, float64_mul, mul_flags_handler)
789 FPU_HELPER(FMULS, float64r32_mul, mul_flags_handler)
790 FPU_HELPER(FDIV, float64_div, div_flags_handler)
791 FPU_HELPER(FDIVS, float64r32_div, div_flags_handler)
792
793 /* fsel - fsel. */
794 uint64_t helper_FSEL(uint64_t a, uint64_t b, uint64_t c)
795 {
796 CPU_DoubleU fa;
797
798 fa.ll = a;
799
800 if ((!float64_is_neg(fa.d) || float64_is_zero(fa.d)) &&
801 !float64_is_any_nan(fa.d)) {
802 return c;
803 } else {
804 return b;
805 }
806 }
807
helper_FTDIV(uint64_t fra,uint64_t frb)808 uint32_t helper_FTDIV(uint64_t fra, uint64_t frb)
809 {
810 int fe_flag = 0;
811 int fg_flag = 0;
812
813 if (unlikely(float64_is_infinity(fra) ||
814 float64_is_infinity(frb) ||
815 float64_is_zero(frb))) {
816 fe_flag = 1;
817 fg_flag = 1;
818 } else {
819 int e_a = ppc_float64_get_unbiased_exp(fra);
820 int e_b = ppc_float64_get_unbiased_exp(frb);
821
822 if (unlikely(float64_is_any_nan(fra) ||
823 float64_is_any_nan(frb))) {
824 fe_flag = 1;
825 } else if ((e_b <= -1022) || (e_b >= 1021)) {
826 fe_flag = 1;
827 } else if (!float64_is_zero(fra) &&
828 (((e_a - e_b) >= 1023) ||
829 ((e_a - e_b) <= -1021) ||
830 (e_a <= -970))) {
831 fe_flag = 1;
832 }
833
834 if (unlikely(float64_is_zero_or_denormal(frb))) {
835 /* XB is not zero because of the above check and */
836 /* so must be denormalized. */
837 fg_flag = 1;
838 }
839 }
840
841 return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
842 }
843
helper_FTSQRT(uint64_t frb)844 uint32_t helper_FTSQRT(uint64_t frb)
845 {
846 int fe_flag = 0;
847 int fg_flag = 0;
848
849 if (unlikely(float64_is_infinity(frb) || float64_is_zero(frb))) {
850 fe_flag = 1;
851 fg_flag = 1;
852 } else {
853 int e_b = ppc_float64_get_unbiased_exp(frb);
854
855 if (unlikely(float64_is_any_nan(frb))) {
856 fe_flag = 1;
857 } else if (unlikely(float64_is_zero(frb))) {
858 fe_flag = 1;
859 } else if (unlikely(float64_is_neg(frb))) {
860 fe_flag = 1;
861 } else if (!float64_is_zero(frb) && (e_b <= (-1022 + 52))) {
862 fe_flag = 1;
863 }
864
865 if (unlikely(float64_is_zero_or_denormal(frb))) {
866 /* XB is not zero because of the above check and */
867 /* therefore must be denormalized. */
868 fg_flag = 1;
869 }
870 }
871
872 return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
873 }
874
helper_fcmpu(CPUPPCState * env,uint64_t arg1,uint64_t arg2,uint32_t crfD)875 void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
876 uint32_t crfD)
877 {
878 CPU_DoubleU farg1, farg2;
879 uint32_t ret = 0;
880
881 farg1.ll = arg1;
882 farg2.ll = arg2;
883
884 if (unlikely(float64_is_any_nan(farg1.d) ||
885 float64_is_any_nan(farg2.d))) {
886 ret = 0x01UL;
887 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
888 ret = 0x08UL;
889 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
890 ret = 0x04UL;
891 } else {
892 ret = 0x02UL;
893 }
894
895 env->fpscr &= ~FP_FPCC;
896 env->fpscr |= ret << FPSCR_FPCC;
897 env->crf[crfD] = ret;
898 if (unlikely(ret == 0x01UL
899 && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
900 float64_is_signaling_nan(farg2.d, &env->fp_status)))) {
901 /* sNaN comparison */
902 float_invalid_op_vxsnan(env, GETPC());
903 }
904 }
905
helper_fcmpo(CPUPPCState * env,uint64_t arg1,uint64_t arg2,uint32_t crfD)906 void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
907 uint32_t crfD)
908 {
909 CPU_DoubleU farg1, farg2;
910 uint32_t ret = 0;
911
912 farg1.ll = arg1;
913 farg2.ll = arg2;
914
915 if (unlikely(float64_is_any_nan(farg1.d) ||
916 float64_is_any_nan(farg2.d))) {
917 ret = 0x01UL;
918 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
919 ret = 0x08UL;
920 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
921 ret = 0x04UL;
922 } else {
923 ret = 0x02UL;
924 }
925
926 env->fpscr &= ~FP_FPCC;
927 env->fpscr |= ret << FPSCR_FPCC;
928 env->crf[crfD] = (uint32_t) ret;
929 if (unlikely(ret == 0x01UL)) {
930 float_invalid_op_vxvc(env, 1, GETPC());
931 if (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
932 float64_is_signaling_nan(farg2.d, &env->fp_status)) {
933 /* sNaN comparison */
934 float_invalid_op_vxsnan(env, GETPC());
935 }
936 }
937 }
938
939 /* Single-precision floating-point conversions */
efscfsi(CPUPPCState * env,uint32_t val)940 static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val)
941 {
942 CPU_FloatU u;
943
944 u.f = int32_to_float32(val, &env->vec_status);
945
946 return u.l;
947 }
948
efscfui(CPUPPCState * env,uint32_t val)949 static inline uint32_t efscfui(CPUPPCState *env, uint32_t val)
950 {
951 CPU_FloatU u;
952
953 u.f = uint32_to_float32(val, &env->vec_status);
954
955 return u.l;
956 }
957
efsctsi(CPUPPCState * env,uint32_t val)958 static inline int32_t efsctsi(CPUPPCState *env, uint32_t val)
959 {
960 CPU_FloatU u;
961
962 u.l = val;
963 /* NaN are not treated the same way IEEE 754 does */
964 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
965 return 0;
966 }
967
968 return float32_to_int32(u.f, &env->vec_status);
969 }
970
efsctui(CPUPPCState * env,uint32_t val)971 static inline uint32_t efsctui(CPUPPCState *env, uint32_t val)
972 {
973 CPU_FloatU u;
974
975 u.l = val;
976 /* NaN are not treated the same way IEEE 754 does */
977 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
978 return 0;
979 }
980
981 return float32_to_uint32(u.f, &env->vec_status);
982 }
983
efsctsiz(CPUPPCState * env,uint32_t val)984 static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val)
985 {
986 CPU_FloatU u;
987
988 u.l = val;
989 /* NaN are not treated the same way IEEE 754 does */
990 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
991 return 0;
992 }
993
994 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
995 }
996
efsctuiz(CPUPPCState * env,uint32_t val)997 static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val)
998 {
999 CPU_FloatU u;
1000
1001 u.l = val;
1002 /* NaN are not treated the same way IEEE 754 does */
1003 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1004 return 0;
1005 }
1006
1007 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
1008 }
1009
efscfsf(CPUPPCState * env,uint32_t val)1010 static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val)
1011 {
1012 CPU_FloatU u;
1013 float32 tmp;
1014
1015 u.f = int32_to_float32(val, &env->vec_status);
1016 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
1017 u.f = float32_div(u.f, tmp, &env->vec_status);
1018
1019 return u.l;
1020 }
1021
efscfuf(CPUPPCState * env,uint32_t val)1022 static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val)
1023 {
1024 CPU_FloatU u;
1025 float32 tmp;
1026
1027 u.f = uint32_to_float32(val, &env->vec_status);
1028 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1029 u.f = float32_div(u.f, tmp, &env->vec_status);
1030
1031 return u.l;
1032 }
1033
efsctsf(CPUPPCState * env,uint32_t val)1034 static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val)
1035 {
1036 CPU_FloatU u;
1037 float32 tmp;
1038
1039 u.l = val;
1040 /* NaN are not treated the same way IEEE 754 does */
1041 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1042 return 0;
1043 }
1044 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1045 u.f = float32_mul(u.f, tmp, &env->vec_status);
1046
1047 return float32_to_int32(u.f, &env->vec_status);
1048 }
1049
efsctuf(CPUPPCState * env,uint32_t val)1050 static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val)
1051 {
1052 CPU_FloatU u;
1053 float32 tmp;
1054
1055 u.l = val;
1056 /* NaN are not treated the same way IEEE 754 does */
1057 if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) {
1058 return 0;
1059 }
1060 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
1061 u.f = float32_mul(u.f, tmp, &env->vec_status);
1062
1063 return float32_to_uint32(u.f, &env->vec_status);
1064 }
1065
1066 #define HELPER_SPE_SINGLE_CONV(name) \
1067 uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \
1068 { \
1069 return e##name(env, val); \
1070 }
1071 /* efscfsi */
1072 HELPER_SPE_SINGLE_CONV(fscfsi);
1073 /* efscfui */
1074 HELPER_SPE_SINGLE_CONV(fscfui);
1075 /* efscfuf */
1076 HELPER_SPE_SINGLE_CONV(fscfuf);
1077 /* efscfsf */
1078 HELPER_SPE_SINGLE_CONV(fscfsf);
1079 /* efsctsi */
1080 HELPER_SPE_SINGLE_CONV(fsctsi);
1081 /* efsctui */
1082 HELPER_SPE_SINGLE_CONV(fsctui);
1083 /* efsctsiz */
1084 HELPER_SPE_SINGLE_CONV(fsctsiz);
1085 /* efsctuiz */
1086 HELPER_SPE_SINGLE_CONV(fsctuiz);
1087 /* efsctsf */
1088 HELPER_SPE_SINGLE_CONV(fsctsf);
1089 /* efsctuf */
1090 HELPER_SPE_SINGLE_CONV(fsctuf);
1091
1092 #define HELPER_SPE_VECTOR_CONV(name) \
1093 uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \
1094 { \
1095 return ((uint64_t)e##name(env, val >> 32) << 32) | \
1096 (uint64_t)e##name(env, val); \
1097 }
1098 /* evfscfsi */
1099 HELPER_SPE_VECTOR_CONV(fscfsi);
1100 /* evfscfui */
1101 HELPER_SPE_VECTOR_CONV(fscfui);
1102 /* evfscfuf */
1103 HELPER_SPE_VECTOR_CONV(fscfuf);
1104 /* evfscfsf */
1105 HELPER_SPE_VECTOR_CONV(fscfsf);
1106 /* evfsctsi */
1107 HELPER_SPE_VECTOR_CONV(fsctsi);
1108 /* evfsctui */
1109 HELPER_SPE_VECTOR_CONV(fsctui);
1110 /* evfsctsiz */
1111 HELPER_SPE_VECTOR_CONV(fsctsiz);
1112 /* evfsctuiz */
1113 HELPER_SPE_VECTOR_CONV(fsctuiz);
1114 /* evfsctsf */
1115 HELPER_SPE_VECTOR_CONV(fsctsf);
1116 /* evfsctuf */
1117 HELPER_SPE_VECTOR_CONV(fsctuf);
1118
1119 /* Single-precision floating-point arithmetic */
efsadd(CPUPPCState * env,uint32_t op1,uint32_t op2)1120 static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2)
1121 {
1122 CPU_FloatU u1, u2;
1123
1124 u1.l = op1;
1125 u2.l = op2;
1126 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
1127 return u1.l;
1128 }
1129
efssub(CPUPPCState * env,uint32_t op1,uint32_t op2)1130 static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2)
1131 {
1132 CPU_FloatU u1, u2;
1133
1134 u1.l = op1;
1135 u2.l = op2;
1136 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
1137 return u1.l;
1138 }
1139
efsmul(CPUPPCState * env,uint32_t op1,uint32_t op2)1140 static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2)
1141 {
1142 CPU_FloatU u1, u2;
1143
1144 u1.l = op1;
1145 u2.l = op2;
1146 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
1147 return u1.l;
1148 }
1149
efsdiv(CPUPPCState * env,uint32_t op1,uint32_t op2)1150 static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2)
1151 {
1152 CPU_FloatU u1, u2;
1153
1154 u1.l = op1;
1155 u2.l = op2;
1156 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
1157 return u1.l;
1158 }
1159
1160 #define HELPER_SPE_SINGLE_ARITH(name) \
1161 uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
1162 { \
1163 return e##name(env, op1, op2); \
1164 }
1165 /* efsadd */
1166 HELPER_SPE_SINGLE_ARITH(fsadd);
1167 /* efssub */
1168 HELPER_SPE_SINGLE_ARITH(fssub);
1169 /* efsmul */
1170 HELPER_SPE_SINGLE_ARITH(fsmul);
1171 /* efsdiv */
1172 HELPER_SPE_SINGLE_ARITH(fsdiv);
1173
1174 #define HELPER_SPE_VECTOR_ARITH(name) \
1175 uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
1176 { \
1177 return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \
1178 (uint64_t)e##name(env, op1, op2); \
1179 }
1180 /* evfsadd */
1181 HELPER_SPE_VECTOR_ARITH(fsadd);
1182 /* evfssub */
1183 HELPER_SPE_VECTOR_ARITH(fssub);
1184 /* evfsmul */
1185 HELPER_SPE_VECTOR_ARITH(fsmul);
1186 /* evfsdiv */
1187 HELPER_SPE_VECTOR_ARITH(fsdiv);
1188
1189 /* Single-precision floating-point comparisons */
efscmplt(CPUPPCState * env,uint32_t op1,uint32_t op2)1190 static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1191 {
1192 CPU_FloatU u1, u2;
1193
1194 u1.l = op1;
1195 u2.l = op2;
1196 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
1197 }
1198
efscmpgt(CPUPPCState * env,uint32_t op1,uint32_t op2)1199 static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1200 {
1201 CPU_FloatU u1, u2;
1202
1203 u1.l = op1;
1204 u2.l = op2;
1205 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
1206 }
1207
efscmpeq(CPUPPCState * env,uint32_t op1,uint32_t op2)1208 static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
1209 {
1210 CPU_FloatU u1, u2;
1211
1212 u1.l = op1;
1213 u2.l = op2;
1214 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
1215 }
1216
efststlt(CPUPPCState * env,uint32_t op1,uint32_t op2)1217 static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1218 {
1219 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
1220 return efscmplt(env, op1, op2);
1221 }
1222
efststgt(CPUPPCState * env,uint32_t op1,uint32_t op2)1223 static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2)
1224 {
1225 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
1226 return efscmpgt(env, op1, op2);
1227 }
1228
efststeq(CPUPPCState * env,uint32_t op1,uint32_t op2)1229 static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2)
1230 {
1231 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
1232 return efscmpeq(env, op1, op2);
1233 }
1234
1235 #define HELPER_SINGLE_SPE_CMP(name) \
1236 uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \
1237 { \
1238 return e##name(env, op1, op2); \
1239 }
1240 /* efststlt */
1241 HELPER_SINGLE_SPE_CMP(fststlt);
1242 /* efststgt */
1243 HELPER_SINGLE_SPE_CMP(fststgt);
1244 /* efststeq */
1245 HELPER_SINGLE_SPE_CMP(fststeq);
1246 /* efscmplt */
1247 HELPER_SINGLE_SPE_CMP(fscmplt);
1248 /* efscmpgt */
1249 HELPER_SINGLE_SPE_CMP(fscmpgt);
1250 /* efscmpeq */
1251 HELPER_SINGLE_SPE_CMP(fscmpeq);
1252
evcmp_merge(int t0,int t1)1253 static inline uint32_t evcmp_merge(int t0, int t1)
1254 {
1255 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
1256 }
1257
1258 #define HELPER_VECTOR_SPE_CMP(name) \
1259 uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \
1260 { \
1261 return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \
1262 e##name(env, op1, op2)); \
1263 }
1264 /* evfststlt */
1265 HELPER_VECTOR_SPE_CMP(fststlt);
1266 /* evfststgt */
1267 HELPER_VECTOR_SPE_CMP(fststgt);
1268 /* evfststeq */
1269 HELPER_VECTOR_SPE_CMP(fststeq);
1270 /* evfscmplt */
1271 HELPER_VECTOR_SPE_CMP(fscmplt);
1272 /* evfscmpgt */
1273 HELPER_VECTOR_SPE_CMP(fscmpgt);
1274 /* evfscmpeq */
1275 HELPER_VECTOR_SPE_CMP(fscmpeq);
1276
1277 /* Double-precision floating-point conversion */
helper_efdcfsi(CPUPPCState * env,uint32_t val)1278 uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val)
1279 {
1280 CPU_DoubleU u;
1281
1282 u.d = int32_to_float64(val, &env->vec_status);
1283
1284 return u.ll;
1285 }
1286
helper_efdcfsid(CPUPPCState * env,uint64_t val)1287 uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val)
1288 {
1289 CPU_DoubleU u;
1290
1291 u.d = int64_to_float64(val, &env->vec_status);
1292
1293 return u.ll;
1294 }
1295
helper_efdcfui(CPUPPCState * env,uint32_t val)1296 uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val)
1297 {
1298 CPU_DoubleU u;
1299
1300 u.d = uint32_to_float64(val, &env->vec_status);
1301
1302 return u.ll;
1303 }
1304
helper_efdcfuid(CPUPPCState * env,uint64_t val)1305 uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val)
1306 {
1307 CPU_DoubleU u;
1308
1309 u.d = uint64_to_float64(val, &env->vec_status);
1310
1311 return u.ll;
1312 }
1313
helper_efdctsi(CPUPPCState * env,uint64_t val)1314 uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val)
1315 {
1316 CPU_DoubleU u;
1317
1318 u.ll = val;
1319 /* NaN are not treated the same way IEEE 754 does */
1320 if (unlikely(float64_is_any_nan(u.d))) {
1321 return 0;
1322 }
1323
1324 return float64_to_int32(u.d, &env->vec_status);
1325 }
1326
helper_efdctui(CPUPPCState * env,uint64_t val)1327 uint32_t helper_efdctui(CPUPPCState *env, uint64_t val)
1328 {
1329 CPU_DoubleU u;
1330
1331 u.ll = val;
1332 /* NaN are not treated the same way IEEE 754 does */
1333 if (unlikely(float64_is_any_nan(u.d))) {
1334 return 0;
1335 }
1336
1337 return float64_to_uint32(u.d, &env->vec_status);
1338 }
1339
helper_efdctsiz(CPUPPCState * env,uint64_t val)1340 uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val)
1341 {
1342 CPU_DoubleU u;
1343
1344 u.ll = val;
1345 /* NaN are not treated the same way IEEE 754 does */
1346 if (unlikely(float64_is_any_nan(u.d))) {
1347 return 0;
1348 }
1349
1350 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
1351 }
1352
helper_efdctsidz(CPUPPCState * env,uint64_t val)1353 uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val)
1354 {
1355 CPU_DoubleU u;
1356
1357 u.ll = val;
1358 /* NaN are not treated the same way IEEE 754 does */
1359 if (unlikely(float64_is_any_nan(u.d))) {
1360 return 0;
1361 }
1362
1363 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
1364 }
1365
helper_efdctuiz(CPUPPCState * env,uint64_t val)1366 uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val)
1367 {
1368 CPU_DoubleU u;
1369
1370 u.ll = val;
1371 /* NaN are not treated the same way IEEE 754 does */
1372 if (unlikely(float64_is_any_nan(u.d))) {
1373 return 0;
1374 }
1375
1376 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
1377 }
1378
helper_efdctuidz(CPUPPCState * env,uint64_t val)1379 uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val)
1380 {
1381 CPU_DoubleU u;
1382
1383 u.ll = val;
1384 /* NaN are not treated the same way IEEE 754 does */
1385 if (unlikely(float64_is_any_nan(u.d))) {
1386 return 0;
1387 }
1388
1389 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
1390 }
1391
helper_efdcfsf(CPUPPCState * env,uint32_t val)1392 uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val)
1393 {
1394 CPU_DoubleU u;
1395 float64 tmp;
1396
1397 u.d = int32_to_float64(val, &env->vec_status);
1398 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
1399 u.d = float64_div(u.d, tmp, &env->vec_status);
1400
1401 return u.ll;
1402 }
1403
helper_efdcfuf(CPUPPCState * env,uint32_t val)1404 uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val)
1405 {
1406 CPU_DoubleU u;
1407 float64 tmp;
1408
1409 u.d = uint32_to_float64(val, &env->vec_status);
1410 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
1411 u.d = float64_div(u.d, tmp, &env->vec_status);
1412
1413 return u.ll;
1414 }
1415
helper_efdctsf(CPUPPCState * env,uint64_t val)1416 uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val)
1417 {
1418 CPU_DoubleU u;
1419 float64 tmp;
1420
1421 u.ll = val;
1422 /* NaN are not treated the same way IEEE 754 does */
1423 if (unlikely(float64_is_any_nan(u.d))) {
1424 return 0;
1425 }
1426 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
1427 u.d = float64_mul(u.d, tmp, &env->vec_status);
1428
1429 return float64_to_int32(u.d, &env->vec_status);
1430 }
1431
helper_efdctuf(CPUPPCState * env,uint64_t val)1432 uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val)
1433 {
1434 CPU_DoubleU u;
1435 float64 tmp;
1436
1437 u.ll = val;
1438 /* NaN are not treated the same way IEEE 754 does */
1439 if (unlikely(float64_is_any_nan(u.d))) {
1440 return 0;
1441 }
1442 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
1443 u.d = float64_mul(u.d, tmp, &env->vec_status);
1444
1445 return float64_to_uint32(u.d, &env->vec_status);
1446 }
1447
helper_efscfd(CPUPPCState * env,uint64_t val)1448 uint32_t helper_efscfd(CPUPPCState *env, uint64_t val)
1449 {
1450 CPU_DoubleU u1;
1451 CPU_FloatU u2;
1452
1453 u1.ll = val;
1454 u2.f = float64_to_float32(u1.d, &env->vec_status);
1455
1456 return u2.l;
1457 }
1458
helper_efdcfs(CPUPPCState * env,uint32_t val)1459 uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val)
1460 {
1461 CPU_DoubleU u2;
1462 CPU_FloatU u1;
1463
1464 u1.l = val;
1465 u2.d = float32_to_float64(u1.f, &env->vec_status);
1466
1467 return u2.ll;
1468 }
1469
1470 /* Double precision fixed-point arithmetic */
helper_efdadd(CPUPPCState * env,uint64_t op1,uint64_t op2)1471 uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2)
1472 {
1473 CPU_DoubleU u1, u2;
1474
1475 u1.ll = op1;
1476 u2.ll = op2;
1477 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
1478 return u1.ll;
1479 }
1480
helper_efdsub(CPUPPCState * env,uint64_t op1,uint64_t op2)1481 uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2)
1482 {
1483 CPU_DoubleU u1, u2;
1484
1485 u1.ll = op1;
1486 u2.ll = op2;
1487 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
1488 return u1.ll;
1489 }
1490
helper_efdmul(CPUPPCState * env,uint64_t op1,uint64_t op2)1491 uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2)
1492 {
1493 CPU_DoubleU u1, u2;
1494
1495 u1.ll = op1;
1496 u2.ll = op2;
1497 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
1498 return u1.ll;
1499 }
1500
helper_efddiv(CPUPPCState * env,uint64_t op1,uint64_t op2)1501 uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2)
1502 {
1503 CPU_DoubleU u1, u2;
1504
1505 u1.ll = op1;
1506 u2.ll = op2;
1507 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
1508 return u1.ll;
1509 }
1510
1511 /* Double precision floating point helpers */
helper_efdtstlt(CPUPPCState * env,uint64_t op1,uint64_t op2)1512 uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1513 {
1514 CPU_DoubleU u1, u2;
1515
1516 u1.ll = op1;
1517 u2.ll = op2;
1518 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
1519 }
1520
helper_efdtstgt(CPUPPCState * env,uint64_t op1,uint64_t op2)1521 uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1522 {
1523 CPU_DoubleU u1, u2;
1524
1525 u1.ll = op1;
1526 u2.ll = op2;
1527 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
1528 }
1529
helper_efdtsteq(CPUPPCState * env,uint64_t op1,uint64_t op2)1530 uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2)
1531 {
1532 CPU_DoubleU u1, u2;
1533
1534 u1.ll = op1;
1535 u2.ll = op2;
1536 return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
1537 }
1538
helper_efdcmplt(CPUPPCState * env,uint64_t op1,uint64_t op2)1539 uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1540 {
1541 /* XXX: TODO: test special values (NaN, infinites, ...) */
1542 return helper_efdtstlt(env, op1, op2);
1543 }
1544
helper_efdcmpgt(CPUPPCState * env,uint64_t op1,uint64_t op2)1545 uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2)
1546 {
1547 /* XXX: TODO: test special values (NaN, infinites, ...) */
1548 return helper_efdtstgt(env, op1, op2);
1549 }
1550
helper_efdcmpeq(CPUPPCState * env,uint64_t op1,uint64_t op2)1551 uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
1552 {
1553 /* XXX: TODO: test special values (NaN, infinites, ...) */
1554 return helper_efdtsteq(env, op1, op2);
1555 }
1556
1557 #define float64_to_float64(x, env) x
1558
1559
1560 /*
1561 * VSX_ADD_SUB - VSX floating point add/subtract
1562 * name - instruction mnemonic
1563 * op - operation (add or sub)
1564 * nels - number of elements (1, 2 or 4)
1565 * tp - type (float32 or float64)
1566 * fld - vsr_t field (VsrD(*) or VsrW(*))
1567 * sfifprf - set FI and FPRF
1568 */
1569 #define VSX_ADD_SUB(name, op, nels, tp, fld, sfifprf, r2sp) \
1570 void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
1571 ppc_vsr_t *xa, ppc_vsr_t *xb) \
1572 { \
1573 ppc_vsr_t t = { }; \
1574 int i; \
1575 \
1576 helper_reset_fpstatus(env); \
1577 \
1578 for (i = 0; i < nels; i++) { \
1579 float_status tstat = env->fp_status; \
1580 set_float_exception_flags(0, &tstat); \
1581 t.fld = tp##_##op(xa->fld, xb->fld, &tstat); \
1582 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1583 \
1584 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1585 float_invalid_op_addsub(env, tstat.float_exception_flags, \
1586 sfifprf, GETPC()); \
1587 } \
1588 \
1589 if (r2sp) { \
1590 t.fld = do_frsp(env, t.fld, GETPC()); \
1591 } \
1592 \
1593 if (sfifprf) { \
1594 helper_compute_fprf_float64(env, t.fld); \
1595 } \
1596 } \
1597 *xt = t; \
1598 do_float_check_status(env, sfifprf, GETPC()); \
1599 }
1600
1601 VSX_ADD_SUB(XSADDDP, add, 1, float64, VsrD(0), 1, 0)
1602 VSX_ADD_SUB(XSADDSP, add, 1, float64, VsrD(0), 1, 1)
1603 VSX_ADD_SUB(XVADDDP, add, 2, float64, VsrD(i), 0, 0)
1604 VSX_ADD_SUB(XVADDSP, add, 4, float32, VsrW(i), 0, 0)
1605 VSX_ADD_SUB(XSSUBDP, sub, 1, float64, VsrD(0), 1, 0)
1606 VSX_ADD_SUB(XSSUBSP, sub, 1, float64, VsrD(0), 1, 1)
1607 VSX_ADD_SUB(XVSUBDP, sub, 2, float64, VsrD(i), 0, 0)
1608 VSX_ADD_SUB(XVSUBSP, sub, 4, float32, VsrW(i), 0, 0)
1609
helper_xsaddqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xa,ppc_vsr_t * xb)1610 void helper_xsaddqp(CPUPPCState *env, uint32_t opcode,
1611 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
1612 {
1613 ppc_vsr_t t = *xt;
1614 float_status tstat;
1615
1616 helper_reset_fpstatus(env);
1617
1618 tstat = env->fp_status;
1619 if (unlikely(Rc(opcode) != 0)) {
1620 tstat.float_rounding_mode = float_round_to_odd;
1621 }
1622
1623 set_float_exception_flags(0, &tstat);
1624 t.f128 = float128_add(xa->f128, xb->f128, &tstat);
1625 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
1626
1627 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
1628 float_invalid_op_addsub(env, tstat.float_exception_flags, 1, GETPC());
1629 }
1630
1631 helper_compute_fprf_float128(env, t.f128);
1632
1633 *xt = t;
1634 do_float_check_status(env, true, GETPC());
1635 }
1636
1637 /*
1638 * VSX_MUL - VSX floating point multiply
1639 * op - instruction mnemonic
1640 * nels - number of elements (1, 2 or 4)
1641 * tp - type (float32 or float64)
1642 * fld - vsr_t field (VsrD(*) or VsrW(*))
1643 * sfifprf - set FI and FPRF
1644 */
1645 #define VSX_MUL(op, nels, tp, fld, sfifprf, r2sp) \
1646 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
1647 ppc_vsr_t *xa, ppc_vsr_t *xb) \
1648 { \
1649 ppc_vsr_t t = { }; \
1650 int i; \
1651 \
1652 helper_reset_fpstatus(env); \
1653 \
1654 for (i = 0; i < nels; i++) { \
1655 float_status tstat = env->fp_status; \
1656 set_float_exception_flags(0, &tstat); \
1657 t.fld = tp##_mul(xa->fld, xb->fld, &tstat); \
1658 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1659 \
1660 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1661 float_invalid_op_mul(env, tstat.float_exception_flags, \
1662 sfifprf, GETPC()); \
1663 } \
1664 \
1665 if (r2sp) { \
1666 t.fld = do_frsp(env, t.fld, GETPC()); \
1667 } \
1668 \
1669 if (sfifprf) { \
1670 helper_compute_fprf_float64(env, t.fld); \
1671 } \
1672 } \
1673 \
1674 *xt = t; \
1675 do_float_check_status(env, sfifprf, GETPC()); \
1676 }
1677
1678 VSX_MUL(XSMULDP, 1, float64, VsrD(0), 1, 0)
1679 VSX_MUL(XSMULSP, 1, float64, VsrD(0), 1, 1)
1680 VSX_MUL(XVMULDP, 2, float64, VsrD(i), 0, 0)
1681 VSX_MUL(XVMULSP, 4, float32, VsrW(i), 0, 0)
1682
helper_xsmulqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xa,ppc_vsr_t * xb)1683 void helper_xsmulqp(CPUPPCState *env, uint32_t opcode,
1684 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
1685 {
1686 ppc_vsr_t t = *xt;
1687 float_status tstat;
1688
1689 helper_reset_fpstatus(env);
1690 tstat = env->fp_status;
1691 if (unlikely(Rc(opcode) != 0)) {
1692 tstat.float_rounding_mode = float_round_to_odd;
1693 }
1694
1695 set_float_exception_flags(0, &tstat);
1696 t.f128 = float128_mul(xa->f128, xb->f128, &tstat);
1697 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
1698
1699 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
1700 float_invalid_op_mul(env, tstat.float_exception_flags, 1, GETPC());
1701 }
1702 helper_compute_fprf_float128(env, t.f128);
1703
1704 *xt = t;
1705 do_float_check_status(env, true, GETPC());
1706 }
1707
1708 /*
1709 * VSX_DIV - VSX floating point divide
1710 * op - instruction mnemonic
1711 * nels - number of elements (1, 2 or 4)
1712 * tp - type (float32 or float64)
1713 * fld - vsr_t field (VsrD(*) or VsrW(*))
1714 * sfifprf - set FI and FPRF
1715 */
1716 #define VSX_DIV(op, nels, tp, fld, sfifprf, r2sp) \
1717 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
1718 ppc_vsr_t *xa, ppc_vsr_t *xb) \
1719 { \
1720 ppc_vsr_t t = { }; \
1721 int i; \
1722 \
1723 helper_reset_fpstatus(env); \
1724 \
1725 for (i = 0; i < nels; i++) { \
1726 float_status tstat = env->fp_status; \
1727 set_float_exception_flags(0, &tstat); \
1728 t.fld = tp##_div(xa->fld, xb->fld, &tstat); \
1729 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1730 \
1731 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1732 float_invalid_op_div(env, tstat.float_exception_flags, \
1733 sfifprf, GETPC()); \
1734 } \
1735 if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \
1736 float_zero_divide_excp(env, GETPC()); \
1737 } \
1738 \
1739 if (r2sp) { \
1740 t.fld = do_frsp(env, t.fld, GETPC()); \
1741 } \
1742 \
1743 if (sfifprf) { \
1744 helper_compute_fprf_float64(env, t.fld); \
1745 } \
1746 } \
1747 \
1748 *xt = t; \
1749 do_float_check_status(env, sfifprf, GETPC()); \
1750 }
1751
1752 VSX_DIV(XSDIVDP, 1, float64, VsrD(0), 1, 0)
1753 VSX_DIV(XSDIVSP, 1, float64, VsrD(0), 1, 1)
1754 VSX_DIV(XVDIVDP, 2, float64, VsrD(i), 0, 0)
1755 VSX_DIV(XVDIVSP, 4, float32, VsrW(i), 0, 0)
1756
helper_xsdivqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xa,ppc_vsr_t * xb)1757 void helper_xsdivqp(CPUPPCState *env, uint32_t opcode,
1758 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
1759 {
1760 ppc_vsr_t t = *xt;
1761 float_status tstat;
1762
1763 helper_reset_fpstatus(env);
1764 tstat = env->fp_status;
1765 if (unlikely(Rc(opcode) != 0)) {
1766 tstat.float_rounding_mode = float_round_to_odd;
1767 }
1768
1769 set_float_exception_flags(0, &tstat);
1770 t.f128 = float128_div(xa->f128, xb->f128, &tstat);
1771 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
1772
1773 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
1774 float_invalid_op_div(env, tstat.float_exception_flags, 1, GETPC());
1775 }
1776 if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) {
1777 float_zero_divide_excp(env, GETPC());
1778 }
1779
1780 helper_compute_fprf_float128(env, t.f128);
1781 *xt = t;
1782 do_float_check_status(env, true, GETPC());
1783 }
1784
1785 /*
1786 * VSX_RE - VSX floating point reciprocal estimate
1787 * op - instruction mnemonic
1788 * nels - number of elements (1, 2 or 4)
1789 * tp - type (float32 or float64)
1790 * fld - vsr_t field (VsrD(*) or VsrW(*))
1791 * sfifprf - set FI and FPRF
1792 */
1793 #define VSX_RE(op, nels, tp, fld, sfifprf, r2sp) \
1794 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
1795 { \
1796 ppc_vsr_t t = { }; \
1797 int i; \
1798 \
1799 helper_reset_fpstatus(env); \
1800 \
1801 for (i = 0; i < nels; i++) { \
1802 if (unlikely(tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \
1803 float_invalid_op_vxsnan(env, GETPC()); \
1804 } \
1805 t.fld = tp##_div(tp##_one, xb->fld, &env->fp_status); \
1806 \
1807 if (r2sp) { \
1808 t.fld = do_frsp(env, t.fld, GETPC()); \
1809 } \
1810 \
1811 if (sfifprf) { \
1812 helper_compute_fprf_float64(env, t.fld); \
1813 } \
1814 } \
1815 \
1816 *xt = t; \
1817 do_float_check_status(env, sfifprf, GETPC()); \
1818 }
1819
1820 VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0)
1821 VSX_RE(xsresp, 1, float64, VsrD(0), 1, 1)
1822 VSX_RE(xvredp, 2, float64, VsrD(i), 0, 0)
1823 VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0)
1824
1825 /*
1826 * VSX_SQRT - VSX floating point square root
1827 * op - instruction mnemonic
1828 * nels - number of elements (1, 2 or 4)
1829 * tp - type (float32 or float64)
1830 * fld - vsr_t field (VsrD(*) or VsrW(*))
1831 * sfifprf - set FI and FPRF
1832 */
1833 #define VSX_SQRT(op, nels, tp, fld, sfifprf, r2sp) \
1834 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
1835 { \
1836 ppc_vsr_t t = { }; \
1837 int i; \
1838 \
1839 helper_reset_fpstatus(env); \
1840 \
1841 for (i = 0; i < nels; i++) { \
1842 float_status tstat = env->fp_status; \
1843 set_float_exception_flags(0, &tstat); \
1844 t.fld = tp##_sqrt(xb->fld, &tstat); \
1845 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1846 \
1847 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1848 float_invalid_op_sqrt(env, tstat.float_exception_flags, \
1849 sfifprf, GETPC()); \
1850 } \
1851 \
1852 if (r2sp) { \
1853 t.fld = do_frsp(env, t.fld, GETPC()); \
1854 } \
1855 \
1856 if (sfifprf) { \
1857 helper_compute_fprf_float64(env, t.fld); \
1858 } \
1859 } \
1860 \
1861 *xt = t; \
1862 do_float_check_status(env, sfifprf, GETPC()); \
1863 }
1864
1865 VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0)
1866 VSX_SQRT(xssqrtsp, 1, float64, VsrD(0), 1, 1)
1867 VSX_SQRT(xvsqrtdp, 2, float64, VsrD(i), 0, 0)
1868 VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0)
1869
1870 /*
1871 *VSX_RSQRTE - VSX floating point reciprocal square root estimate
1872 * op - instruction mnemonic
1873 * nels - number of elements (1, 2 or 4)
1874 * tp - type (float32 or float64)
1875 * fld - vsr_t field (VsrD(*) or VsrW(*))
1876 * sfifprf - set FI and FPRF
1877 */
1878 #define VSX_RSQRTE(op, nels, tp, fld, sfifprf, r2sp) \
1879 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
1880 { \
1881 ppc_vsr_t t = { }; \
1882 int i; \
1883 \
1884 helper_reset_fpstatus(env); \
1885 \
1886 for (i = 0; i < nels; i++) { \
1887 float_status tstat = env->fp_status; \
1888 set_float_exception_flags(0, &tstat); \
1889 t.fld = tp##_sqrt(xb->fld, &tstat); \
1890 t.fld = tp##_div(tp##_one, t.fld, &tstat); \
1891 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
1892 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
1893 float_invalid_op_sqrt(env, tstat.float_exception_flags, \
1894 sfifprf, GETPC()); \
1895 } \
1896 if (r2sp) { \
1897 t.fld = do_frsp(env, t.fld, GETPC()); \
1898 } \
1899 \
1900 if (sfifprf) { \
1901 helper_compute_fprf_float64(env, t.fld); \
1902 } \
1903 } \
1904 \
1905 *xt = t; \
1906 do_float_check_status(env, sfifprf, GETPC()); \
1907 }
1908
1909 VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0)
1910 VSX_RSQRTE(xsrsqrtesp, 1, float64, VsrD(0), 1, 1)
1911 VSX_RSQRTE(xvrsqrtedp, 2, float64, VsrD(i), 0, 0)
1912 VSX_RSQRTE(xvrsqrtesp, 4, float32, VsrW(i), 0, 0)
1913
1914 /*
1915 * VSX_TDIV - VSX floating point test for divide
1916 * op - instruction mnemonic
1917 * nels - number of elements (1, 2 or 4)
1918 * tp - type (float32 or float64)
1919 * fld - vsr_t field (VsrD(*) or VsrW(*))
1920 * emin - minimum unbiased exponent
1921 * emax - maximum unbiased exponent
1922 * nbits - number of fraction bits
1923 */
1924 #define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \
1925 void helper_##op(CPUPPCState *env, uint32_t opcode, \
1926 ppc_vsr_t *xa, ppc_vsr_t *xb) \
1927 { \
1928 int i; \
1929 int fe_flag = 0; \
1930 int fg_flag = 0; \
1931 \
1932 for (i = 0; i < nels; i++) { \
1933 if (unlikely(tp##_is_infinity(xa->fld) || \
1934 tp##_is_infinity(xb->fld) || \
1935 tp##_is_zero(xb->fld))) { \
1936 fe_flag = 1; \
1937 fg_flag = 1; \
1938 } else { \
1939 int e_a = ppc_##tp##_get_unbiased_exp(xa->fld); \
1940 int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \
1941 \
1942 if (unlikely(tp##_is_any_nan(xa->fld) || \
1943 tp##_is_any_nan(xb->fld))) { \
1944 fe_flag = 1; \
1945 } else if ((e_b <= emin) || (e_b >= (emax - 2))) { \
1946 fe_flag = 1; \
1947 } else if (!tp##_is_zero(xa->fld) && \
1948 (((e_a - e_b) >= emax) || \
1949 ((e_a - e_b) <= (emin + 1)) || \
1950 (e_a <= (emin + nbits)))) { \
1951 fe_flag = 1; \
1952 } \
1953 \
1954 if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \
1955 /* \
1956 * XB is not zero because of the above check and so \
1957 * must be denormalized. \
1958 */ \
1959 fg_flag = 1; \
1960 } \
1961 } \
1962 } \
1963 \
1964 env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
1965 }
1966
1967 VSX_TDIV(xstdivdp, 1, float64, VsrD(0), -1022, 1023, 52)
1968 VSX_TDIV(xvtdivdp, 2, float64, VsrD(i), -1022, 1023, 52)
1969 VSX_TDIV(xvtdivsp, 4, float32, VsrW(i), -126, 127, 23)
1970
1971 /*
1972 * VSX_TSQRT - VSX floating point test for square root
1973 * op - instruction mnemonic
1974 * nels - number of elements (1, 2 or 4)
1975 * tp - type (float32 or float64)
1976 * fld - vsr_t field (VsrD(*) or VsrW(*))
1977 * emin - minimum unbiased exponent
1978 * emax - maximum unbiased exponent
1979 * nbits - number of fraction bits
1980 */
1981 #define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \
1982 void helper_##op(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) \
1983 { \
1984 int i; \
1985 int fe_flag = 0; \
1986 int fg_flag = 0; \
1987 \
1988 for (i = 0; i < nels; i++) { \
1989 if (unlikely(tp##_is_infinity(xb->fld) || \
1990 tp##_is_zero(xb->fld))) { \
1991 fe_flag = 1; \
1992 fg_flag = 1; \
1993 } else { \
1994 int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \
1995 \
1996 if (unlikely(tp##_is_any_nan(xb->fld))) { \
1997 fe_flag = 1; \
1998 } else if (unlikely(tp##_is_zero(xb->fld))) { \
1999 fe_flag = 1; \
2000 } else if (unlikely(tp##_is_neg(xb->fld))) { \
2001 fe_flag = 1; \
2002 } else if (!tp##_is_zero(xb->fld) && \
2003 (e_b <= (emin + nbits))) { \
2004 fe_flag = 1; \
2005 } \
2006 \
2007 if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \
2008 /* \
2009 * XB is not zero because of the above check and \
2010 * therefore must be denormalized. \
2011 */ \
2012 fg_flag = 1; \
2013 } \
2014 } \
2015 } \
2016 \
2017 env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
2018 }
2019
2020 VSX_TSQRT(xstsqrtdp, 1, float64, VsrD(0), -1022, 52)
2021 VSX_TSQRT(xvtsqrtdp, 2, float64, VsrD(i), -1022, 52)
2022 VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23)
2023
2024 /*
2025 * VSX_MADD - VSX floating point muliply/add variations
2026 * op - instruction mnemonic
2027 * nels - number of elements (1, 2 or 4)
2028 * tp - type (float32 or float64)
2029 * fld - vsr_t field (VsrD(*) or VsrW(*))
2030 * maddflgs - flags for the float*muladd routine that control the
2031 * various forms (madd, msub, nmadd, nmsub)
2032 * sfifprf - set FI and FPRF
2033 */
2034 #define VSX_MADD(op, nels, tp, fld, maddflgs, sfifprf) \
2035 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
2036 ppc_vsr_t *s1, ppc_vsr_t *s2, ppc_vsr_t *s3) \
2037 { \
2038 ppc_vsr_t t = { }; \
2039 int i; \
2040 \
2041 helper_reset_fpstatus(env); \
2042 \
2043 for (i = 0; i < nels; i++) { \
2044 float_status tstat = env->fp_status; \
2045 set_float_exception_flags(0, &tstat); \
2046 t.fld = tp##_muladd(s1->fld, s3->fld, s2->fld, maddflgs, &tstat); \
2047 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
2048 \
2049 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
2050 float_invalid_op_madd(env, tstat.float_exception_flags, \
2051 sfifprf, GETPC()); \
2052 } \
2053 \
2054 if (sfifprf) { \
2055 helper_compute_fprf_float64(env, t.fld); \
2056 } \
2057 } \
2058 *xt = t; \
2059 do_float_check_status(env, sfifprf, GETPC()); \
2060 }
2061
2062 VSX_MADD(XSMADDDP, 1, float64, VsrD(0), MADD_FLGS, 1)
2063 VSX_MADD(XSMSUBDP, 1, float64, VsrD(0), MSUB_FLGS, 1)
2064 VSX_MADD(XSNMADDDP, 1, float64, VsrD(0), NMADD_FLGS, 1)
2065 VSX_MADD(XSNMSUBDP, 1, float64, VsrD(0), NMSUB_FLGS, 1)
2066 VSX_MADD(XSMADDSP, 1, float64r32, VsrD(0), MADD_FLGS, 1)
2067 VSX_MADD(XSMSUBSP, 1, float64r32, VsrD(0), MSUB_FLGS, 1)
2068 VSX_MADD(XSNMADDSP, 1, float64r32, VsrD(0), NMADD_FLGS, 1)
2069 VSX_MADD(XSNMSUBSP, 1, float64r32, VsrD(0), NMSUB_FLGS, 1)
2070
2071 VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0)
2072 VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0)
2073 VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0)
2074 VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0)
2075
2076 VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0)
2077 VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0)
2078 VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0)
2079 VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0)
2080
2081 /*
2082 * VSX_MADDQ - VSX floating point quad-precision muliply/add
2083 * op - instruction mnemonic
2084 * maddflgs - flags for the float*muladd routine that control the
2085 * various forms (madd, msub, nmadd, nmsub)
2086 * ro - round to odd
2087 */
2088 #define VSX_MADDQ(op, maddflgs, ro) \
2089 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *s1, ppc_vsr_t *s2,\
2090 ppc_vsr_t *s3) \
2091 { \
2092 ppc_vsr_t t = *xt; \
2093 \
2094 helper_reset_fpstatus(env); \
2095 \
2096 float_status tstat = env->fp_status; \
2097 set_float_exception_flags(0, &tstat); \
2098 if (ro) { \
2099 tstat.float_rounding_mode = float_round_to_odd; \
2100 } \
2101 t.f128 = float128_muladd(s1->f128, s3->f128, s2->f128, maddflgs, &tstat); \
2102 env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
2103 \
2104 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
2105 float_invalid_op_madd(env, tstat.float_exception_flags, \
2106 false, GETPC()); \
2107 } \
2108 \
2109 helper_compute_fprf_float128(env, t.f128); \
2110 *xt = t; \
2111 do_float_check_status(env, true, GETPC()); \
2112 }
2113
2114 VSX_MADDQ(XSMADDQP, MADD_FLGS, 0)
2115 VSX_MADDQ(XSMADDQPO, MADD_FLGS, 1)
2116 VSX_MADDQ(XSMSUBQP, MSUB_FLGS, 0)
2117 VSX_MADDQ(XSMSUBQPO, MSUB_FLGS, 1)
2118 VSX_MADDQ(XSNMADDQP, NMADD_FLGS, 0)
2119 VSX_MADDQ(XSNMADDQPO, NMADD_FLGS, 1)
2120 VSX_MADDQ(XSNMSUBQP, NMSUB_FLGS, 0)
2121 VSX_MADDQ(XSNMSUBQPO, NMSUB_FLGS, 0)
2122
2123 /*
2124 * VSX_SCALAR_CMP - VSX scalar floating point compare
2125 * op - instruction mnemonic
2126 * tp - type
2127 * cmp - comparison operation
2128 * fld - vsr_t field
2129 * svxvc - set VXVC bit
2130 */
2131 #define VSX_SCALAR_CMP(op, tp, cmp, fld, svxvc) \
2132 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
2133 ppc_vsr_t *xa, ppc_vsr_t *xb) \
2134 { \
2135 int flags; \
2136 bool r, vxvc; \
2137 \
2138 helper_reset_fpstatus(env); \
2139 \
2140 if (svxvc) { \
2141 r = tp##_##cmp(xb->fld, xa->fld, &env->fp_status); \
2142 } else { \
2143 r = tp##_##cmp##_quiet(xb->fld, xa->fld, &env->fp_status); \
2144 } \
2145 \
2146 flags = get_float_exception_flags(&env->fp_status); \
2147 if (unlikely(flags & float_flag_invalid)) { \
2148 vxvc = svxvc; \
2149 if (flags & float_flag_invalid_snan) { \
2150 float_invalid_op_vxsnan(env, GETPC()); \
2151 vxvc &= !(env->fpscr & FP_VE); \
2152 } \
2153 if (vxvc) { \
2154 float_invalid_op_vxvc(env, 0, GETPC()); \
2155 } \
2156 } \
2157 \
2158 memset(xt, 0, sizeof(*xt)); \
2159 memset(&xt->fld, -r, sizeof(xt->fld)); \
2160 do_float_check_status(env, false, GETPC()); \
2161 }
2162
2163 VSX_SCALAR_CMP(XSCMPEQDP, float64, eq, VsrD(0), 0)
2164 VSX_SCALAR_CMP(XSCMPGEDP, float64, le, VsrD(0), 1)
2165 VSX_SCALAR_CMP(XSCMPGTDP, float64, lt, VsrD(0), 1)
2166 VSX_SCALAR_CMP(XSCMPEQQP, float128, eq, f128, 0)
2167 VSX_SCALAR_CMP(XSCMPGEQP, float128, le, f128, 1)
2168 VSX_SCALAR_CMP(XSCMPGTQP, float128, lt, f128, 1)
2169
helper_xscmpexpdp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xa,ppc_vsr_t * xb)2170 void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode,
2171 ppc_vsr_t *xa, ppc_vsr_t *xb)
2172 {
2173 int64_t exp_a, exp_b;
2174 uint32_t cc;
2175
2176 exp_a = extract64(xa->VsrD(0), 52, 11);
2177 exp_b = extract64(xb->VsrD(0), 52, 11);
2178
2179 if (unlikely(float64_is_any_nan(xa->VsrD(0)) ||
2180 float64_is_any_nan(xb->VsrD(0)))) {
2181 cc = CRF_SO;
2182 } else {
2183 if (exp_a < exp_b) {
2184 cc = CRF_LT;
2185 } else if (exp_a > exp_b) {
2186 cc = CRF_GT;
2187 } else {
2188 cc = CRF_EQ;
2189 }
2190 }
2191
2192 env->fpscr &= ~FP_FPCC;
2193 env->fpscr |= cc << FPSCR_FPCC;
2194 env->crf[BF(opcode)] = cc;
2195
2196 do_float_check_status(env, false, GETPC());
2197 }
2198
helper_xscmpexpqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xa,ppc_vsr_t * xb)2199 void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode,
2200 ppc_vsr_t *xa, ppc_vsr_t *xb)
2201 {
2202 int64_t exp_a, exp_b;
2203 uint32_t cc;
2204
2205 exp_a = extract64(xa->VsrD(0), 48, 15);
2206 exp_b = extract64(xb->VsrD(0), 48, 15);
2207
2208 if (unlikely(float128_is_any_nan(xa->f128) ||
2209 float128_is_any_nan(xb->f128))) {
2210 cc = CRF_SO;
2211 } else {
2212 if (exp_a < exp_b) {
2213 cc = CRF_LT;
2214 } else if (exp_a > exp_b) {
2215 cc = CRF_GT;
2216 } else {
2217 cc = CRF_EQ;
2218 }
2219 }
2220
2221 env->fpscr &= ~FP_FPCC;
2222 env->fpscr |= cc << FPSCR_FPCC;
2223 env->crf[BF(opcode)] = cc;
2224
2225 do_float_check_status(env, false, GETPC());
2226 }
2227
do_scalar_cmp(CPUPPCState * env,ppc_vsr_t * xa,ppc_vsr_t * xb,int crf_idx,bool ordered)2228 static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb,
2229 int crf_idx, bool ordered)
2230 {
2231 uint32_t cc;
2232 bool vxsnan_flag = false, vxvc_flag = false;
2233
2234 helper_reset_fpstatus(env);
2235
2236 switch (float64_compare(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) {
2237 case float_relation_less:
2238 cc = CRF_LT;
2239 break;
2240 case float_relation_equal:
2241 cc = CRF_EQ;
2242 break;
2243 case float_relation_greater:
2244 cc = CRF_GT;
2245 break;
2246 case float_relation_unordered:
2247 cc = CRF_SO;
2248
2249 if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) ||
2250 float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) {
2251 vxsnan_flag = true;
2252 if (!(env->fpscr & FP_VE) && ordered) {
2253 vxvc_flag = true;
2254 }
2255 } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) ||
2256 float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) {
2257 if (ordered) {
2258 vxvc_flag = true;
2259 }
2260 }
2261
2262 break;
2263 default:
2264 g_assert_not_reached();
2265 }
2266
2267 env->fpscr &= ~FP_FPCC;
2268 env->fpscr |= cc << FPSCR_FPCC;
2269 env->crf[crf_idx] = cc;
2270
2271 if (vxsnan_flag) {
2272 float_invalid_op_vxsnan(env, GETPC());
2273 }
2274 if (vxvc_flag) {
2275 float_invalid_op_vxvc(env, 0, GETPC());
2276 }
2277
2278 do_float_check_status(env, false, GETPC());
2279 }
2280
helper_xscmpodp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xa,ppc_vsr_t * xb)2281 void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2282 ppc_vsr_t *xb)
2283 {
2284 do_scalar_cmp(env, xa, xb, BF(opcode), true);
2285 }
2286
helper_xscmpudp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xa,ppc_vsr_t * xb)2287 void helper_xscmpudp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2288 ppc_vsr_t *xb)
2289 {
2290 do_scalar_cmp(env, xa, xb, BF(opcode), false);
2291 }
2292
do_scalar_cmpq(CPUPPCState * env,ppc_vsr_t * xa,ppc_vsr_t * xb,int crf_idx,bool ordered)2293 static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa,
2294 ppc_vsr_t *xb, int crf_idx, bool ordered)
2295 {
2296 uint32_t cc;
2297 bool vxsnan_flag = false, vxvc_flag = false;
2298
2299 helper_reset_fpstatus(env);
2300
2301 switch (float128_compare(xa->f128, xb->f128, &env->fp_status)) {
2302 case float_relation_less:
2303 cc = CRF_LT;
2304 break;
2305 case float_relation_equal:
2306 cc = CRF_EQ;
2307 break;
2308 case float_relation_greater:
2309 cc = CRF_GT;
2310 break;
2311 case float_relation_unordered:
2312 cc = CRF_SO;
2313
2314 if (float128_is_signaling_nan(xa->f128, &env->fp_status) ||
2315 float128_is_signaling_nan(xb->f128, &env->fp_status)) {
2316 vxsnan_flag = true;
2317 if (!(env->fpscr & FP_VE) && ordered) {
2318 vxvc_flag = true;
2319 }
2320 } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) ||
2321 float128_is_quiet_nan(xb->f128, &env->fp_status)) {
2322 if (ordered) {
2323 vxvc_flag = true;
2324 }
2325 }
2326
2327 break;
2328 default:
2329 g_assert_not_reached();
2330 }
2331
2332 env->fpscr &= ~FP_FPCC;
2333 env->fpscr |= cc << FPSCR_FPCC;
2334 env->crf[crf_idx] = cc;
2335
2336 if (vxsnan_flag) {
2337 float_invalid_op_vxsnan(env, GETPC());
2338 }
2339 if (vxvc_flag) {
2340 float_invalid_op_vxvc(env, 0, GETPC());
2341 }
2342
2343 do_float_check_status(env, false, GETPC());
2344 }
2345
helper_xscmpoqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xa,ppc_vsr_t * xb)2346 void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2347 ppc_vsr_t *xb)
2348 {
2349 do_scalar_cmpq(env, xa, xb, BF(opcode), true);
2350 }
2351
helper_xscmpuqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xa,ppc_vsr_t * xb)2352 void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa,
2353 ppc_vsr_t *xb)
2354 {
2355 do_scalar_cmpq(env, xa, xb, BF(opcode), false);
2356 }
2357
2358 /*
2359 * VSX_MAX_MIN - VSX floating point maximum/minimum
2360 * name - instruction mnemonic
2361 * op - operation (max or min)
2362 * nels - number of elements (1, 2 or 4)
2363 * tp - type (float32 or float64)
2364 * fld - vsr_t field (VsrD(*) or VsrW(*))
2365 */
2366 #define VSX_MAX_MIN(name, op, nels, tp, fld) \
2367 void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
2368 ppc_vsr_t *xa, ppc_vsr_t *xb) \
2369 { \
2370 ppc_vsr_t t = { }; \
2371 int i; \
2372 \
2373 for (i = 0; i < nels; i++) { \
2374 t.fld = tp##_##op(xa->fld, xb->fld, &env->fp_status); \
2375 if (unlikely(tp##_is_signaling_nan(xa->fld, &env->fp_status) || \
2376 tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \
2377 float_invalid_op_vxsnan(env, GETPC()); \
2378 } \
2379 } \
2380 \
2381 *xt = t; \
2382 do_float_check_status(env, false, GETPC()); \
2383 }
2384
2385 VSX_MAX_MIN(XSMAXDP, maxnum, 1, float64, VsrD(0))
2386 VSX_MAX_MIN(XVMAXDP, maxnum, 2, float64, VsrD(i))
2387 VSX_MAX_MIN(XVMAXSP, maxnum, 4, float32, VsrW(i))
2388 VSX_MAX_MIN(XSMINDP, minnum, 1, float64, VsrD(0))
2389 VSX_MAX_MIN(XVMINDP, minnum, 2, float64, VsrD(i))
2390 VSX_MAX_MIN(XVMINSP, minnum, 4, float32, VsrW(i))
2391
2392 #define VSX_MAX_MINC(name, max, tp, fld) \
2393 void helper_##name(CPUPPCState *env, \
2394 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
2395 { \
2396 ppc_vsr_t t = { }; \
2397 bool first; \
2398 \
2399 helper_reset_fpstatus(env); \
2400 \
2401 if (max) { \
2402 first = tp##_le_quiet(xb->fld, xa->fld, &env->fp_status); \
2403 } else { \
2404 first = tp##_lt_quiet(xa->fld, xb->fld, &env->fp_status); \
2405 } \
2406 \
2407 if (first) { \
2408 t.fld = xa->fld; \
2409 } else { \
2410 t.fld = xb->fld; \
2411 if (env->fp_status.float_exception_flags & float_flag_invalid_snan) { \
2412 float_invalid_op_vxsnan(env, GETPC()); \
2413 } \
2414 } \
2415 \
2416 *xt = t; \
2417 }
2418
2419 VSX_MAX_MINC(XSMAXCDP, true, float64, VsrD(0));
2420 VSX_MAX_MINC(XSMINCDP, false, float64, VsrD(0));
2421 VSX_MAX_MINC(XSMAXCQP, true, float128, f128);
2422 VSX_MAX_MINC(XSMINCQP, false, float128, f128);
2423
2424 #define VSX_MAX_MINJ(name, max) \
2425 void helper_##name(CPUPPCState *env, \
2426 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
2427 { \
2428 ppc_vsr_t t = { }; \
2429 bool vxsnan_flag = false, vex_flag = false; \
2430 \
2431 if (unlikely(float64_is_any_nan(xa->VsrD(0)))) { \
2432 if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status)) { \
2433 vxsnan_flag = true; \
2434 } \
2435 t.VsrD(0) = xa->VsrD(0); \
2436 } else if (unlikely(float64_is_any_nan(xb->VsrD(0)))) { \
2437 if (float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \
2438 vxsnan_flag = true; \
2439 } \
2440 t.VsrD(0) = xb->VsrD(0); \
2441 } else if (float64_is_zero(xa->VsrD(0)) && \
2442 float64_is_zero(xb->VsrD(0))) { \
2443 if (max) { \
2444 if (!float64_is_neg(xa->VsrD(0)) || \
2445 !float64_is_neg(xb->VsrD(0))) { \
2446 t.VsrD(0) = 0ULL; \
2447 } else { \
2448 t.VsrD(0) = 0x8000000000000000ULL; \
2449 } \
2450 } else { \
2451 if (float64_is_neg(xa->VsrD(0)) || \
2452 float64_is_neg(xb->VsrD(0))) { \
2453 t.VsrD(0) = 0x8000000000000000ULL; \
2454 } else { \
2455 t.VsrD(0) = 0ULL; \
2456 } \
2457 } \
2458 } else if ((max && \
2459 !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) || \
2460 (!max && \
2461 float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) { \
2462 t.VsrD(0) = xa->VsrD(0); \
2463 } else { \
2464 t.VsrD(0) = xb->VsrD(0); \
2465 } \
2466 \
2467 vex_flag = (env->fpscr & FP_VE) && vxsnan_flag; \
2468 if (vxsnan_flag) { \
2469 float_invalid_op_vxsnan(env, GETPC()); \
2470 } \
2471 if (!vex_flag) { \
2472 *xt = t; \
2473 } \
2474 } \
2475
2476 VSX_MAX_MINJ(XSMAXJDP, 1);
2477 VSX_MAX_MINJ(XSMINJDP, 0);
2478
2479 /*
2480 * VSX_CMP - VSX floating point compare
2481 * op - instruction mnemonic
2482 * nels - number of elements (1, 2 or 4)
2483 * tp - type (float32 or float64)
2484 * fld - vsr_t field (VsrD(*) or VsrW(*))
2485 * cmp - comparison operation
2486 * svxvc - set VXVC bit
2487 * exp - expected result of comparison
2488 */
2489 #define VSX_CMP(op, nels, tp, fld, cmp, svxvc, exp) \
2490 uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
2491 ppc_vsr_t *xa, ppc_vsr_t *xb) \
2492 { \
2493 ppc_vsr_t t = *xt; \
2494 uint32_t crf6 = 0; \
2495 int i; \
2496 int all_true = 1; \
2497 int all_false = 1; \
2498 \
2499 helper_reset_fpstatus(env); \
2500 \
2501 for (i = 0; i < nels; i++) { \
2502 if (unlikely(tp##_is_any_nan(xa->fld) || \
2503 tp##_is_any_nan(xb->fld))) { \
2504 if (tp##_is_signaling_nan(xa->fld, &env->fp_status) || \
2505 tp##_is_signaling_nan(xb->fld, &env->fp_status)) { \
2506 float_invalid_op_vxsnan(env, GETPC()); \
2507 } \
2508 if (svxvc) { \
2509 float_invalid_op_vxvc(env, 0, GETPC()); \
2510 } \
2511 t.fld = 0; \
2512 all_true = 0; \
2513 } else { \
2514 if (tp##_##cmp(xb->fld, xa->fld, &env->fp_status) == exp) { \
2515 t.fld = -1; \
2516 all_false = 0; \
2517 } else { \
2518 t.fld = 0; \
2519 all_true = 0; \
2520 } \
2521 } \
2522 } \
2523 \
2524 *xt = t; \
2525 crf6 = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \
2526 return crf6; \
2527 }
2528
2529 VSX_CMP(XVCMPEQDP, 2, float64, VsrD(i), eq, 0, 1)
2530 VSX_CMP(XVCMPGEDP, 2, float64, VsrD(i), le, 1, 1)
2531 VSX_CMP(XVCMPGTDP, 2, float64, VsrD(i), lt, 1, 1)
2532 VSX_CMP(XVCMPNEDP, 2, float64, VsrD(i), eq, 0, 0)
2533 VSX_CMP(XVCMPEQSP, 4, float32, VsrW(i), eq, 0, 1)
2534 VSX_CMP(XVCMPGESP, 4, float32, VsrW(i), le, 1, 1)
2535 VSX_CMP(XVCMPGTSP, 4, float32, VsrW(i), lt, 1, 1)
2536 VSX_CMP(XVCMPNESP, 4, float32, VsrW(i), eq, 0, 0)
2537
2538 /*
2539 * VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
2540 * op - instruction mnemonic
2541 * nels - number of elements (1, 2 or 4)
2542 * stp - source type (float32 or float64)
2543 * ttp - target type (float32 or float64)
2544 * sfld - source vsr_t field
2545 * tfld - target vsr_t field (f32 or f64)
2546 * sfifprf - set FI and FPRF
2547 */
2548 #define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf) \
2549 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2550 { \
2551 ppc_vsr_t t = { }; \
2552 int i; \
2553 \
2554 helper_reset_fpstatus(env); \
2555 \
2556 for (i = 0; i < nels; i++) { \
2557 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
2558 if (unlikely(stp##_is_signaling_nan(xb->sfld, \
2559 &env->fp_status))) { \
2560 float_invalid_op_vxsnan(env, GETPC()); \
2561 t.tfld = ttp##_snan_to_qnan(t.tfld); \
2562 } \
2563 if (sfifprf) { \
2564 helper_compute_fprf_##ttp(env, t.tfld); \
2565 } \
2566 } \
2567 \
2568 *xt = t; \
2569 do_float_check_status(env, sfifprf, GETPC()); \
2570 }
2571
2572 VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1)
2573 VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0)
2574
2575 #define VSX_CVT_FP_TO_FP2(op, nels, stp, ttp, sfifprf) \
2576 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2577 { \
2578 ppc_vsr_t t = { }; \
2579 int i; \
2580 \
2581 helper_reset_fpstatus(env); \
2582 \
2583 for (i = 0; i < nels; i++) { \
2584 t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \
2585 if (unlikely(stp##_is_signaling_nan(xb->VsrD(i), \
2586 &env->fp_status))) { \
2587 float_invalid_op_vxsnan(env, GETPC()); \
2588 t.VsrW(2 * i) = ttp##_snan_to_qnan(t.VsrW(2 * i)); \
2589 } \
2590 if (sfifprf) { \
2591 helper_compute_fprf_##ttp(env, t.VsrW(2 * i)); \
2592 } \
2593 t.VsrW(2 * i + 1) = t.VsrW(2 * i); \
2594 } \
2595 \
2596 *xt = t; \
2597 do_float_check_status(env, sfifprf, GETPC()); \
2598 }
2599
2600 VSX_CVT_FP_TO_FP2(xvcvdpsp, 2, float64, float32, 0)
2601 VSX_CVT_FP_TO_FP2(xscvdpsp, 1, float64, float32, 1)
2602
2603 /*
2604 * VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion
2605 * op - instruction mnemonic
2606 * nels - number of elements (1, 2 or 4)
2607 * stp - source type (float32 or float64)
2608 * ttp - target type (float32 or float64)
2609 * sfld - source vsr_t field
2610 * tfld - target vsr_t field (f32 or f64)
2611 * sfprf - set FPRF
2612 */
2613 #define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \
2614 void helper_##op(CPUPPCState *env, uint32_t opcode, \
2615 ppc_vsr_t *xt, ppc_vsr_t *xb) \
2616 { \
2617 ppc_vsr_t t = *xt; \
2618 int i; \
2619 \
2620 helper_reset_fpstatus(env); \
2621 \
2622 for (i = 0; i < nels; i++) { \
2623 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
2624 if (unlikely(stp##_is_signaling_nan(xb->sfld, \
2625 &env->fp_status))) { \
2626 float_invalid_op_vxsnan(env, GETPC()); \
2627 t.tfld = ttp##_snan_to_qnan(t.tfld); \
2628 } \
2629 if (sfprf) { \
2630 helper_compute_fprf_##ttp(env, t.tfld); \
2631 } \
2632 } \
2633 \
2634 *xt = t; \
2635 do_float_check_status(env, true, GETPC()); \
2636 }
2637
2638 VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1)
2639
2640 /*
2641 * VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion
2642 * involving one half precision value
2643 * op - instruction mnemonic
2644 * nels - number of elements (1, 2 or 4)
2645 * stp - source type
2646 * ttp - target type
2647 * sfld - source vsr_t field
2648 * tfld - target vsr_t field
2649 * sfifprf - set FI and FPRF
2650 */
2651 #define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfifprf) \
2652 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2653 { \
2654 ppc_vsr_t t = { }; \
2655 int i; \
2656 \
2657 helper_reset_fpstatus(env); \
2658 \
2659 for (i = 0; i < nels; i++) { \
2660 t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status); \
2661 if (unlikely(stp##_is_signaling_nan(xb->sfld, \
2662 &env->fp_status))) { \
2663 float_invalid_op_vxsnan(env, GETPC()); \
2664 t.tfld = ttp##_snan_to_qnan(t.tfld); \
2665 } \
2666 if (sfifprf) { \
2667 helper_compute_fprf_##ttp(env, t.tfld); \
2668 } \
2669 } \
2670 \
2671 *xt = t; \
2672 do_float_check_status(env, sfifprf, GETPC()); \
2673 }
2674
2675 VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1)
2676 VSX_CVT_FP_TO_FP_HP(xscvhpdp, 1, float16, float64, VsrH(3), VsrD(0), 1)
2677 VSX_CVT_FP_TO_FP_HP(xvcvsphp, 4, float32, float16, VsrW(i), VsrH(2 * i + 1), 0)
2678 VSX_CVT_FP_TO_FP_HP(xvcvhpsp, 4, float16, float32, VsrH(2 * i + 1), VsrW(i), 0)
2679
helper_XVCVSPBF16(CPUPPCState * env,ppc_vsr_t * xt,ppc_vsr_t * xb)2680 void helper_XVCVSPBF16(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)
2681 {
2682 ppc_vsr_t t = { };
2683 int i, status;
2684
2685 helper_reset_fpstatus(env);
2686
2687 for (i = 0; i < 4; i++) {
2688 t.VsrH(2 * i + 1) = float32_to_bfloat16(xb->VsrW(i), &env->fp_status);
2689 }
2690
2691 status = get_float_exception_flags(&env->fp_status);
2692 if (unlikely(status & float_flag_invalid_snan)) {
2693 float_invalid_op_vxsnan(env, GETPC());
2694 }
2695
2696 *xt = t;
2697 do_float_check_status(env, false, GETPC());
2698 }
2699
helper_XSCVQPDP(CPUPPCState * env,uint32_t ro,ppc_vsr_t * xt,ppc_vsr_t * xb)2700 void helper_XSCVQPDP(CPUPPCState *env, uint32_t ro, ppc_vsr_t *xt,
2701 ppc_vsr_t *xb)
2702 {
2703 ppc_vsr_t t = { };
2704 float_status tstat;
2705
2706 helper_reset_fpstatus(env);
2707
2708 tstat = env->fp_status;
2709 if (ro != 0) {
2710 tstat.float_rounding_mode = float_round_to_odd;
2711 }
2712
2713 t.VsrD(0) = float128_to_float64(xb->f128, &tstat);
2714 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
2715 if (unlikely(float128_is_signaling_nan(xb->f128, &tstat))) {
2716 float_invalid_op_vxsnan(env, GETPC());
2717 t.VsrD(0) = float64_snan_to_qnan(t.VsrD(0));
2718 }
2719 helper_compute_fprf_float64(env, t.VsrD(0));
2720
2721 *xt = t;
2722 do_float_check_status(env, true, GETPC());
2723 }
2724
helper_xscvdpspn(CPUPPCState * env,uint64_t xb)2725 uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
2726 {
2727 uint64_t result, sign, exp, frac;
2728
2729 helper_reset_fpstatus(env);
2730 float_status tstat = env->fp_status;
2731 set_float_exception_flags(0, &tstat);
2732
2733 sign = extract64(xb, 63, 1);
2734 exp = extract64(xb, 52, 11);
2735 frac = extract64(xb, 0, 52) | 0x10000000000000ULL;
2736
2737 if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) {
2738 /* DP denormal operand. */
2739 /* Exponent override to DP min exp. */
2740 exp = 1;
2741 /* Implicit bit override to 0. */
2742 frac = deposit64(frac, 53, 1, 0);
2743 }
2744
2745 if (unlikely(exp < 897 && frac != 0)) {
2746 /* SP tiny operand. */
2747 if (897 - exp > 63) {
2748 frac = 0;
2749 } else {
2750 /* Denormalize until exp = SP min exp. */
2751 frac >>= (897 - exp);
2752 }
2753 /* Exponent override to SP min exp - 1. */
2754 exp = 896;
2755 }
2756
2757 result = sign << 31;
2758 result |= extract64(exp, 10, 1) << 30;
2759 result |= extract64(exp, 0, 7) << 23;
2760 result |= extract64(frac, 29, 23);
2761
2762 /* hardware replicates result to both words of the doubleword result. */
2763 return (result << 32) | result;
2764 }
2765
helper_XSCVSPDPN(uint64_t xb)2766 uint64_t helper_XSCVSPDPN(uint64_t xb)
2767 {
2768 return helper_todouble(xb >> 32);
2769 }
2770
2771 /*
2772 * VSX_CVT_FP_TO_INT - VSX floating point to integer conversion
2773 * op - instruction mnemonic
2774 * nels - number of elements (1, 2 or 4)
2775 * stp - source type (float32 or float64)
2776 * ttp - target type (int32, uint32, int64 or uint64)
2777 * sfld - source vsr_t field
2778 * tfld - target vsr_t field
2779 * sfi - set FI
2780 * rnan - resulting NaN
2781 */
2782 #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, sfi, rnan) \
2783 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2784 { \
2785 int all_flags = 0; \
2786 ppc_vsr_t t = { }; \
2787 int i, flags; \
2788 \
2789 for (i = 0; i < nels; i++) { \
2790 helper_reset_fpstatus(env); \
2791 t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \
2792 flags = env->fp_status.float_exception_flags; \
2793 all_flags |= flags; \
2794 if (unlikely(flags & float_flag_invalid)) { \
2795 t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC());\
2796 } \
2797 } \
2798 \
2799 *xt = t; \
2800 env->fp_status.float_exception_flags = all_flags; \
2801 do_float_check_status(env, sfi, GETPC()); \
2802 }
2803
2804 VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), true, \
2805 0x8000000000000000ULL)
2806 VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), true, 0ULL)
2807 VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), false, \
2808 0x8000000000000000ULL)
2809 VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), false, \
2810 0ULL)
2811 VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), false, \
2812 0x8000000000000000ULL)
2813 VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), false, \
2814 0x80000000ULL)
2815 VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), \
2816 false, 0ULL)
2817 VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), false, 0U)
2818
2819 #define VSX_CVT_FP_TO_INT128(op, tp, rnan) \
2820 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2821 { \
2822 ppc_vsr_t t; \
2823 int flags; \
2824 \
2825 helper_reset_fpstatus(env); \
2826 t.s128 = float128_to_##tp##_round_to_zero(xb->f128, &env->fp_status); \
2827 flags = get_float_exception_flags(&env->fp_status); \
2828 if (unlikely(flags & float_flag_invalid)) { \
2829 t.VsrD(0) = float_invalid_cvt(env, flags, t.VsrD(0), rnan, 0, GETPC());\
2830 t.VsrD(1) = -(t.VsrD(0) & 1); \
2831 } \
2832 \
2833 *xt = t; \
2834 do_float_check_status(env, true, GETPC()); \
2835 }
2836
2837 VSX_CVT_FP_TO_INT128(XSCVQPUQZ, uint128, 0)
2838 VSX_CVT_FP_TO_INT128(XSCVQPSQZ, int128, 0x8000000000000000ULL);
2839
2840 /*
2841 * Likewise, except that the result is duplicated into both subwords.
2842 * Power ISA v3.1 has Programming Notes for these insns:
2843 * Previous versions of the architecture allowed the contents of
2844 * word 0 of the result register to be undefined. However, all
2845 * processors that support this instruction write the result into
2846 * words 0 and 1 (and words 2 and 3) of the result register, as
2847 * is required by this version of the architecture.
2848 */
2849 #define VSX_CVT_FP_TO_INT2(op, nels, stp, ttp, sfi, rnan) \
2850 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2851 { \
2852 int all_flags = 0; \
2853 ppc_vsr_t t = { }; \
2854 int i, flags; \
2855 \
2856 for (i = 0; i < nels; i++) { \
2857 helper_reset_fpstatus(env); \
2858 t.VsrW(2 * i) = stp##_to_##ttp##_round_to_zero(xb->VsrD(i), \
2859 &env->fp_status); \
2860 flags = env->fp_status.float_exception_flags; \
2861 all_flags |= flags; \
2862 if (unlikely(flags & float_flag_invalid)) { \
2863 t.VsrW(2 * i) = float_invalid_cvt(env, flags, t.VsrW(2 * i), \
2864 rnan, 0, GETPC()); \
2865 } \
2866 t.VsrW(2 * i + 1) = t.VsrW(2 * i); \
2867 } \
2868 \
2869 *xt = t; \
2870 env->fp_status.float_exception_flags = all_flags; \
2871 do_float_check_status(env, sfi, GETPC()); \
2872 }
2873
2874 VSX_CVT_FP_TO_INT2(xscvdpsxws, 1, float64, int32, true, 0x80000000U)
2875 VSX_CVT_FP_TO_INT2(xscvdpuxws, 1, float64, uint32, true, 0U)
2876 VSX_CVT_FP_TO_INT2(xvcvdpsxws, 2, float64, int32, false, 0x80000000U)
2877 VSX_CVT_FP_TO_INT2(xvcvdpuxws, 2, float64, uint32, false, 0U)
2878
2879 /*
2880 * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion
2881 * op - instruction mnemonic
2882 * stp - source type (float32 or float64)
2883 * ttp - target type (int32, uint32, int64 or uint64)
2884 * sfld - source vsr_t field
2885 * tfld - target vsr_t field
2886 * rnan - resulting NaN
2887 */
2888 #define VSX_CVT_FP_TO_INT_VECTOR(op, stp, ttp, sfld, tfld, rnan) \
2889 void helper_##op(CPUPPCState *env, uint32_t opcode, \
2890 ppc_vsr_t *xt, ppc_vsr_t *xb) \
2891 { \
2892 ppc_vsr_t t = { }; \
2893 int flags; \
2894 \
2895 helper_reset_fpstatus(env); \
2896 \
2897 t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \
2898 flags = get_float_exception_flags(&env->fp_status); \
2899 if (flags & float_flag_invalid) { \
2900 t.tfld = float_invalid_cvt(env, flags, t.tfld, rnan, 0, GETPC()); \
2901 } \
2902 \
2903 *xt = t; \
2904 do_float_check_status(env, true, GETPC()); \
2905 }
2906
2907 VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \
2908 0x8000000000000000ULL)
2909 VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \
2910 0xffffffff80000000ULL)
2911 VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL)
2912 VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL)
2913
2914 /*
2915 * VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
2916 * op - instruction mnemonic
2917 * nels - number of elements (1, 2 or 4)
2918 * stp - source type (int32, uint32, int64 or uint64)
2919 * ttp - target type (float32 or float64)
2920 * sfld - source vsr_t field
2921 * tfld - target vsr_t field
2922 * jdef - definition of the j index (i or 2*i)
2923 * sfifprf - set FI and FPRF
2924 */
2925 #define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfifprf, r2sp)\
2926 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2927 { \
2928 ppc_vsr_t t = { }; \
2929 int i; \
2930 \
2931 helper_reset_fpstatus(env); \
2932 \
2933 for (i = 0; i < nels; i++) { \
2934 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
2935 if (r2sp) { \
2936 t.tfld = do_frsp(env, t.tfld, GETPC()); \
2937 } \
2938 if (sfifprf) { \
2939 helper_compute_fprf_float64(env, t.tfld); \
2940 } \
2941 } \
2942 \
2943 *xt = t; \
2944 do_float_check_status(env, sfifprf, GETPC()); \
2945 }
2946
2947 VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0)
2948 VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 0)
2949 VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, VsrD(0), VsrD(0), 1, 1)
2950 VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 1)
2951 VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0)
2952 VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0)
2953 VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2 * i), VsrD(i), 0, 0)
2954 VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2 * i), VsrD(i), 0, 0)
2955 VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0)
2956 VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0)
2957
2958 #define VSX_CVT_INT_TO_FP2(op, stp, ttp) \
2959 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
2960 { \
2961 ppc_vsr_t t = { }; \
2962 int i; \
2963 \
2964 for (i = 0; i < 2; i++) { \
2965 t.VsrW(2 * i) = stp##_to_##ttp(xb->VsrD(i), &env->fp_status); \
2966 t.VsrW(2 * i + 1) = t.VsrW(2 * i); \
2967 } \
2968 \
2969 *xt = t; \
2970 do_float_check_status(env, false, GETPC()); \
2971 }
2972
2973 VSX_CVT_INT_TO_FP2(xvcvsxdsp, int64, float32)
2974 VSX_CVT_INT_TO_FP2(xvcvuxdsp, uint64, float32)
2975
2976 #define VSX_CVT_INT128_TO_FP(op, tp) \
2977 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb)\
2978 { \
2979 helper_reset_fpstatus(env); \
2980 xt->f128 = tp##_to_float128(xb->s128, &env->fp_status); \
2981 helper_compute_fprf_float128(env, xt->f128); \
2982 do_float_check_status(env, true, GETPC()); \
2983 }
2984
2985 VSX_CVT_INT128_TO_FP(XSCVUQQP, uint128);
2986 VSX_CVT_INT128_TO_FP(XSCVSQQP, int128);
2987
2988 /*
2989 * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion
2990 * op - instruction mnemonic
2991 * stp - source type (int32, uint32, int64 or uint64)
2992 * ttp - target type (float32 or float64)
2993 * sfld - source vsr_t field
2994 * tfld - target vsr_t field
2995 */
2996 #define VSX_CVT_INT_TO_FP_VECTOR(op, stp, ttp, sfld, tfld) \
2997 void helper_##op(CPUPPCState *env, uint32_t opcode, \
2998 ppc_vsr_t *xt, ppc_vsr_t *xb) \
2999 { \
3000 ppc_vsr_t t = *xt; \
3001 \
3002 helper_reset_fpstatus(env); \
3003 t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \
3004 helper_compute_fprf_##ttp(env, t.tfld); \
3005 \
3006 *xt = t; \
3007 do_float_check_status(env, true, GETPC()); \
3008 }
3009
3010 VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128)
3011 VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128)
3012
3013 /*
3014 * For "use current rounding mode", define a value that will not be
3015 * one of the existing rounding model enums.
3016 */
3017 #define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \
3018 float_round_up + float_round_to_zero)
3019
3020 /*
3021 * VSX_ROUND - VSX floating point round
3022 * op - instruction mnemonic
3023 * nels - number of elements (1, 2 or 4)
3024 * tp - type (float32 or float64)
3025 * fld - vsr_t field (VsrD(*) or VsrW(*))
3026 * rmode - rounding mode
3027 * sfifprf - set FI and FPRF
3028 */
3029 #define VSX_ROUND(op, nels, tp, fld, rmode, sfifprf) \
3030 void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
3031 { \
3032 ppc_vsr_t t = { }; \
3033 int i; \
3034 FloatRoundMode curr_rounding_mode; \
3035 \
3036 helper_reset_fpstatus(env); \
3037 \
3038 if (rmode != FLOAT_ROUND_CURRENT) { \
3039 curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \
3040 set_float_rounding_mode(rmode, &env->fp_status); \
3041 } \
3042 \
3043 for (i = 0; i < nels; i++) { \
3044 if (unlikely(tp##_is_signaling_nan(xb->fld, \
3045 &env->fp_status))) { \
3046 float_invalid_op_vxsnan(env, GETPC()); \
3047 t.fld = tp##_snan_to_qnan(xb->fld); \
3048 } else { \
3049 t.fld = tp##_round_to_int(xb->fld, &env->fp_status); \
3050 } \
3051 if (sfifprf) { \
3052 helper_compute_fprf_float64(env, t.fld); \
3053 } \
3054 } \
3055 \
3056 /* \
3057 * If this is not a "use current rounding mode" instruction, \
3058 * then inhibit setting of the XX bit and restore rounding \
3059 * mode from FPSCR \
3060 */ \
3061 if (rmode != FLOAT_ROUND_CURRENT) { \
3062 set_float_rounding_mode(curr_rounding_mode, &env->fp_status); \
3063 env->fp_status.float_exception_flags &= ~float_flag_inexact; \
3064 } \
3065 \
3066 *xt = t; \
3067 do_float_check_status(env, sfifprf, GETPC()); \
3068 }
3069
3070 VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1)
3071 VSX_ROUND(xsrdpic, 1, float64, VsrD(0), FLOAT_ROUND_CURRENT, 1)
3072 VSX_ROUND(xsrdpim, 1, float64, VsrD(0), float_round_down, 1)
3073 VSX_ROUND(xsrdpip, 1, float64, VsrD(0), float_round_up, 1)
3074 VSX_ROUND(xsrdpiz, 1, float64, VsrD(0), float_round_to_zero, 1)
3075
3076 VSX_ROUND(xvrdpi, 2, float64, VsrD(i), float_round_ties_away, 0)
3077 VSX_ROUND(xvrdpic, 2, float64, VsrD(i), FLOAT_ROUND_CURRENT, 0)
3078 VSX_ROUND(xvrdpim, 2, float64, VsrD(i), float_round_down, 0)
3079 VSX_ROUND(xvrdpip, 2, float64, VsrD(i), float_round_up, 0)
3080 VSX_ROUND(xvrdpiz, 2, float64, VsrD(i), float_round_to_zero, 0)
3081
3082 VSX_ROUND(xvrspi, 4, float32, VsrW(i), float_round_ties_away, 0)
3083 VSX_ROUND(xvrspic, 4, float32, VsrW(i), FLOAT_ROUND_CURRENT, 0)
3084 VSX_ROUND(xvrspim, 4, float32, VsrW(i), float_round_down, 0)
3085 VSX_ROUND(xvrspip, 4, float32, VsrW(i), float_round_up, 0)
3086 VSX_ROUND(xvrspiz, 4, float32, VsrW(i), float_round_to_zero, 0)
3087
helper_xsrsp(CPUPPCState * env,uint64_t xb)3088 uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
3089 {
3090 helper_reset_fpstatus(env);
3091
3092 uint64_t xt = do_frsp(env, xb, GETPC());
3093
3094 helper_compute_fprf_float64(env, xt);
3095 do_float_check_status(env, true, GETPC());
3096 return xt;
3097 }
3098
helper_XVXSIGSP(ppc_vsr_t * xt,ppc_vsr_t * xb)3099 void helper_XVXSIGSP(ppc_vsr_t *xt, ppc_vsr_t *xb)
3100 {
3101 ppc_vsr_t t = { };
3102 uint32_t exp, i, fraction;
3103
3104 for (i = 0; i < 4; i++) {
3105 exp = (xb->VsrW(i) >> 23) & 0xFF;
3106 fraction = xb->VsrW(i) & 0x7FFFFF;
3107 if (exp != 0 && exp != 255) {
3108 t.VsrW(i) = fraction | 0x00800000;
3109 } else {
3110 t.VsrW(i) = fraction;
3111 }
3112 }
3113 *xt = t;
3114 }
3115
3116 #define VSX_TSTDC(tp) \
3117 static int32_t tp##_tstdc(tp b, uint32_t dcmx) \
3118 { \
3119 uint32_t match = 0; \
3120 uint32_t sign = tp##_is_neg(b); \
3121 if (tp##_is_any_nan(b)) { \
3122 match = extract32(dcmx, 6, 1); \
3123 } else if (tp##_is_infinity(b)) { \
3124 match = extract32(dcmx, 4 + !sign, 1); \
3125 } else if (tp##_is_zero(b)) { \
3126 match = extract32(dcmx, 2 + !sign, 1); \
3127 } else if (tp##_is_zero_or_denormal(b)) { \
3128 match = extract32(dcmx, 0 + !sign, 1); \
3129 } \
3130 return (match != 0); \
3131 }
3132
3133 VSX_TSTDC(float32)
VSX_TSTDC(float64)3134 VSX_TSTDC(float64)
3135 VSX_TSTDC(float128)
3136 #undef VSX_TSTDC
3137
3138 void helper_XVTSTDCDP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v)
3139 {
3140 int i;
3141 for (i = 0; i < 2; i++) {
3142 t->s64[i] = (int64_t)-float64_tstdc(b->f64[i], dcmx);
3143 }
3144 }
3145
helper_XVTSTDCSP(ppc_vsr_t * t,ppc_vsr_t * b,uint64_t dcmx,uint32_t v)3146 void helper_XVTSTDCSP(ppc_vsr_t *t, ppc_vsr_t *b, uint64_t dcmx, uint32_t v)
3147 {
3148 int i;
3149 for (i = 0; i < 4; i++) {
3150 t->s32[i] = (int32_t)-float32_tstdc(b->f32[i], dcmx);
3151 }
3152 }
3153
not_SP_value(float64 val)3154 static bool not_SP_value(float64 val)
3155 {
3156 return val != helper_todouble(helper_tosingle(val));
3157 }
3158
3159 /*
3160 * VSX_XS_TSTDC - VSX Scalar Test Data Class
3161 * NAME - instruction name
3162 * FLD - vsr_t field (VsrD(0) or f128)
3163 * TP - type (float64 or float128)
3164 */
3165 #define VSX_XS_TSTDC(NAME, FLD, TP) \
3166 void helper_##NAME(CPUPPCState *env, uint32_t bf, \
3167 uint32_t dcmx, ppc_vsr_t *b) \
3168 { \
3169 uint32_t cc, match, sign = TP##_is_neg(b->FLD); \
3170 match = TP##_tstdc(b->FLD, dcmx); \
3171 cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \
3172 env->fpscr &= ~FP_FPCC; \
3173 env->fpscr |= cc << FPSCR_FPCC; \
3174 env->crf[bf] = cc; \
3175 }
3176
3177 VSX_XS_TSTDC(XSTSTDCDP, VsrD(0), float64)
VSX_XS_TSTDC(XSTSTDCQP,f128,float128)3178 VSX_XS_TSTDC(XSTSTDCQP, f128, float128)
3179 #undef VSX_XS_TSTDC
3180
3181 void helper_XSTSTDCSP(CPUPPCState *env, uint32_t bf,
3182 uint32_t dcmx, ppc_vsr_t *b)
3183 {
3184 uint32_t cc, match, sign = float64_is_neg(b->VsrD(0));
3185 uint32_t exp = (b->VsrD(0) >> 52) & 0x7FF;
3186 int not_sp = (int)not_SP_value(b->VsrD(0));
3187 match = float64_tstdc(b->VsrD(0), dcmx) || (exp > 0 && exp < 0x381);
3188 cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT;
3189 env->fpscr &= ~FP_FPCC;
3190 env->fpscr |= cc << FPSCR_FPCC;
3191 env->crf[bf] = cc;
3192 }
3193
helper_xsrqpi(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xb)3194 void helper_xsrqpi(CPUPPCState *env, uint32_t opcode,
3195 ppc_vsr_t *xt, ppc_vsr_t *xb)
3196 {
3197 ppc_vsr_t t = { };
3198 uint8_t r = Rrm(opcode);
3199 uint8_t ex = Rc(opcode);
3200 uint8_t rmc = RMC(opcode);
3201 uint8_t rmode = 0;
3202 float_status tstat;
3203
3204 helper_reset_fpstatus(env);
3205
3206 if (r == 0 && rmc == 0) {
3207 rmode = float_round_ties_away;
3208 } else if (r == 0 && rmc == 0x3) {
3209 rmode = env->fpscr & FP_RN;
3210 } else if (r == 1) {
3211 switch (rmc) {
3212 case 0:
3213 rmode = float_round_nearest_even;
3214 break;
3215 case 1:
3216 rmode = float_round_to_zero;
3217 break;
3218 case 2:
3219 rmode = float_round_up;
3220 break;
3221 case 3:
3222 rmode = float_round_down;
3223 break;
3224 default:
3225 abort();
3226 }
3227 }
3228
3229 tstat = env->fp_status;
3230 set_float_exception_flags(0, &tstat);
3231 set_float_rounding_mode(rmode, &tstat);
3232 t.f128 = float128_round_to_int(xb->f128, &tstat);
3233 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3234
3235 if (unlikely(tstat.float_exception_flags & float_flag_invalid_snan)) {
3236 float_invalid_op_vxsnan(env, GETPC());
3237 }
3238
3239 if (ex == 0 && (tstat.float_exception_flags & float_flag_inexact)) {
3240 env->fp_status.float_exception_flags &= ~float_flag_inexact;
3241 }
3242
3243 helper_compute_fprf_float128(env, t.f128);
3244 do_float_check_status(env, true, GETPC());
3245 *xt = t;
3246 }
3247
helper_xsrqpxp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xb)3248 void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode,
3249 ppc_vsr_t *xt, ppc_vsr_t *xb)
3250 {
3251 ppc_vsr_t t = { };
3252 uint8_t r = Rrm(opcode);
3253 uint8_t rmc = RMC(opcode);
3254 uint8_t rmode = 0;
3255 floatx80 round_res;
3256 float_status tstat;
3257
3258 helper_reset_fpstatus(env);
3259
3260 if (r == 0 && rmc == 0) {
3261 rmode = float_round_ties_away;
3262 } else if (r == 0 && rmc == 0x3) {
3263 rmode = env->fpscr & FP_RN;
3264 } else if (r == 1) {
3265 switch (rmc) {
3266 case 0:
3267 rmode = float_round_nearest_even;
3268 break;
3269 case 1:
3270 rmode = float_round_to_zero;
3271 break;
3272 case 2:
3273 rmode = float_round_up;
3274 break;
3275 case 3:
3276 rmode = float_round_down;
3277 break;
3278 default:
3279 abort();
3280 }
3281 }
3282
3283 tstat = env->fp_status;
3284 set_float_exception_flags(0, &tstat);
3285 set_float_rounding_mode(rmode, &tstat);
3286 round_res = float128_to_floatx80(xb->f128, &tstat);
3287 t.f128 = floatx80_to_float128(round_res, &tstat);
3288 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3289
3290 if (unlikely(tstat.float_exception_flags & float_flag_invalid_snan)) {
3291 float_invalid_op_vxsnan(env, GETPC());
3292 t.f128 = float128_snan_to_qnan(t.f128);
3293 }
3294
3295 helper_compute_fprf_float128(env, t.f128);
3296 *xt = t;
3297 do_float_check_status(env, true, GETPC());
3298 }
3299
helper_xssqrtqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xb)3300 void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode,
3301 ppc_vsr_t *xt, ppc_vsr_t *xb)
3302 {
3303 ppc_vsr_t t = { };
3304 float_status tstat;
3305
3306 helper_reset_fpstatus(env);
3307
3308 tstat = env->fp_status;
3309 if (unlikely(Rc(opcode) != 0)) {
3310 tstat.float_rounding_mode = float_round_to_odd;
3311 }
3312
3313 set_float_exception_flags(0, &tstat);
3314 t.f128 = float128_sqrt(xb->f128, &tstat);
3315 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3316
3317 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
3318 float_invalid_op_sqrt(env, tstat.float_exception_flags, 1, GETPC());
3319 }
3320
3321 helper_compute_fprf_float128(env, t.f128);
3322 *xt = t;
3323 do_float_check_status(env, true, GETPC());
3324 }
3325
helper_xssubqp(CPUPPCState * env,uint32_t opcode,ppc_vsr_t * xt,ppc_vsr_t * xa,ppc_vsr_t * xb)3326 void helper_xssubqp(CPUPPCState *env, uint32_t opcode,
3327 ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb)
3328 {
3329 ppc_vsr_t t = *xt;
3330 float_status tstat;
3331
3332 helper_reset_fpstatus(env);
3333
3334 tstat = env->fp_status;
3335 if (unlikely(Rc(opcode) != 0)) {
3336 tstat.float_rounding_mode = float_round_to_odd;
3337 }
3338
3339 set_float_exception_flags(0, &tstat);
3340 t.f128 = float128_sub(xa->f128, xb->f128, &tstat);
3341 env->fp_status.float_exception_flags |= tstat.float_exception_flags;
3342
3343 if (unlikely(tstat.float_exception_flags & float_flag_invalid)) {
3344 float_invalid_op_addsub(env, tstat.float_exception_flags, 1, GETPC());
3345 }
3346
3347 helper_compute_fprf_float128(env, t.f128);
3348 *xt = t;
3349 do_float_check_status(env, true, GETPC());
3350 }
3351
vsxger_excp(CPUPPCState * env,uintptr_t retaddr)3352 static inline void vsxger_excp(CPUPPCState *env, uintptr_t retaddr)
3353 {
3354 /*
3355 * XV*GER instructions execute and set the FPSCR as if exceptions
3356 * are disabled and only at the end throw an exception
3357 */
3358 target_ulong enable;
3359 enable = env->fpscr & (FP_ENABLES | FP_FI | FP_FR);
3360 env->fpscr &= ~(FP_ENABLES | FP_FI | FP_FR);
3361 int status = get_float_exception_flags(&env->fp_status);
3362 if (unlikely(status & float_flag_invalid)) {
3363 if (status & float_flag_invalid_snan) {
3364 float_invalid_op_vxsnan(env, 0);
3365 }
3366 if (status & float_flag_invalid_imz) {
3367 float_invalid_op_vximz(env, false, 0);
3368 }
3369 if (status & float_flag_invalid_isi) {
3370 float_invalid_op_vxisi(env, false, 0);
3371 }
3372 }
3373 do_float_check_status(env, false, retaddr);
3374 env->fpscr |= enable;
3375 do_fpscr_check_status(env, retaddr);
3376 }
3377
3378 typedef float64 extract_f16(float16, float_status *);
3379
extract_hf16(float16 in,float_status * fp_status)3380 static float64 extract_hf16(float16 in, float_status *fp_status)
3381 {
3382 return float16_to_float64(in, true, fp_status);
3383 }
3384
extract_bf16(bfloat16 in,float_status * fp_status)3385 static float64 extract_bf16(bfloat16 in, float_status *fp_status)
3386 {
3387 return bfloat16_to_float64(in, fp_status);
3388 }
3389
vsxger16(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask,bool acc,bool neg_mul,bool neg_acc,extract_f16 extract)3390 static void vsxger16(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3391 ppc_acc_t *at, uint32_t mask, bool acc,
3392 bool neg_mul, bool neg_acc, extract_f16 extract)
3393 {
3394 float32 r, aux_acc;
3395 float64 psum, va, vb, vc, vd;
3396 int i, j, xmsk_bit, ymsk_bit;
3397 uint8_t pmsk = FIELD_EX32(mask, GER_MSK, PMSK),
3398 xmsk = FIELD_EX32(mask, GER_MSK, XMSK),
3399 ymsk = FIELD_EX32(mask, GER_MSK, YMSK);
3400 float_status *excp_ptr = &env->fp_status;
3401 for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) {
3402 for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) {
3403 if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) {
3404 va = !(pmsk & 2) ? float64_zero :
3405 extract(a->VsrHF(2 * i), excp_ptr);
3406 vb = !(pmsk & 2) ? float64_zero :
3407 extract(b->VsrHF(2 * j), excp_ptr);
3408 vc = !(pmsk & 1) ? float64_zero :
3409 extract(a->VsrHF(2 * i + 1), excp_ptr);
3410 vd = !(pmsk & 1) ? float64_zero :
3411 extract(b->VsrHF(2 * j + 1), excp_ptr);
3412 psum = float64_mul(va, vb, excp_ptr);
3413 psum = float64r32_muladd(vc, vd, psum, 0, excp_ptr);
3414 r = float64_to_float32(psum, excp_ptr);
3415 if (acc) {
3416 aux_acc = at[i].VsrSF(j);
3417 if (neg_mul) {
3418 r = bfp32_neg(r);
3419 }
3420 if (neg_acc) {
3421 aux_acc = bfp32_neg(aux_acc);
3422 }
3423 r = float32_add(r, aux_acc, excp_ptr);
3424 }
3425 at[i].VsrSF(j) = r;
3426 } else {
3427 at[i].VsrSF(j) = float32_zero;
3428 }
3429 }
3430 }
3431 vsxger_excp(env, GETPC());
3432 }
3433
3434 typedef void vsxger_zero(ppc_vsr_t *at, int, int);
3435
3436 typedef void vsxger_muladd_f(ppc_vsr_t *, ppc_vsr_t *, ppc_vsr_t *, int, int,
3437 int flags, float_status *s);
3438
vsxger_muladd32(ppc_vsr_t * at,ppc_vsr_t * a,ppc_vsr_t * b,int i,int j,int flags,float_status * s)3439 static void vsxger_muladd32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3440 int j, int flags, float_status *s)
3441 {
3442 at[i].VsrSF(j) = float32_muladd(a->VsrSF(i), b->VsrSF(j),
3443 at[i].VsrSF(j), flags, s);
3444 }
3445
vsxger_mul32(ppc_vsr_t * at,ppc_vsr_t * a,ppc_vsr_t * b,int i,int j,int flags,float_status * s)3446 static void vsxger_mul32(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3447 int j, int flags, float_status *s)
3448 {
3449 at[i].VsrSF(j) = float32_mul(a->VsrSF(i), b->VsrSF(j), s);
3450 }
3451
vsxger_zero32(ppc_vsr_t * at,int i,int j)3452 static void vsxger_zero32(ppc_vsr_t *at, int i, int j)
3453 {
3454 at[i].VsrSF(j) = float32_zero;
3455 }
3456
vsxger_muladd64(ppc_vsr_t * at,ppc_vsr_t * a,ppc_vsr_t * b,int i,int j,int flags,float_status * s)3457 static void vsxger_muladd64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3458 int j, int flags, float_status *s)
3459 {
3460 if (j >= 2) {
3461 j -= 2;
3462 at[i].VsrDF(j) = float64_muladd(a[i / 2].VsrDF(i % 2), b->VsrDF(j),
3463 at[i].VsrDF(j), flags, s);
3464 }
3465 }
3466
vsxger_mul64(ppc_vsr_t * at,ppc_vsr_t * a,ppc_vsr_t * b,int i,int j,int flags,float_status * s)3467 static void vsxger_mul64(ppc_vsr_t *at, ppc_vsr_t *a, ppc_vsr_t *b, int i,
3468 int j, int flags, float_status *s)
3469 {
3470 if (j >= 2) {
3471 j -= 2;
3472 at[i].VsrDF(j) = float64_mul(a[i / 2].VsrDF(i % 2), b->VsrDF(j), s);
3473 }
3474 }
3475
vsxger_zero64(ppc_vsr_t * at,int i,int j)3476 static void vsxger_zero64(ppc_vsr_t *at, int i, int j)
3477 {
3478 if (j >= 2) {
3479 j -= 2;
3480 at[i].VsrDF(j) = float64_zero;
3481 }
3482 }
3483
vsxger(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask,bool acc,bool neg_mul,bool neg_acc,vsxger_muladd_f mul,vsxger_muladd_f muladd,vsxger_zero zero)3484 static void vsxger(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3485 ppc_acc_t *at, uint32_t mask, bool acc, bool neg_mul,
3486 bool neg_acc, vsxger_muladd_f mul, vsxger_muladd_f muladd,
3487 vsxger_zero zero)
3488 {
3489 int i, j, xmsk_bit, ymsk_bit, op_flags;
3490 uint8_t xmsk = mask & 0x0F;
3491 uint8_t ymsk = (mask >> 4) & 0x0F;
3492 float_status *excp_ptr = &env->fp_status;
3493 op_flags = (neg_acc ^ neg_mul) ? float_muladd_negate_c : 0;
3494 op_flags |= (neg_mul) ? float_muladd_negate_result : 0;
3495 helper_reset_fpstatus(env);
3496 for (i = 0, xmsk_bit = 1 << 3; i < 4; i++, xmsk_bit >>= 1) {
3497 for (j = 0, ymsk_bit = 1 << 3; j < 4; j++, ymsk_bit >>= 1) {
3498 if ((xmsk_bit & xmsk) && (ymsk_bit & ymsk)) {
3499 if (acc) {
3500 muladd(at, a, b, i, j, op_flags, excp_ptr);
3501 } else {
3502 mul(at, a, b, i, j, op_flags, excp_ptr);
3503 }
3504 } else {
3505 zero(at, i, j);
3506 }
3507 }
3508 }
3509 vsxger_excp(env, GETPC());
3510 }
3511
3512 QEMU_FLATTEN
helper_XVBF16GER2(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3513 void helper_XVBF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3514 ppc_acc_t *at, uint32_t mask)
3515 {
3516 vsxger16(env, a, b, at, mask, false, false, false, extract_bf16);
3517 }
3518
3519 QEMU_FLATTEN
helper_XVBF16GER2PP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3520 void helper_XVBF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3521 ppc_acc_t *at, uint32_t mask)
3522 {
3523 vsxger16(env, a, b, at, mask, true, false, false, extract_bf16);
3524 }
3525
3526 QEMU_FLATTEN
helper_XVBF16GER2PN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3527 void helper_XVBF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3528 ppc_acc_t *at, uint32_t mask)
3529 {
3530 vsxger16(env, a, b, at, mask, true, false, true, extract_bf16);
3531 }
3532
3533 QEMU_FLATTEN
helper_XVBF16GER2NP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3534 void helper_XVBF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3535 ppc_acc_t *at, uint32_t mask)
3536 {
3537 vsxger16(env, a, b, at, mask, true, true, false, extract_bf16);
3538 }
3539
3540 QEMU_FLATTEN
helper_XVBF16GER2NN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3541 void helper_XVBF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3542 ppc_acc_t *at, uint32_t mask)
3543 {
3544 vsxger16(env, a, b, at, mask, true, true, true, extract_bf16);
3545 }
3546
3547 QEMU_FLATTEN
helper_XVF16GER2(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3548 void helper_XVF16GER2(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3549 ppc_acc_t *at, uint32_t mask)
3550 {
3551 vsxger16(env, a, b, at, mask, false, false, false, extract_hf16);
3552 }
3553
3554 QEMU_FLATTEN
helper_XVF16GER2PP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3555 void helper_XVF16GER2PP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3556 ppc_acc_t *at, uint32_t mask)
3557 {
3558 vsxger16(env, a, b, at, mask, true, false, false, extract_hf16);
3559 }
3560
3561 QEMU_FLATTEN
helper_XVF16GER2PN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3562 void helper_XVF16GER2PN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3563 ppc_acc_t *at, uint32_t mask)
3564 {
3565 vsxger16(env, a, b, at, mask, true, false, true, extract_hf16);
3566 }
3567
3568 QEMU_FLATTEN
helper_XVF16GER2NP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3569 void helper_XVF16GER2NP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3570 ppc_acc_t *at, uint32_t mask)
3571 {
3572 vsxger16(env, a, b, at, mask, true, true, false, extract_hf16);
3573 }
3574
3575 QEMU_FLATTEN
helper_XVF16GER2NN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3576 void helper_XVF16GER2NN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3577 ppc_acc_t *at, uint32_t mask)
3578 {
3579 vsxger16(env, a, b, at, mask, true, true, true, extract_hf16);
3580 }
3581
3582 QEMU_FLATTEN
helper_XVF32GER(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3583 void helper_XVF32GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3584 ppc_acc_t *at, uint32_t mask)
3585 {
3586 vsxger(env, a, b, at, mask, false, false, false, vsxger_mul32,
3587 vsxger_muladd32, vsxger_zero32);
3588 }
3589
3590 QEMU_FLATTEN
helper_XVF32GERPP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3591 void helper_XVF32GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3592 ppc_acc_t *at, uint32_t mask)
3593 {
3594 vsxger(env, a, b, at, mask, true, false, false, vsxger_mul32,
3595 vsxger_muladd32, vsxger_zero32);
3596 }
3597
3598 QEMU_FLATTEN
helper_XVF32GERPN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3599 void helper_XVF32GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3600 ppc_acc_t *at, uint32_t mask)
3601 {
3602 vsxger(env, a, b, at, mask, true, false, true, vsxger_mul32,
3603 vsxger_muladd32, vsxger_zero32);
3604 }
3605
3606 QEMU_FLATTEN
helper_XVF32GERNP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3607 void helper_XVF32GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3608 ppc_acc_t *at, uint32_t mask)
3609 {
3610 vsxger(env, a, b, at, mask, true, true, false, vsxger_mul32,
3611 vsxger_muladd32, vsxger_zero32);
3612 }
3613
3614 QEMU_FLATTEN
helper_XVF32GERNN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3615 void helper_XVF32GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3616 ppc_acc_t *at, uint32_t mask)
3617 {
3618 vsxger(env, a, b, at, mask, true, true, true, vsxger_mul32,
3619 vsxger_muladd32, vsxger_zero32);
3620 }
3621
3622 QEMU_FLATTEN
helper_XVF64GER(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3623 void helper_XVF64GER(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3624 ppc_acc_t *at, uint32_t mask)
3625 {
3626 vsxger(env, a, b, at, mask, false, false, false, vsxger_mul64,
3627 vsxger_muladd64, vsxger_zero64);
3628 }
3629
3630 QEMU_FLATTEN
helper_XVF64GERPP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3631 void helper_XVF64GERPP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3632 ppc_acc_t *at, uint32_t mask)
3633 {
3634 vsxger(env, a, b, at, mask, true, false, false, vsxger_mul64,
3635 vsxger_muladd64, vsxger_zero64);
3636 }
3637
3638 QEMU_FLATTEN
helper_XVF64GERPN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3639 void helper_XVF64GERPN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3640 ppc_acc_t *at, uint32_t mask)
3641 {
3642 vsxger(env, a, b, at, mask, true, false, true, vsxger_mul64,
3643 vsxger_muladd64, vsxger_zero64);
3644 }
3645
3646 QEMU_FLATTEN
helper_XVF64GERNP(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3647 void helper_XVF64GERNP(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3648 ppc_acc_t *at, uint32_t mask)
3649 {
3650 vsxger(env, a, b, at, mask, true, true, false, vsxger_mul64,
3651 vsxger_muladd64, vsxger_zero64);
3652 }
3653
3654 QEMU_FLATTEN
helper_XVF64GERNN(CPUPPCState * env,ppc_vsr_t * a,ppc_vsr_t * b,ppc_acc_t * at,uint32_t mask)3655 void helper_XVF64GERNN(CPUPPCState *env, ppc_vsr_t *a, ppc_vsr_t *b,
3656 ppc_acc_t *at, uint32_t mask)
3657 {
3658 vsxger(env, a, b, at, mask, true, true, true, vsxger_mul64,
3659 vsxger_muladd64, vsxger_zero64);
3660 }
3661