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 if (exc) { 95 exc &= env->fpcr_exc_enable; 96 fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC); 97 } 98 } 99 } 100 101 /* Input handing without software completion. Trap for all 102 non-finite numbers. */ 103 void helper_ieee_input(CPUAlphaState *env, uint64_t val) 104 { 105 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; 106 uint64_t frac = val & 0xfffffffffffffull; 107 108 if (exp == 0) { 109 /* Denormals without /S raise an exception. */ 110 if (frac != 0) { 111 arith_excp(env, GETPC(), EXC_M_INV, 0); 112 } 113 } else if (exp == 0x7ff) { 114 /* Infinity or NaN. */ 115 env->fpcr |= FPCR_INV; 116 arith_excp(env, GETPC(), EXC_M_INV, 0); 117 } 118 } 119 120 /* Similar, but does not trap for infinities. Used for comparisons. */ 121 void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) 122 { 123 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; 124 uint64_t frac = val & 0xfffffffffffffull; 125 126 if (exp == 0) { 127 /* Denormals without /S raise an exception. */ 128 if (frac != 0) { 129 arith_excp(env, GETPC(), EXC_M_INV, 0); 130 } 131 } else if (exp == 0x7ff && frac) { 132 /* NaN. */ 133 env->fpcr |= FPCR_INV; 134 arith_excp(env, GETPC(), EXC_M_INV, 0); 135 } 136 } 137 138 /* Input handing with software completion. Trap for denorms, unless DNZ 139 is set. If we try to support DNOD (which none of the produced hardware 140 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set; 141 then the code downstream of that will need to cope with denorms sans 142 flush_input_to_zero. Most of it should work sanely, but there's 143 nothing to compare with. */ 144 void helper_ieee_input_s(CPUAlphaState *env, uint64_t val) 145 { 146 if (unlikely(2 * val - 1 < 0x1fffffffffffffull) 147 && !env->fp_status.flush_inputs_to_zero) { 148 arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); 149 } 150 } 151 152 /* S floating (single) */ 153 154 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ 155 static inline uint64_t float32_to_s_int(uint32_t fi) 156 { 157 uint32_t frac = fi & 0x7fffff; 158 uint32_t sign = fi >> 31; 159 uint32_t exp_msb = (fi >> 30) & 1; 160 uint32_t exp_low = (fi >> 23) & 0x7f; 161 uint32_t exp; 162 163 exp = (exp_msb << 10) | exp_low; 164 if (exp_msb) { 165 if (exp_low == 0x7f) { 166 exp = 0x7ff; 167 } 168 } else { 169 if (exp_low != 0x00) { 170 exp |= 0x380; 171 } 172 } 173 174 return (((uint64_t)sign << 63) 175 | ((uint64_t)exp << 52) 176 | ((uint64_t)frac << 29)); 177 } 178 179 static inline uint64_t float32_to_s(float32 fa) 180 { 181 CPU_FloatU a; 182 a.f = fa; 183 return float32_to_s_int(a.l); 184 } 185 186 static inline uint32_t s_to_float32_int(uint64_t a) 187 { 188 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); 189 } 190 191 static inline float32 s_to_float32(uint64_t a) 192 { 193 CPU_FloatU r; 194 r.l = s_to_float32_int(a); 195 return r.f; 196 } 197 198 uint32_t helper_s_to_memory(uint64_t a) 199 { 200 return s_to_float32_int(a); 201 } 202 203 uint64_t helper_memory_to_s(uint32_t a) 204 { 205 return float32_to_s_int(a); 206 } 207 208 uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) 209 { 210 float32 fa, fb, fr; 211 212 fa = s_to_float32(a); 213 fb = s_to_float32(b); 214 fr = float32_add(fa, fb, &FP_STATUS); 215 env->error_code = soft_to_fpcr_exc(env); 216 217 return float32_to_s(fr); 218 } 219 220 uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) 221 { 222 float32 fa, fb, fr; 223 224 fa = s_to_float32(a); 225 fb = s_to_float32(b); 226 fr = float32_sub(fa, fb, &FP_STATUS); 227 env->error_code = soft_to_fpcr_exc(env); 228 229 return float32_to_s(fr); 230 } 231 232 uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) 233 { 234 float32 fa, fb, fr; 235 236 fa = s_to_float32(a); 237 fb = s_to_float32(b); 238 fr = float32_mul(fa, fb, &FP_STATUS); 239 env->error_code = soft_to_fpcr_exc(env); 240 241 return float32_to_s(fr); 242 } 243 244 uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) 245 { 246 float32 fa, fb, fr; 247 248 fa = s_to_float32(a); 249 fb = s_to_float32(b); 250 fr = float32_div(fa, fb, &FP_STATUS); 251 env->error_code = soft_to_fpcr_exc(env); 252 253 return float32_to_s(fr); 254 } 255 256 uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) 257 { 258 float32 fa, fr; 259 260 fa = s_to_float32(a); 261 fr = float32_sqrt(fa, &FP_STATUS); 262 env->error_code = soft_to_fpcr_exc(env); 263 264 return float32_to_s(fr); 265 } 266 267 268 /* T floating (double) */ 269 static inline float64 t_to_float64(uint64_t a) 270 { 271 /* Memory format is the same as float64 */ 272 CPU_DoubleU r; 273 r.ll = a; 274 return r.d; 275 } 276 277 static inline uint64_t float64_to_t(float64 fa) 278 { 279 /* Memory format is the same as float64 */ 280 CPU_DoubleU r; 281 r.d = fa; 282 return r.ll; 283 } 284 285 uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) 286 { 287 float64 fa, fb, fr; 288 289 fa = t_to_float64(a); 290 fb = t_to_float64(b); 291 fr = float64_add(fa, fb, &FP_STATUS); 292 env->error_code = soft_to_fpcr_exc(env); 293 294 return float64_to_t(fr); 295 } 296 297 uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) 298 { 299 float64 fa, fb, fr; 300 301 fa = t_to_float64(a); 302 fb = t_to_float64(b); 303 fr = float64_sub(fa, fb, &FP_STATUS); 304 env->error_code = soft_to_fpcr_exc(env); 305 306 return float64_to_t(fr); 307 } 308 309 uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) 310 { 311 float64 fa, fb, fr; 312 313 fa = t_to_float64(a); 314 fb = t_to_float64(b); 315 fr = float64_mul(fa, fb, &FP_STATUS); 316 env->error_code = soft_to_fpcr_exc(env); 317 318 return float64_to_t(fr); 319 } 320 321 uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) 322 { 323 float64 fa, fb, fr; 324 325 fa = t_to_float64(a); 326 fb = t_to_float64(b); 327 fr = float64_div(fa, fb, &FP_STATUS); 328 env->error_code = soft_to_fpcr_exc(env); 329 330 return float64_to_t(fr); 331 } 332 333 uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) 334 { 335 float64 fa, fr; 336 337 fa = t_to_float64(a); 338 fr = float64_sqrt(fa, &FP_STATUS); 339 env->error_code = soft_to_fpcr_exc(env); 340 341 return float64_to_t(fr); 342 } 343 344 /* Comparisons */ 345 uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) 346 { 347 float64 fa, fb; 348 uint64_t ret = 0; 349 350 fa = t_to_float64(a); 351 fb = t_to_float64(b); 352 353 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { 354 ret = 0x4000000000000000ULL; 355 } 356 env->error_code = soft_to_fpcr_exc(env); 357 358 return ret; 359 } 360 361 uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) 362 { 363 float64 fa, fb; 364 uint64_t ret = 0; 365 366 fa = t_to_float64(a); 367 fb = t_to_float64(b); 368 369 if (float64_eq_quiet(fa, fb, &FP_STATUS)) { 370 ret = 0x4000000000000000ULL; 371 } 372 env->error_code = soft_to_fpcr_exc(env); 373 374 return ret; 375 } 376 377 uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) 378 { 379 float64 fa, fb; 380 uint64_t ret = 0; 381 382 fa = t_to_float64(a); 383 fb = t_to_float64(b); 384 385 if (float64_le(fa, fb, &FP_STATUS)) { 386 ret = 0x4000000000000000ULL; 387 } 388 env->error_code = soft_to_fpcr_exc(env); 389 390 return ret; 391 } 392 393 uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) 394 { 395 float64 fa, fb; 396 uint64_t ret = 0; 397 398 fa = t_to_float64(a); 399 fb = t_to_float64(b); 400 401 if (float64_lt(fa, fb, &FP_STATUS)) { 402 ret = 0x4000000000000000ULL; 403 } 404 env->error_code = soft_to_fpcr_exc(env); 405 406 return ret; 407 } 408 409 /* Floating point format conversion */ 410 uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) 411 { 412 float64 fa; 413 float32 fr; 414 415 fa = t_to_float64(a); 416 fr = float64_to_float32(fa, &FP_STATUS); 417 env->error_code = soft_to_fpcr_exc(env); 418 419 return float32_to_s(fr); 420 } 421 422 uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) 423 { 424 float32 fa; 425 float64 fr; 426 427 fa = s_to_float32(a); 428 fr = float32_to_float64(fa, &FP_STATUS); 429 env->error_code = soft_to_fpcr_exc(env); 430 431 return float64_to_t(fr); 432 } 433 434 uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) 435 { 436 float32 fr = int64_to_float32(a, &FP_STATUS); 437 env->error_code = soft_to_fpcr_exc(env); 438 439 return float32_to_s(fr); 440 } 441 442 /* Implement float64 to uint64_t conversion without saturation -- we must 443 supply the truncated result. This behaviour is used by the compiler 444 to get unsigned conversion for free with the same instruction. */ 445 446 static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) 447 { 448 uint64_t frac, ret = 0; 449 uint32_t exp, sign, exc = 0; 450 int shift; 451 452 sign = (a >> 63); 453 exp = (uint32_t)(a >> 52) & 0x7ff; 454 frac = a & 0xfffffffffffffull; 455 456 if (exp == 0) { 457 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { 458 goto do_underflow; 459 } 460 } else if (exp == 0x7ff) { 461 exc = FPCR_INV; 462 } else { 463 /* Restore implicit bit. */ 464 frac |= 0x10000000000000ull; 465 466 shift = exp - 1023 - 52; 467 if (shift >= 0) { 468 /* In this case the number is so large that we must shift 469 the fraction left. There is no rounding to do. */ 470 if (shift < 64) { 471 ret = frac << shift; 472 } 473 /* Check for overflow. Note the special case of -0x1p63. */ 474 if (shift >= 11 && a != 0xC3E0000000000000ull) { 475 exc = FPCR_IOV | FPCR_INE; 476 } 477 } else { 478 uint64_t round; 479 480 /* In this case the number is smaller than the fraction as 481 represented by the 52 bit number. Here we must think 482 about rounding the result. Handle this by shifting the 483 fractional part of the number into the high bits of ROUND. 484 This will let us efficiently handle round-to-nearest. */ 485 shift = -shift; 486 if (shift < 63) { 487 ret = frac >> shift; 488 round = frac << (64 - shift); 489 } else { 490 /* The exponent is so small we shift out everything. 491 Leave a sticky bit for proper rounding below. */ 492 do_underflow: 493 round = 1; 494 } 495 496 if (round) { 497 exc = FPCR_INE; 498 switch (roundmode) { 499 case float_round_nearest_even: 500 if (round == (1ull << 63)) { 501 /* Fraction is exactly 0.5; round to even. */ 502 ret += (ret & 1); 503 } else if (round > (1ull << 63)) { 504 ret += 1; 505 } 506 break; 507 case float_round_to_zero: 508 break; 509 case float_round_up: 510 ret += 1 - sign; 511 break; 512 case float_round_down: 513 ret += sign; 514 break; 515 } 516 } 517 } 518 if (sign) { 519 ret = -ret; 520 } 521 } 522 env->error_code = exc; 523 524 return ret; 525 } 526 527 uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) 528 { 529 return do_cvttq(env, a, FP_STATUS.float_rounding_mode); 530 } 531 532 uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) 533 { 534 return do_cvttq(env, a, float_round_to_zero); 535 } 536 537 uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) 538 { 539 float64 fr = int64_to_float64(a, &FP_STATUS); 540 env->error_code = soft_to_fpcr_exc(env); 541 return float64_to_t(fr); 542 } 543 544 uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val) 545 { 546 uint32_t exc = 0; 547 if (val != (int32_t)val) { 548 exc = FPCR_IOV | FPCR_INE; 549 } 550 env->error_code = exc; 551 552 return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29); 553 } 554