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