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