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 float32 helper_fmadds(CPUSPARCState *env, float32 s1, 347 float32 s2, float32 s3, uint32_t op) 348 { 349 float32 ret = float32_muladd(s1, s2, s3, op, &env->fp_status); 350 check_ieee_exceptions(env, GETPC()); 351 return ret; 352 } 353 354 float64 helper_fmaddd(CPUSPARCState *env, float64 s1, 355 float64 s2, float64 s3, uint32_t op) 356 { 357 float64 ret = float64_muladd(s1, s2, s3, op, &env->fp_status); 358 check_ieee_exceptions(env, GETPC()); 359 return ret; 360 } 361 362 static uint32_t finish_fcmp(CPUSPARCState *env, FloatRelation r, uintptr_t ra) 363 { 364 check_ieee_exceptions(env, ra); 365 366 /* 367 * FCC values: 368 * 0 = 369 * 1 < 370 * 2 > 371 * 3 unordered 372 */ 373 switch (r) { 374 case float_relation_equal: 375 return 0; 376 case float_relation_less: 377 return 1; 378 case float_relation_greater: 379 return 2; 380 case float_relation_unordered: 381 env->fsr |= FSR_NVA; 382 return 3; 383 } 384 g_assert_not_reached(); 385 } 386 387 uint32_t helper_fcmps(CPUSPARCState *env, float32 src1, float32 src2) 388 { 389 FloatRelation r = float32_compare_quiet(src1, src2, &env->fp_status); 390 return finish_fcmp(env, r, GETPC()); 391 } 392 393 uint32_t helper_fcmpes(CPUSPARCState *env, float32 src1, float32 src2) 394 { 395 FloatRelation r = float32_compare(src1, src2, &env->fp_status); 396 return finish_fcmp(env, r, GETPC()); 397 } 398 399 uint32_t helper_fcmpd(CPUSPARCState *env, float64 src1, float64 src2) 400 { 401 FloatRelation r = float64_compare_quiet(src1, src2, &env->fp_status); 402 return finish_fcmp(env, r, GETPC()); 403 } 404 405 uint32_t helper_fcmped(CPUSPARCState *env, float64 src1, float64 src2) 406 { 407 FloatRelation r = float64_compare(src1, src2, &env->fp_status); 408 return finish_fcmp(env, r, GETPC()); 409 } 410 411 uint32_t helper_fcmpq(CPUSPARCState *env, Int128 src1, Int128 src2) 412 { 413 FloatRelation r = float128_compare_quiet(f128_in(src1), f128_in(src2), 414 &env->fp_status); 415 return finish_fcmp(env, r, GETPC()); 416 } 417 418 uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2) 419 { 420 FloatRelation r = float128_compare(f128_in(src1), f128_in(src2), 421 &env->fp_status); 422 return finish_fcmp(env, r, GETPC()); 423 } 424 425 target_ulong cpu_get_fsr(CPUSPARCState *env) 426 { 427 target_ulong fsr = env->fsr | env->fsr_cexc_ftt; 428 429 fsr |= env->fcc[0] << FSR_FCC0_SHIFT; 430 #ifdef TARGET_SPARC64 431 fsr |= (uint64_t)env->fcc[1] << FSR_FCC1_SHIFT; 432 fsr |= (uint64_t)env->fcc[2] << FSR_FCC2_SHIFT; 433 fsr |= (uint64_t)env->fcc[3] << FSR_FCC3_SHIFT; 434 #endif 435 436 /* VER is kept completely separate until re-assembly. */ 437 fsr |= env->def.fpu_version; 438 439 return fsr; 440 } 441 442 target_ulong helper_get_fsr(CPUSPARCState *env) 443 { 444 return cpu_get_fsr(env); 445 } 446 447 static void set_fsr_nonsplit(CPUSPARCState *env, target_ulong fsr) 448 { 449 int rnd_mode; 450 451 env->fsr = fsr & (FSR_RD_MASK | FSR_TEM_MASK | FSR_AEXC_MASK); 452 453 switch (fsr & FSR_RD_MASK) { 454 case FSR_RD_NEAREST: 455 rnd_mode = float_round_nearest_even; 456 break; 457 default: 458 case FSR_RD_ZERO: 459 rnd_mode = float_round_to_zero; 460 break; 461 case FSR_RD_POS: 462 rnd_mode = float_round_up; 463 break; 464 case FSR_RD_NEG: 465 rnd_mode = float_round_down; 466 break; 467 } 468 set_float_rounding_mode(rnd_mode, &env->fp_status); 469 } 470 471 void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr) 472 { 473 env->fsr_cexc_ftt = fsr & (FSR_CEXC_MASK | FSR_FTT_MASK); 474 475 env->fcc[0] = extract32(fsr, FSR_FCC0_SHIFT, 2); 476 #ifdef TARGET_SPARC64 477 env->fcc[1] = extract64(fsr, FSR_FCC1_SHIFT, 2); 478 env->fcc[2] = extract64(fsr, FSR_FCC2_SHIFT, 2); 479 env->fcc[3] = extract64(fsr, FSR_FCC3_SHIFT, 2); 480 #endif 481 482 set_fsr_nonsplit(env, fsr); 483 } 484 485 void helper_set_fsr_nofcc_noftt(CPUSPARCState *env, uint32_t fsr) 486 { 487 env->fsr_cexc_ftt &= FSR_FTT_MASK; 488 env->fsr_cexc_ftt |= fsr & FSR_CEXC_MASK; 489 set_fsr_nonsplit(env, fsr); 490 } 491