fpu_helper.c (13398B)
1/* 2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the Open Source and Linux Lab nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "qemu/osdep.h" 29#include "qemu/main-loop.h" 30#include "cpu.h" 31#include "exec/helper-proto.h" 32#include "qemu/host-utils.h" 33#include "exec/exec-all.h" 34#include "fpu/softfloat.h" 35 36enum { 37 XTENSA_FP_I = 0x1, 38 XTENSA_FP_U = 0x2, 39 XTENSA_FP_O = 0x4, 40 XTENSA_FP_Z = 0x8, 41 XTENSA_FP_V = 0x10, 42}; 43 44enum { 45 XTENSA_FCR_FLAGS_SHIFT = 2, 46 XTENSA_FSR_FLAGS_SHIFT = 7, 47}; 48 49static const struct { 50 uint32_t xtensa_fp_flag; 51 int softfloat_fp_flag; 52} xtensa_fp_flag_map[] = { 53 { XTENSA_FP_I, float_flag_inexact, }, 54 { XTENSA_FP_U, float_flag_underflow, }, 55 { XTENSA_FP_O, float_flag_overflow, }, 56 { XTENSA_FP_Z, float_flag_divbyzero, }, 57 { XTENSA_FP_V, float_flag_invalid, }, 58}; 59 60void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v) 61{ 62 static const int rounding_mode[] = { 63 float_round_nearest_even, 64 float_round_to_zero, 65 float_round_up, 66 float_round_down, 67 }; 68 69 env->uregs[FCR] = v & 0xfffff07f; 70 set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status); 71} 72 73void HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v) 74{ 75 static const int rounding_mode[] = { 76 float_round_nearest_even, 77 float_round_to_zero, 78 float_round_up, 79 float_round_down, 80 }; 81 82 if (v & 0xfffff000) { 83 qemu_log_mask(LOG_GUEST_ERROR, 84 "MBZ field of FCR is written non-zero: %08x\n", v); 85 } 86 env->uregs[FCR] = v & 0x0000007f; 87 set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status); 88} 89 90void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v) 91{ 92 uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT; 93 int fef = 0; 94 unsigned i; 95 96 if (v & 0xfffff000) { 97 qemu_log_mask(LOG_GUEST_ERROR, 98 "MBZ field of FSR is written non-zero: %08x\n", v); 99 } 100 env->uregs[FSR] = v & 0x00000f80; 101 for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) { 102 if (flags & xtensa_fp_flag_map[i].xtensa_fp_flag) { 103 fef |= xtensa_fp_flag_map[i].softfloat_fp_flag; 104 } 105 } 106 set_float_exception_flags(fef, &env->fp_status); 107} 108 109uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env) 110{ 111 uint32_t flags = 0; 112 int fef = get_float_exception_flags(&env->fp_status); 113 unsigned i; 114 115 for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) { 116 if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) { 117 flags |= xtensa_fp_flag_map[i].xtensa_fp_flag; 118 } 119 } 120 env->uregs[FSR] = flags << XTENSA_FSR_FLAGS_SHIFT; 121 return flags << XTENSA_FSR_FLAGS_SHIFT; 122} 123 124float64 HELPER(abs_d)(float64 v) 125{ 126 return float64_abs(v); 127} 128 129float32 HELPER(abs_s)(float32 v) 130{ 131 return float32_abs(v); 132} 133 134float64 HELPER(neg_d)(float64 v) 135{ 136 return float64_chs(v); 137} 138 139float32 HELPER(neg_s)(float32 v) 140{ 141 return float32_chs(v); 142} 143 144float32 HELPER(fpu2k_add_s)(CPUXtensaState *env, float32 a, float32 b) 145{ 146 return float32_add(a, b, &env->fp_status); 147} 148 149float32 HELPER(fpu2k_sub_s)(CPUXtensaState *env, float32 a, float32 b) 150{ 151 return float32_sub(a, b, &env->fp_status); 152} 153 154float32 HELPER(fpu2k_mul_s)(CPUXtensaState *env, float32 a, float32 b) 155{ 156 return float32_mul(a, b, &env->fp_status); 157} 158 159float32 HELPER(fpu2k_madd_s)(CPUXtensaState *env, 160 float32 a, float32 b, float32 c) 161{ 162 return float32_muladd(b, c, a, 0, &env->fp_status); 163} 164 165float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env, 166 float32 a, float32 b, float32 c) 167{ 168 return float32_muladd(b, c, a, float_muladd_negate_product, 169 &env->fp_status); 170} 171 172float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b) 173{ 174 set_use_first_nan(true, &env->fp_status); 175 return float64_add(a, b, &env->fp_status); 176} 177 178float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b) 179{ 180 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 181 return float32_add(a, b, &env->fp_status); 182} 183 184float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b) 185{ 186 set_use_first_nan(true, &env->fp_status); 187 return float64_sub(a, b, &env->fp_status); 188} 189 190float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b) 191{ 192 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 193 return float32_sub(a, b, &env->fp_status); 194} 195 196float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b) 197{ 198 set_use_first_nan(true, &env->fp_status); 199 return float64_mul(a, b, &env->fp_status); 200} 201 202float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b) 203{ 204 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 205 return float32_mul(a, b, &env->fp_status); 206} 207 208float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c) 209{ 210 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 211 return float64_muladd(b, c, a, 0, &env->fp_status); 212} 213 214float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) 215{ 216 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 217 return float32_muladd(b, c, a, 0, &env->fp_status); 218} 219 220float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c) 221{ 222 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 223 return float64_muladd(b, c, a, float_muladd_negate_product, 224 &env->fp_status); 225} 226 227float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) 228{ 229 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 230 return float32_muladd(b, c, a, float_muladd_negate_product, 231 &env->fp_status); 232} 233 234float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b) 235{ 236 set_use_first_nan(true, &env->fp_status); 237 return float64_div(b, a, &env->fp_status); 238} 239 240float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b) 241{ 242 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 243 return float32_div(b, a, &env->fp_status); 244} 245 246float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v) 247{ 248 set_use_first_nan(true, &env->fp_status); 249 return float64_sqrt(v, &env->fp_status); 250} 251 252float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v) 253{ 254 set_use_first_nan(env->config->use_first_nan, &env->fp_status); 255 return float32_sqrt(v, &env->fp_status); 256} 257 258uint32_t HELPER(ftoi_d)(CPUXtensaState *env, float64 v, 259 uint32_t rounding_mode, uint32_t scale) 260{ 261 float_status fp_status = env->fp_status; 262 uint32_t res; 263 264 set_float_rounding_mode(rounding_mode, &fp_status); 265 res = float64_to_int32(float64_scalbn(v, scale, &fp_status), &fp_status); 266 set_float_exception_flags(get_float_exception_flags(&fp_status), 267 &env->fp_status); 268 return res; 269} 270 271uint32_t HELPER(ftoi_s)(CPUXtensaState *env, float32 v, 272 uint32_t rounding_mode, uint32_t scale) 273{ 274 float_status fp_status = env->fp_status; 275 uint32_t res; 276 277 set_float_rounding_mode(rounding_mode, &fp_status); 278 res = float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status); 279 set_float_exception_flags(get_float_exception_flags(&fp_status), 280 &env->fp_status); 281 return res; 282} 283 284uint32_t HELPER(ftoui_d)(CPUXtensaState *env, float64 v, 285 uint32_t rounding_mode, uint32_t scale) 286{ 287 float_status fp_status = env->fp_status; 288 float64 res; 289 uint32_t rv; 290 291 set_float_rounding_mode(rounding_mode, &fp_status); 292 293 res = float64_scalbn(v, scale, &fp_status); 294 295 if (float64_is_neg(v) && !float64_is_any_nan(v)) { 296 set_float_exception_flags(float_flag_invalid, &fp_status); 297 rv = float64_to_int32(res, &fp_status); 298 } else { 299 rv = float64_to_uint32(res, &fp_status); 300 } 301 set_float_exception_flags(get_float_exception_flags(&fp_status), 302 &env->fp_status); 303 return rv; 304} 305 306uint32_t HELPER(ftoui_s)(CPUXtensaState *env, float32 v, 307 uint32_t rounding_mode, uint32_t scale) 308{ 309 float_status fp_status = env->fp_status; 310 float32 res; 311 uint32_t rv; 312 313 set_float_rounding_mode(rounding_mode, &fp_status); 314 315 res = float32_scalbn(v, scale, &fp_status); 316 317 if (float32_is_neg(v) && !float32_is_any_nan(v)) { 318 rv = float32_to_int32(res, &fp_status); 319 if (rv) { 320 set_float_exception_flags(float_flag_invalid, &fp_status); 321 } 322 } else { 323 rv = float32_to_uint32(res, &fp_status); 324 } 325 set_float_exception_flags(get_float_exception_flags(&fp_status), 326 &env->fp_status); 327 return rv; 328} 329 330float64 HELPER(itof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale) 331{ 332 return float64_scalbn(int32_to_float64(v, &env->fp_status), 333 (int32_t)scale, &env->fp_status); 334} 335 336float32 HELPER(itof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale) 337{ 338 return float32_scalbn(int32_to_float32(v, &env->fp_status), 339 (int32_t)scale, &env->fp_status); 340} 341 342float64 HELPER(uitof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale) 343{ 344 return float64_scalbn(uint32_to_float64(v, &env->fp_status), 345 (int32_t)scale, &env->fp_status); 346} 347 348float32 HELPER(uitof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale) 349{ 350 return float32_scalbn(uint32_to_float32(v, &env->fp_status), 351 (int32_t)scale, &env->fp_status); 352} 353 354float64 HELPER(cvtd_s)(CPUXtensaState *env, float32 v) 355{ 356 return float32_to_float64(v, &env->fp_status); 357} 358 359float32 HELPER(cvts_d)(CPUXtensaState *env, float64 v) 360{ 361 return float64_to_float32(v, &env->fp_status); 362} 363 364uint32_t HELPER(un_d)(CPUXtensaState *env, float64 a, float64 b) 365{ 366 return float64_unordered_quiet(a, b, &env->fp_status); 367} 368 369uint32_t HELPER(un_s)(CPUXtensaState *env, float32 a, float32 b) 370{ 371 return float32_unordered_quiet(a, b, &env->fp_status); 372} 373 374uint32_t HELPER(oeq_d)(CPUXtensaState *env, float64 a, float64 b) 375{ 376 return float64_eq_quiet(a, b, &env->fp_status); 377} 378 379uint32_t HELPER(oeq_s)(CPUXtensaState *env, float32 a, float32 b) 380{ 381 return float32_eq_quiet(a, b, &env->fp_status); 382} 383 384uint32_t HELPER(ueq_d)(CPUXtensaState *env, float64 a, float64 b) 385{ 386 FloatRelation v = float64_compare_quiet(a, b, &env->fp_status); 387 388 return v == float_relation_equal || 389 v == float_relation_unordered; 390} 391 392uint32_t HELPER(ueq_s)(CPUXtensaState *env, float32 a, float32 b) 393{ 394 FloatRelation v = float32_compare_quiet(a, b, &env->fp_status); 395 396 return v == float_relation_equal || 397 v == float_relation_unordered; 398} 399 400uint32_t HELPER(olt_d)(CPUXtensaState *env, float64 a, float64 b) 401{ 402 return float64_lt(a, b, &env->fp_status); 403} 404 405uint32_t HELPER(olt_s)(CPUXtensaState *env, float32 a, float32 b) 406{ 407 return float32_lt(a, b, &env->fp_status); 408} 409 410uint32_t HELPER(ult_d)(CPUXtensaState *env, float64 a, float64 b) 411{ 412 FloatRelation v = float64_compare_quiet(a, b, &env->fp_status); 413 414 return v == float_relation_less || 415 v == float_relation_unordered; 416} 417 418uint32_t HELPER(ult_s)(CPUXtensaState *env, float32 a, float32 b) 419{ 420 FloatRelation v = float32_compare_quiet(a, b, &env->fp_status); 421 422 return v == float_relation_less || 423 v == float_relation_unordered; 424} 425 426uint32_t HELPER(ole_d)(CPUXtensaState *env, float64 a, float64 b) 427{ 428 return float64_le(a, b, &env->fp_status); 429} 430 431uint32_t HELPER(ole_s)(CPUXtensaState *env, float32 a, float32 b) 432{ 433 return float32_le(a, b, &env->fp_status); 434} 435 436uint32_t HELPER(ule_d)(CPUXtensaState *env, float64 a, float64 b) 437{ 438 FloatRelation v = float64_compare_quiet(a, b, &env->fp_status); 439 440 return v != float_relation_greater; 441} 442 443uint32_t HELPER(ule_s)(CPUXtensaState *env, float32 a, float32 b) 444{ 445 FloatRelation v = float32_compare_quiet(a, b, &env->fp_status); 446 447 return v != float_relation_greater; 448}