1 /* 2 * FPU op helpers 3 * 4 * Copyright (c) 2003-2005 Fabrice Bellard 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 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 static inline float128 f128_in(Int128 i) 27 { 28 union { 29 Int128 i; 30 float128 f; 31 } u; 32 33 u.i = i; 34 return u.f; 35 } 36 37 static inline Int128 f128_ret(float128 f) 38 { 39 union { 40 Int128 i; 41 float128 f; 42 } u; 43 44 u.f = f; 45 return u.i; 46 } 47 48 static void check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra) 49 { 50 target_ulong status = get_float_exception_flags(&env->fp_status); 51 target_ulong fsr = env->fsr; 52 53 fsr &= FSR_FTT_CEXC_NMASK; 54 55 if (unlikely(status)) { 56 /* Keep exception flags clear for next time. */ 57 set_float_exception_flags(0, &env->fp_status); 58 59 /* Copy IEEE 754 flags into FSR */ 60 if (status & float_flag_invalid) { 61 fsr |= FSR_NVC; 62 } 63 if (status & float_flag_overflow) { 64 fsr |= FSR_OFC; 65 } 66 if (status & float_flag_underflow) { 67 fsr |= FSR_UFC; 68 } 69 if (status & float_flag_divbyzero) { 70 fsr |= FSR_DZC; 71 } 72 if (status & float_flag_inexact) { 73 fsr |= FSR_NXC; 74 } 75 76 if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) { 77 CPUState *cs = env_cpu(env); 78 79 /* Unmasked exception, generate a trap. Note that while 80 the helper is marked as NO_WG, we can get away with 81 writing to cpu state along the exception path, since 82 TCG generated code will never see the write. */ 83 env->fsr = fsr | FSR_FTT_IEEE_EXCP; 84 cs->exception_index = TT_FP_EXCP; 85 cpu_loop_exit_restore(cs, ra); 86 } else { 87 /* Accumulate exceptions */ 88 fsr |= (fsr & FSR_CEXC_MASK) << 5; 89 } 90 } 91 92 env->fsr = fsr; 93 } 94 95 float32 helper_fadds(CPUSPARCState *env, float32 src1, float32 src2) 96 { 97 float32 ret = float32_add(src1, src2, &env->fp_status); 98 check_ieee_exceptions(env, GETPC()); 99 return ret; 100 } 101 102 float32 helper_fsubs(CPUSPARCState *env, float32 src1, float32 src2) 103 { 104 float32 ret = float32_sub(src1, src2, &env->fp_status); 105 check_ieee_exceptions(env, GETPC()); 106 return ret; 107 } 108 109 float32 helper_fmuls(CPUSPARCState *env, float32 src1, float32 src2) 110 { 111 float32 ret = float32_mul(src1, src2, &env->fp_status); 112 check_ieee_exceptions(env, GETPC()); 113 return ret; 114 } 115 116 float32 helper_fdivs(CPUSPARCState *env, float32 src1, float32 src2) 117 { 118 float32 ret = float32_div(src1, src2, &env->fp_status); 119 check_ieee_exceptions(env, GETPC()); 120 return ret; 121 } 122 123 float64 helper_faddd(CPUSPARCState *env, float64 src1, float64 src2) 124 { 125 float64 ret = float64_add(src1, src2, &env->fp_status); 126 check_ieee_exceptions(env, GETPC()); 127 return ret; 128 } 129 130 float64 helper_fsubd(CPUSPARCState *env, float64 src1, float64 src2) 131 { 132 float64 ret = float64_sub(src1, src2, &env->fp_status); 133 check_ieee_exceptions(env, GETPC()); 134 return ret; 135 } 136 137 float64 helper_fmuld(CPUSPARCState *env, float64 src1, float64 src2) 138 { 139 float64 ret = float64_mul(src1, src2, &env->fp_status); 140 check_ieee_exceptions(env, GETPC()); 141 return ret; 142 } 143 144 float64 helper_fdivd(CPUSPARCState *env, float64 src1, float64 src2) 145 { 146 float64 ret = float64_div(src1, src2, &env->fp_status); 147 check_ieee_exceptions(env, GETPC()); 148 return ret; 149 } 150 151 Int128 helper_faddq(CPUSPARCState *env, Int128 src1, Int128 src2) 152 { 153 float128 ret = float128_add(f128_in(src1), f128_in(src2), &env->fp_status); 154 check_ieee_exceptions(env, GETPC()); 155 return f128_ret(ret); 156 } 157 158 Int128 helper_fsubq(CPUSPARCState *env, Int128 src1, Int128 src2) 159 { 160 float128 ret = float128_sub(f128_in(src1), f128_in(src2), &env->fp_status); 161 check_ieee_exceptions(env, GETPC()); 162 return f128_ret(ret); 163 } 164 165 Int128 helper_fmulq(CPUSPARCState *env, Int128 src1, Int128 src2) 166 { 167 float128 ret = float128_mul(f128_in(src1), f128_in(src2), &env->fp_status); 168 check_ieee_exceptions(env, GETPC()); 169 return f128_ret(ret); 170 } 171 172 Int128 helper_fdivq(CPUSPARCState *env, Int128 src1, Int128 src2) 173 { 174 float128 ret = float128_div(f128_in(src1), f128_in(src2), &env->fp_status); 175 check_ieee_exceptions(env, GETPC()); 176 return f128_ret(ret); 177 } 178 179 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2) 180 { 181 float64 ret = float64_mul(float32_to_float64(src1, &env->fp_status), 182 float32_to_float64(src2, &env->fp_status), 183 &env->fp_status); 184 check_ieee_exceptions(env, GETPC()); 185 return ret; 186 } 187 188 Int128 helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2) 189 { 190 float128 ret = float128_mul(float64_to_float128(src1, &env->fp_status), 191 float64_to_float128(src2, &env->fp_status), 192 &env->fp_status); 193 check_ieee_exceptions(env, GETPC()); 194 return f128_ret(ret); 195 } 196 197 /* Integer to float conversion. */ 198 float32 helper_fitos(CPUSPARCState *env, int32_t src) 199 { 200 float32 ret = int32_to_float32(src, &env->fp_status); 201 check_ieee_exceptions(env, GETPC()); 202 return ret; 203 } 204 205 float64 helper_fitod(CPUSPARCState *env, int32_t src) 206 { 207 float64 ret = int32_to_float64(src, &env->fp_status); 208 check_ieee_exceptions(env, GETPC()); 209 return ret; 210 } 211 212 Int128 helper_fitoq(CPUSPARCState *env, int32_t src) 213 { 214 float128 ret = int32_to_float128(src, &env->fp_status); 215 check_ieee_exceptions(env, GETPC()); 216 return f128_ret(ret); 217 } 218 219 #ifdef TARGET_SPARC64 220 float32 helper_fxtos(CPUSPARCState *env, int64_t src) 221 { 222 float32 ret = int64_to_float32(src, &env->fp_status); 223 check_ieee_exceptions(env, GETPC()); 224 return ret; 225 } 226 227 float64 helper_fxtod(CPUSPARCState *env, int64_t src) 228 { 229 float64 ret = int64_to_float64(src, &env->fp_status); 230 check_ieee_exceptions(env, GETPC()); 231 return ret; 232 } 233 234 Int128 helper_fxtoq(CPUSPARCState *env, int64_t src) 235 { 236 float128 ret = int64_to_float128(src, &env->fp_status); 237 check_ieee_exceptions(env, GETPC()); 238 return f128_ret(ret); 239 } 240 #endif 241 242 /* floating point conversion */ 243 float32 helper_fdtos(CPUSPARCState *env, float64 src) 244 { 245 float32 ret = float64_to_float32(src, &env->fp_status); 246 check_ieee_exceptions(env, GETPC()); 247 return ret; 248 } 249 250 float64 helper_fstod(CPUSPARCState *env, float32 src) 251 { 252 float64 ret = float32_to_float64(src, &env->fp_status); 253 check_ieee_exceptions(env, GETPC()); 254 return ret; 255 } 256 257 float32 helper_fqtos(CPUSPARCState *env, Int128 src) 258 { 259 float32 ret = float128_to_float32(f128_in(src), &env->fp_status); 260 check_ieee_exceptions(env, GETPC()); 261 return ret; 262 } 263 264 Int128 helper_fstoq(CPUSPARCState *env, float32 src) 265 { 266 float128 ret = float32_to_float128(src, &env->fp_status); 267 check_ieee_exceptions(env, GETPC()); 268 return f128_ret(ret); 269 } 270 271 float64 helper_fqtod(CPUSPARCState *env, Int128 src) 272 { 273 float64 ret = float128_to_float64(f128_in(src), &env->fp_status); 274 check_ieee_exceptions(env, GETPC()); 275 return ret; 276 } 277 278 Int128 helper_fdtoq(CPUSPARCState *env, float64 src) 279 { 280 float128 ret = float64_to_float128(src, &env->fp_status); 281 check_ieee_exceptions(env, GETPC()); 282 return f128_ret(ret); 283 } 284 285 /* Float to integer conversion. */ 286 int32_t helper_fstoi(CPUSPARCState *env, float32 src) 287 { 288 int32_t ret = float32_to_int32_round_to_zero(src, &env->fp_status); 289 check_ieee_exceptions(env, GETPC()); 290 return ret; 291 } 292 293 int32_t helper_fdtoi(CPUSPARCState *env, float64 src) 294 { 295 int32_t ret = float64_to_int32_round_to_zero(src, &env->fp_status); 296 check_ieee_exceptions(env, GETPC()); 297 return ret; 298 } 299 300 int32_t helper_fqtoi(CPUSPARCState *env, Int128 src) 301 { 302 int32_t ret = float128_to_int32_round_to_zero(f128_in(src), 303 &env->fp_status); 304 check_ieee_exceptions(env, GETPC()); 305 return ret; 306 } 307 308 #ifdef TARGET_SPARC64 309 int64_t helper_fstox(CPUSPARCState *env, float32 src) 310 { 311 int64_t ret = float32_to_int64_round_to_zero(src, &env->fp_status); 312 check_ieee_exceptions(env, GETPC()); 313 return ret; 314 } 315 316 int64_t helper_fdtox(CPUSPARCState *env, float64 src) 317 { 318 int64_t ret = float64_to_int64_round_to_zero(src, &env->fp_status); 319 check_ieee_exceptions(env, GETPC()); 320 return ret; 321 } 322 323 int64_t helper_fqtox(CPUSPARCState *env, Int128 src) 324 { 325 int64_t ret = float128_to_int64_round_to_zero(f128_in(src), 326 &env->fp_status); 327 check_ieee_exceptions(env, GETPC()); 328 return ret; 329 } 330 #endif 331 332 float32 helper_fsqrts(CPUSPARCState *env, float32 src) 333 { 334 float32 ret = float32_sqrt(src, &env->fp_status); 335 check_ieee_exceptions(env, GETPC()); 336 return ret; 337 } 338 339 float64 helper_fsqrtd(CPUSPARCState *env, float64 src) 340 { 341 float64 ret = float64_sqrt(src, &env->fp_status); 342 check_ieee_exceptions(env, GETPC()); 343 return ret; 344 } 345 346 Int128 helper_fsqrtq(CPUSPARCState *env, Int128 src) 347 { 348 float128 ret = float128_sqrt(f128_in(src), &env->fp_status); 349 check_ieee_exceptions(env, GETPC()); 350 return f128_ret(ret); 351 } 352 353 #define GEN_FCMP(name, size, FS, E) \ 354 target_ulong glue(helper_, name) (CPUSPARCState *env, \ 355 Int128 src1, Int128 src2) \ 356 { \ 357 float128 reg1 = f128_in(src1); \ 358 float128 reg2 = f128_in(src2); \ 359 FloatRelation ret; \ 360 target_ulong fsr; \ 361 if (E) { \ 362 ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ 363 } else { \ 364 ret = glue(size, _compare_quiet)(reg1, reg2, \ 365 &env->fp_status); \ 366 } \ 367 check_ieee_exceptions(env, GETPC()); \ 368 fsr = env->fsr; \ 369 switch (ret) { \ 370 case float_relation_unordered: \ 371 fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ 372 fsr |= FSR_NVA; \ 373 break; \ 374 case float_relation_less: \ 375 fsr &= ~(FSR_FCC1) << FS; \ 376 fsr |= FSR_FCC0 << FS; \ 377 break; \ 378 case float_relation_greater: \ 379 fsr &= ~(FSR_FCC0) << FS; \ 380 fsr |= FSR_FCC1 << FS; \ 381 break; \ 382 default: \ 383 fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ 384 break; \ 385 } \ 386 return fsr; \ 387 } 388 #define GEN_FCMP_T(name, size, FS, E) \ 389 target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\ 390 { \ 391 FloatRelation ret; \ 392 target_ulong fsr; \ 393 if (E) { \ 394 ret = glue(size, _compare)(src1, src2, &env->fp_status); \ 395 } else { \ 396 ret = glue(size, _compare_quiet)(src1, src2, \ 397 &env->fp_status); \ 398 } \ 399 check_ieee_exceptions(env, GETPC()); \ 400 fsr = env->fsr; \ 401 switch (ret) { \ 402 case float_relation_unordered: \ 403 fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ 404 break; \ 405 case float_relation_less: \ 406 fsr &= ~(FSR_FCC1 << FS); \ 407 fsr |= FSR_FCC0 << FS; \ 408 break; \ 409 case float_relation_greater: \ 410 fsr &= ~(FSR_FCC0 << FS); \ 411 fsr |= FSR_FCC1 << FS; \ 412 break; \ 413 default: \ 414 fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ 415 break; \ 416 } \ 417 return fsr; \ 418 } 419 420 GEN_FCMP_T(fcmps, float32, 0, 0); 421 GEN_FCMP_T(fcmpd, float64, 0, 0); 422 423 GEN_FCMP_T(fcmpes, float32, 0, 1); 424 GEN_FCMP_T(fcmped, float64, 0, 1); 425 426 GEN_FCMP(fcmpq, float128, 0, 0); 427 GEN_FCMP(fcmpeq, float128, 0, 1); 428 429 #ifdef TARGET_SPARC64 430 GEN_FCMP_T(fcmps_fcc1, float32, 22, 0); 431 GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0); 432 GEN_FCMP(fcmpq_fcc1, float128, 22, 0); 433 434 GEN_FCMP_T(fcmps_fcc2, float32, 24, 0); 435 GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0); 436 GEN_FCMP(fcmpq_fcc2, float128, 24, 0); 437 438 GEN_FCMP_T(fcmps_fcc3, float32, 26, 0); 439 GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0); 440 GEN_FCMP(fcmpq_fcc3, float128, 26, 0); 441 442 GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1); 443 GEN_FCMP_T(fcmped_fcc1, float64, 22, 1); 444 GEN_FCMP(fcmpeq_fcc1, float128, 22, 1); 445 446 GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1); 447 GEN_FCMP_T(fcmped_fcc2, float64, 24, 1); 448 GEN_FCMP(fcmpeq_fcc2, float128, 24, 1); 449 450 GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1); 451 GEN_FCMP_T(fcmped_fcc3, float64, 26, 1); 452 GEN_FCMP(fcmpeq_fcc3, float128, 26, 1); 453 #endif 454 #undef GEN_FCMP_T 455 #undef GEN_FCMP 456 457 target_ulong cpu_get_fsr(CPUSPARCState *env) 458 { 459 target_ulong fsr = env->fsr; 460 461 /* VER is kept completely separate until re-assembly. */ 462 fsr |= env->def.fpu_version; 463 464 return fsr; 465 } 466 467 target_ulong helper_get_fsr(CPUSPARCState *env) 468 { 469 return cpu_get_fsr(env); 470 } 471 472 static void set_fsr_nonsplit(CPUSPARCState *env, target_ulong fsr) 473 { 474 int rnd_mode; 475 476 env->fsr = fsr & ~FSR_VER_MASK; 477 478 switch (fsr & FSR_RD_MASK) { 479 case FSR_RD_NEAREST: 480 rnd_mode = float_round_nearest_even; 481 break; 482 default: 483 case FSR_RD_ZERO: 484 rnd_mode = float_round_to_zero; 485 break; 486 case FSR_RD_POS: 487 rnd_mode = float_round_up; 488 break; 489 case FSR_RD_NEG: 490 rnd_mode = float_round_down; 491 break; 492 } 493 set_float_rounding_mode(rnd_mode, &env->fp_status); 494 } 495 496 void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr) 497 { 498 set_fsr_nonsplit(env, fsr); 499 } 500 501 void helper_set_fsr(CPUSPARCState *env, target_ulong fsr) 502 { 503 set_fsr_nonsplit(env, fsr); 504 } 505