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