1 /* 2 * Helpers for floating point instructions. 3 * 4 * Copyright (c) 2007 Jocelyn Mayer 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "cpu.h" 22 #include "exec/exec-all.h" 23 #include "exec/helper-proto.h" 24 #include "fpu/softfloat.h" 25 26 #define FP_STATUS (env->fp_status) 27 28 29 void helper_setroundmode(CPUAlphaState *env, uint32_t val) 30 { 31 set_float_rounding_mode(val, &FP_STATUS); 32 } 33 34 void helper_setflushzero(CPUAlphaState *env, uint32_t val) 35 { 36 set_flush_to_zero(val, &FP_STATUS); 37 } 38 39 #define CONVERT_BIT(X, SRC, DST) \ 40 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) 41 42 static uint32_t soft_to_fpcr_exc(CPUAlphaState *env) 43 { 44 uint8_t exc = get_float_exception_flags(&FP_STATUS); 45 uint32_t ret = 0; 46 47 if (unlikely(exc)) { 48 set_float_exception_flags(0, &FP_STATUS); 49 ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV); 50 ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE); 51 ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF); 52 ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF); 53 ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE); 54 } 55 56 return ret; 57 } 58 59 static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr, 60 uint32_t exc, uint32_t regno, uint32_t hw_exc) 61 { 62 hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV); 63 hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE); 64 hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV); 65 hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF); 66 hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE); 67 hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV); 68 69 arith_excp(env, retaddr, hw_exc, 1ull << regno); 70 } 71 72 /* Raise exceptions for ieee fp insns without software completion. 73 In that case there are no exceptions that don't trap; the mask 74 doesn't apply. */ 75 void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno) 76 { 77 uint32_t exc = env->error_code; 78 if (exc) { 79 env->fpcr |= exc; 80 exc &= ~ignore; 81 if (exc) { 82 fp_exc_raise1(env, GETPC(), exc, regno, 0); 83 } 84 } 85 } 86 87 /* Raise exceptions for ieee fp insns with software completion. */ 88 void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno) 89 { 90 uint32_t exc = env->error_code & ~ignore; 91 if (exc) { 92 env->fpcr |= exc; 93 exc &= ~ignore; 94 #ifdef CONFIG_USER_ONLY 95 /* 96 * In user mode, the kernel's software handler only 97 * delivers a signal if the exception is enabled. 98 */ 99 if (!(exc & env->fpcr_exc_enable)) { 100 return; 101 } 102 #else 103 /* 104 * In system mode, the software handler gets invoked 105 * for any non-ignored exception. 106 */ 107 if (!exc) { 108 return; 109 } 110 #endif 111 exc &= env->fpcr_exc_enable; 112 fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC); 113 } 114 } 115 116 /* Input handing without software completion. Trap for all 117 non-finite numbers. */ 118 void helper_ieee_input(CPUAlphaState *env, uint64_t val) 119 { 120 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; 121 uint64_t frac = val & 0xfffffffffffffull; 122 123 if (exp == 0) { 124 /* Denormals without /S raise an exception. */ 125 if (frac != 0) { 126 arith_excp(env, GETPC(), EXC_M_INV, 0); 127 } 128 } else if (exp == 0x7ff) { 129 /* Infinity or NaN. */ 130 env->fpcr |= FPCR_INV; 131 arith_excp(env, GETPC(), EXC_M_INV, 0); 132 } 133 } 134 135 /* Similar, but does not trap for infinities. Used for comparisons. */ 136 void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) 137 { 138 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; 139 uint64_t frac = val & 0xfffffffffffffull; 140 141 if (exp == 0) { 142 /* Denormals without /S raise an exception. */ 143 if (frac != 0) { 144 arith_excp(env, GETPC(), EXC_M_INV, 0); 145 } 146 } else if (exp == 0x7ff && frac) { 147 /* NaN. */ 148 env->fpcr |= FPCR_INV; 149 arith_excp(env, GETPC(), EXC_M_INV, 0); 150 } 151 } 152 153 /* Input handing with software completion. Trap for denorms, unless DNZ 154 is set. If we try to support DNOD (which none of the produced hardware 155 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set; 156 then the code downstream of that will need to cope with denorms sans 157 flush_input_to_zero. Most of it should work sanely, but there's 158 nothing to compare with. */ 159 void helper_ieee_input_s(CPUAlphaState *env, uint64_t val) 160 { 161 if (unlikely(2 * val - 1 < 0x1fffffffffffffull) 162 && !env->fp_status.flush_inputs_to_zero) { 163 arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); 164 } 165 } 166 167 /* S floating (single) */ 168 169 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ 170 static inline uint64_t float32_to_s_int(uint32_t fi) 171 { 172 uint32_t frac = fi & 0x7fffff; 173 uint32_t sign = fi >> 31; 174 uint32_t exp_msb = (fi >> 30) & 1; 175 uint32_t exp_low = (fi >> 23) & 0x7f; 176 uint32_t exp; 177 178 exp = (exp_msb << 10) | exp_low; 179 if (exp_msb) { 180 if (exp_low == 0x7f) { 181 exp = 0x7ff; 182 } 183 } else { 184 if (exp_low != 0x00) { 185 exp |= 0x380; 186 } 187 } 188 189 return (((uint64_t)sign << 63) 190 | ((uint64_t)exp << 52) 191 | ((uint64_t)frac << 29)); 192 } 193 194 static inline uint64_t float32_to_s(float32 fa) 195 { 196 CPU_FloatU a; 197 a.f = fa; 198 return float32_to_s_int(a.l); 199 } 200 201 static inline uint32_t s_to_float32_int(uint64_t a) 202 { 203 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); 204 } 205 206 static inline float32 s_to_float32(uint64_t a) 207 { 208 CPU_FloatU r; 209 r.l = s_to_float32_int(a); 210 return r.f; 211 } 212 213 uint32_t helper_s_to_memory(uint64_t a) 214 { 215 return s_to_float32_int(a); 216 } 217 218 uint64_t helper_memory_to_s(uint32_t a) 219 { 220 return float32_to_s_int(a); 221 } 222 223 uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) 224 { 225 float32 fa, fb, fr; 226 227 fa = s_to_float32(a); 228 fb = s_to_float32(b); 229 fr = float32_add(fa, fb, &FP_STATUS); 230 env->error_code = soft_to_fpcr_exc(env); 231 232 return float32_to_s(fr); 233 } 234 235 uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) 236 { 237 float32 fa, fb, fr; 238 239 fa = s_to_float32(a); 240 fb = s_to_float32(b); 241 fr = float32_sub(fa, fb, &FP_STATUS); 242 env->error_code = soft_to_fpcr_exc(env); 243 244 return float32_to_s(fr); 245 } 246 247 uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) 248 { 249 float32 fa, fb, fr; 250 251 fa = s_to_float32(a); 252 fb = s_to_float32(b); 253 fr = float32_mul(fa, fb, &FP_STATUS); 254 env->error_code = soft_to_fpcr_exc(env); 255 256 return float32_to_s(fr); 257 } 258 259 uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) 260 { 261 float32 fa, fb, fr; 262 263 fa = s_to_float32(a); 264 fb = s_to_float32(b); 265 fr = float32_div(fa, fb, &FP_STATUS); 266 env->error_code = soft_to_fpcr_exc(env); 267 268 return float32_to_s(fr); 269 } 270 271 uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) 272 { 273 float32 fa, fr; 274 275 fa = s_to_float32(a); 276 fr = float32_sqrt(fa, &FP_STATUS); 277 env->error_code = soft_to_fpcr_exc(env); 278 279 return float32_to_s(fr); 280 } 281 282 283 /* T floating (double) */ 284 static inline float64 t_to_float64(uint64_t a) 285 { 286 /* Memory format is the same as float64 */ 287 CPU_DoubleU r; 288 r.ll = a; 289 return r.d; 290 } 291 292 static inline uint64_t float64_to_t(float64 fa) 293 { 294 /* Memory format is the same as float64 */ 295 CPU_DoubleU r; 296 r.d = fa; 297 return r.ll; 298 } 299 300 uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) 301 { 302 float64 fa, fb, fr; 303 304 fa = t_to_float64(a); 305 fb = t_to_float64(b); 306 fr = float64_add(fa, fb, &FP_STATUS); 307 env->error_code = soft_to_fpcr_exc(env); 308 309 return float64_to_t(fr); 310 } 311 312 uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) 313 { 314 float64 fa, fb, fr; 315 316 fa = t_to_float64(a); 317 fb = t_to_float64(b); 318 fr = float64_sub(fa, fb, &FP_STATUS); 319 env->error_code = soft_to_fpcr_exc(env); 320 321 return float64_to_t(fr); 322 } 323 324 uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) 325 { 326 float64 fa, fb, fr; 327 328 fa = t_to_float64(a); 329 fb = t_to_float64(b); 330 fr = float64_mul(fa, fb, &FP_STATUS); 331 env->error_code = soft_to_fpcr_exc(env); 332 333 return float64_to_t(fr); 334 } 335 336 uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) 337 { 338 float64 fa, fb, fr; 339 340 fa = t_to_float64(a); 341 fb = t_to_float64(b); 342 fr = float64_div(fa, fb, &FP_STATUS); 343 env->error_code = soft_to_fpcr_exc(env); 344 345 return float64_to_t(fr); 346 } 347 348 uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) 349 { 350 float64 fa, fr; 351 352 fa = t_to_float64(a); 353 fr = float64_sqrt(fa, &FP_STATUS); 354 env->error_code = soft_to_fpcr_exc(env); 355 356 return float64_to_t(fr); 357 } 358 359 /* Comparisons */ 360 uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) 361 { 362 float64 fa, fb; 363 uint64_t ret = 0; 364 365 fa = t_to_float64(a); 366 fb = t_to_float64(b); 367 368 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { 369 ret = 0x4000000000000000ULL; 370 } 371 env->error_code = soft_to_fpcr_exc(env); 372 373 return ret; 374 } 375 376 uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) 377 { 378 float64 fa, fb; 379 uint64_t ret = 0; 380 381 fa = t_to_float64(a); 382 fb = t_to_float64(b); 383 384 if (float64_eq_quiet(fa, fb, &FP_STATUS)) { 385 ret = 0x4000000000000000ULL; 386 } 387 env->error_code = soft_to_fpcr_exc(env); 388 389 return ret; 390 } 391 392 uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) 393 { 394 float64 fa, fb; 395 uint64_t ret = 0; 396 397 fa = t_to_float64(a); 398 fb = t_to_float64(b); 399 400 if (float64_le(fa, fb, &FP_STATUS)) { 401 ret = 0x4000000000000000ULL; 402 } 403 env->error_code = soft_to_fpcr_exc(env); 404 405 return ret; 406 } 407 408 uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) 409 { 410 float64 fa, fb; 411 uint64_t ret = 0; 412 413 fa = t_to_float64(a); 414 fb = t_to_float64(b); 415 416 if (float64_lt(fa, fb, &FP_STATUS)) { 417 ret = 0x4000000000000000ULL; 418 } 419 env->error_code = soft_to_fpcr_exc(env); 420 421 return ret; 422 } 423 424 /* Floating point format conversion */ 425 uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) 426 { 427 float64 fa; 428 float32 fr; 429 430 fa = t_to_float64(a); 431 fr = float64_to_float32(fa, &FP_STATUS); 432 env->error_code = soft_to_fpcr_exc(env); 433 434 return float32_to_s(fr); 435 } 436 437 uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) 438 { 439 float32 fa; 440 float64 fr; 441 442 fa = s_to_float32(a); 443 fr = float32_to_float64(fa, &FP_STATUS); 444 env->error_code = soft_to_fpcr_exc(env); 445 446 return float64_to_t(fr); 447 } 448 449 uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) 450 { 451 float32 fr = int64_to_float32(a, &FP_STATUS); 452 env->error_code = soft_to_fpcr_exc(env); 453 454 return float32_to_s(fr); 455 } 456 457 /* Implement float64 to uint64_t conversion without saturation -- we must 458 supply the truncated result. This behaviour is used by the compiler 459 to get unsigned conversion for free with the same instruction. */ 460 461 static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) 462 { 463 uint64_t frac, ret = 0; 464 uint32_t exp, sign, exc = 0; 465 int shift; 466 467 sign = (a >> 63); 468 exp = (uint32_t)(a >> 52) & 0x7ff; 469 frac = a & 0xfffffffffffffull; 470 471 if (exp == 0) { 472 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { 473 goto do_underflow; 474 } 475 } else if (exp == 0x7ff) { 476 exc = FPCR_INV; 477 } else { 478 /* Restore implicit bit. */ 479 frac |= 0x10000000000000ull; 480 481 shift = exp - 1023 - 52; 482 if (shift >= 0) { 483 /* In this case the number is so large that we must shift 484 the fraction left. There is no rounding to do. */ 485 if (shift < 64) { 486 ret = frac << shift; 487 } 488 /* Check for overflow. Note the special case of -0x1p63. */ 489 if (shift >= 11 && a != 0xC3E0000000000000ull) { 490 exc = FPCR_IOV | FPCR_INE; 491 } 492 } else { 493 uint64_t round; 494 495 /* In this case the number is smaller than the fraction as 496 represented by the 52 bit number. Here we must think 497 about rounding the result. Handle this by shifting the 498 fractional part of the number into the high bits of ROUND. 499 This will let us efficiently handle round-to-nearest. */ 500 shift = -shift; 501 if (shift < 63) { 502 ret = frac >> shift; 503 round = frac << (64 - shift); 504 } else { 505 /* The exponent is so small we shift out everything. 506 Leave a sticky bit for proper rounding below. */ 507 do_underflow: 508 round = 1; 509 } 510 511 if (round) { 512 exc = FPCR_INE; 513 switch (roundmode) { 514 case float_round_nearest_even: 515 if (round == (1ull << 63)) { 516 /* Fraction is exactly 0.5; round to even. */ 517 ret += (ret & 1); 518 } else if (round > (1ull << 63)) { 519 ret += 1; 520 } 521 break; 522 case float_round_to_zero: 523 break; 524 case float_round_up: 525 ret += 1 - sign; 526 break; 527 case float_round_down: 528 ret += sign; 529 break; 530 } 531 } 532 } 533 if (sign) { 534 ret = -ret; 535 } 536 } 537 env->error_code = exc; 538 539 return ret; 540 } 541 542 uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) 543 { 544 return do_cvttq(env, a, FP_STATUS.float_rounding_mode); 545 } 546 547 uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) 548 { 549 return do_cvttq(env, a, float_round_to_zero); 550 } 551 552 uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) 553 { 554 float64 fr = int64_to_float64(a, &FP_STATUS); 555 env->error_code = soft_to_fpcr_exc(env); 556 return float64_to_t(fr); 557 } 558 559 uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val) 560 { 561 uint32_t exc = 0; 562 if (val != (int32_t)val) { 563 exc = FPCR_IOV | FPCR_INE; 564 } 565 env->error_code = exc; 566 567 return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29); 568 } 569