1 /* 2 * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "qemu.h" 20 #include "exec/helper-proto.h" 21 #include "fpu/softfloat.h" 22 #include "cpu.h" 23 #include "internal.h" 24 #include "macros.h" 25 #include "arch.h" 26 #include "hex_arch_types.h" 27 #include "fma_emu.h" 28 #include "conv_emu.h" 29 30 #define SF_BIAS 127 31 #define SF_MANTBITS 23 32 33 /* Exceptions processing helpers */ 34 static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env, 35 uint32_t exception, 36 uintptr_t pc) 37 { 38 CPUState *cs = CPU(hexagon_env_get_cpu(env)); 39 qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); 40 cs->exception_index = exception; 41 cpu_loop_exit_restore(cs, pc); 42 } 43 44 void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) 45 { 46 do_raise_exception_err(env, excp, 0); 47 } 48 49 static inline void log_reg_write(CPUHexagonState *env, int rnum, 50 target_ulong val, uint32_t slot) 51 { 52 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")", 53 rnum, val, val); 54 if (val == env->gpr[rnum]) { 55 HEX_DEBUG_LOG(" NO CHANGE"); 56 } 57 HEX_DEBUG_LOG("\n"); 58 59 env->new_value[rnum] = val; 60 #if HEX_DEBUG 61 /* Do this so HELPER(debug_commit_end) will know */ 62 env->reg_written[rnum] = 1; 63 #endif 64 } 65 66 static inline void log_pred_write(CPUHexagonState *env, int pnum, 67 target_ulong val) 68 { 69 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld 70 " (0x" TARGET_FMT_lx ")\n", 71 pnum, val, val); 72 73 /* Multiple writes to the same preg are and'ed together */ 74 if (env->pred_written & (1 << pnum)) { 75 env->new_pred_value[pnum] &= val & 0xff; 76 } else { 77 env->new_pred_value[pnum] = val & 0xff; 78 env->pred_written |= 1 << pnum; 79 } 80 } 81 82 static inline void log_store32(CPUHexagonState *env, target_ulong addr, 83 target_ulong val, int width, int slot) 84 { 85 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx 86 ", %" PRId32 " [0x08%" PRIx32 "])\n", 87 width, addr, val, val); 88 env->mem_log_stores[slot].va = addr; 89 env->mem_log_stores[slot].width = width; 90 env->mem_log_stores[slot].data32 = val; 91 } 92 93 static inline void log_store64(CPUHexagonState *env, target_ulong addr, 94 int64_t val, int width, int slot) 95 { 96 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx 97 ", %" PRId64 " [0x016%" PRIx64 "])\n", 98 width, addr, val, val); 99 env->mem_log_stores[slot].va = addr; 100 env->mem_log_stores[slot].width = width; 101 env->mem_log_stores[slot].data64 = val; 102 } 103 104 static inline void write_new_pc(CPUHexagonState *env, target_ulong addr) 105 { 106 HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr); 107 108 /* 109 * If more than one branch is taken in a packet, only the first one 110 * is actually done. 111 */ 112 if (env->branch_taken) { 113 HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, " 114 "ignoring the second one\n"); 115 } else { 116 fCHECK_PCALIGN(addr); 117 env->branch_taken = 1; 118 env->next_PC = addr; 119 } 120 } 121 122 #if HEX_DEBUG 123 /* Handy place to set a breakpoint */ 124 void HELPER(debug_start_packet)(CPUHexagonState *env) 125 { 126 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n", 127 env->gpr[HEX_REG_PC]); 128 129 for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) { 130 env->reg_written[i] = 0; 131 } 132 } 133 #endif 134 135 static inline int32_t new_pred_value(CPUHexagonState *env, int pnum) 136 { 137 return env->new_pred_value[pnum]; 138 } 139 140 #if HEX_DEBUG 141 /* Checks for bookkeeping errors between disassembly context and runtime */ 142 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check) 143 { 144 if (env->mem_log_stores[slot].width != check) { 145 HEX_DEBUG_LOG("ERROR: %d != %d\n", 146 env->mem_log_stores[slot].width, check); 147 g_assert_not_reached(); 148 } 149 } 150 #endif 151 152 void HELPER(commit_store)(CPUHexagonState *env, int slot_num) 153 { 154 switch (env->mem_log_stores[slot_num].width) { 155 case 1: 156 put_user_u8(env->mem_log_stores[slot_num].data32, 157 env->mem_log_stores[slot_num].va); 158 break; 159 case 2: 160 put_user_u16(env->mem_log_stores[slot_num].data32, 161 env->mem_log_stores[slot_num].va); 162 break; 163 case 4: 164 put_user_u32(env->mem_log_stores[slot_num].data32, 165 env->mem_log_stores[slot_num].va); 166 break; 167 case 8: 168 put_user_u64(env->mem_log_stores[slot_num].data64, 169 env->mem_log_stores[slot_num].va); 170 break; 171 default: 172 g_assert_not_reached(); 173 } 174 } 175 176 #if HEX_DEBUG 177 static void print_store(CPUHexagonState *env, int slot) 178 { 179 if (!(env->slot_cancelled & (1 << slot))) { 180 uint8_t width = env->mem_log_stores[slot].width; 181 if (width == 1) { 182 uint32_t data = env->mem_log_stores[slot].data32 & 0xff; 183 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32 184 " (0x%02" PRIx32 ")\n", 185 env->mem_log_stores[slot].va, data, data); 186 } else if (width == 2) { 187 uint32_t data = env->mem_log_stores[slot].data32 & 0xffff; 188 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32 189 " (0x%04" PRIx32 ")\n", 190 env->mem_log_stores[slot].va, data, data); 191 } else if (width == 4) { 192 uint32_t data = env->mem_log_stores[slot].data32; 193 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32 194 " (0x%08" PRIx32 ")\n", 195 env->mem_log_stores[slot].va, data, data); 196 } else if (width == 8) { 197 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64 198 " (0x%016" PRIx64 ")\n", 199 env->mem_log_stores[slot].va, 200 env->mem_log_stores[slot].data64, 201 env->mem_log_stores[slot].data64); 202 } else { 203 HEX_DEBUG_LOG("\tBad store width %d\n", width); 204 g_assert_not_reached(); 205 } 206 } 207 } 208 209 /* This function is a handy place to set a breakpoint */ 210 void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1) 211 { 212 bool reg_printed = false; 213 bool pred_printed = false; 214 int i; 215 216 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n", 217 env->this_PC); 218 HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled); 219 220 for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { 221 if (env->reg_written[i]) { 222 if (!reg_printed) { 223 HEX_DEBUG_LOG("Regs written\n"); 224 reg_printed = true; 225 } 226 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n", 227 i, env->new_value[i], env->new_value[i]); 228 } 229 } 230 231 for (i = 0; i < NUM_PREGS; i++) { 232 if (env->pred_written & (1 << i)) { 233 if (!pred_printed) { 234 HEX_DEBUG_LOG("Predicates written\n"); 235 pred_printed = true; 236 } 237 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n", 238 i, env->new_pred_value[i]); 239 } 240 } 241 242 if (has_st0 || has_st1) { 243 HEX_DEBUG_LOG("Stores\n"); 244 if (has_st0) { 245 print_store(env, 0); 246 } 247 if (has_st1) { 248 print_store(env, 1); 249 } 250 } 251 252 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC); 253 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx 254 ", insn = " TARGET_FMT_lx 255 "\n", 256 env->gpr[HEX_REG_QEMU_PKT_CNT], 257 env->gpr[HEX_REG_QEMU_INSN_CNT]); 258 259 } 260 #endif 261 262 static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS) 263 { 264 int32_t length = M & 0x0001ffff; 265 uint32_t new_ptr = RxV + offset; 266 uint32_t start_addr = CS; 267 uint32_t end_addr = start_addr + length; 268 269 if (new_ptr >= end_addr) { 270 new_ptr -= length; 271 } else if (new_ptr < start_addr) { 272 new_ptr += length; 273 } 274 275 return new_ptr; 276 } 277 278 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) 279 { 280 int32_t K_const = (M >> 24) & 0xf; 281 int32_t length = M & 0x1ffff; 282 int32_t mask = (1 << (K_const + 2)) - 1; 283 uint32_t new_ptr = RxV + offset; 284 uint32_t start_addr = RxV & (~mask); 285 uint32_t end_addr = start_addr | length; 286 287 if (K_const == 0 && length >= 4) { 288 return fcircadd_v4(RxV, offset, M, CS); 289 } 290 291 if (new_ptr >= end_addr) { 292 new_ptr -= length; 293 } else if (new_ptr < start_addr) { 294 new_ptr += length; 295 } 296 297 return new_ptr; 298 } 299 300 /* 301 * Hexagon FP operations return ~0 insteat of NaN 302 * The hex_check_sfnan/hex_check_dfnan functions perform this check 303 */ 304 static float32 hex_check_sfnan(float32 x) 305 { 306 if (float32_is_any_nan(x)) { 307 return make_float32(0xFFFFFFFFU); 308 } 309 return x; 310 } 311 312 static float64 hex_check_dfnan(float64 x) 313 { 314 if (float64_is_any_nan(x)) { 315 return make_float64(0xFFFFFFFFFFFFFFFFULL); 316 } 317 return x; 318 } 319 320 /* 321 * mem_noshuf 322 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual 323 * 324 * If the load is in slot 0 and there is a store in slot1 (that 325 * wasn't cancelled), we have to do the store first. 326 */ 327 static void check_noshuf(CPUHexagonState *env, uint32_t slot) 328 { 329 if (slot == 0 && env->pkt_has_store_s1 && 330 ((env->slot_cancelled & (1 << 1)) == 0)) { 331 HELPER(commit_store)(env, 1); 332 } 333 } 334 335 static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, 336 target_ulong vaddr) 337 { 338 uint8_t retval; 339 check_noshuf(env, slot); 340 get_user_u8(retval, vaddr); 341 return retval; 342 } 343 344 static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, 345 target_ulong vaddr) 346 { 347 uint16_t retval; 348 check_noshuf(env, slot); 349 get_user_u16(retval, vaddr); 350 return retval; 351 } 352 353 static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, 354 target_ulong vaddr) 355 { 356 uint32_t retval; 357 check_noshuf(env, slot); 358 get_user_u32(retval, vaddr); 359 return retval; 360 } 361 362 static inline uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, 363 target_ulong vaddr) 364 { 365 uint64_t retval; 366 check_noshuf(env, slot); 367 get_user_u64(retval, vaddr); 368 return retval; 369 } 370 371 /* Floating point */ 372 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV) 373 { 374 float64 out_f64; 375 arch_fpop_start(env); 376 out_f64 = float32_to_float64(RsV, &env->fp_status); 377 out_f64 = hex_check_dfnan(out_f64); 378 arch_fpop_end(env); 379 return out_f64; 380 } 381 382 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV) 383 { 384 float32 out_f32; 385 arch_fpop_start(env); 386 out_f32 = float64_to_float32(RssV, &env->fp_status); 387 out_f32 = hex_check_sfnan(out_f32); 388 arch_fpop_end(env); 389 return out_f32; 390 } 391 392 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV) 393 { 394 float32 RdV; 395 arch_fpop_start(env); 396 RdV = uint32_to_float32(RsV, &env->fp_status); 397 RdV = hex_check_sfnan(RdV); 398 arch_fpop_end(env); 399 return RdV; 400 } 401 402 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV) 403 { 404 float64 RddV; 405 arch_fpop_start(env); 406 RddV = uint32_to_float64(RsV, &env->fp_status); 407 RddV = hex_check_dfnan(RddV); 408 arch_fpop_end(env); 409 return RddV; 410 } 411 412 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV) 413 { 414 float32 RdV; 415 arch_fpop_start(env); 416 RdV = int32_to_float32(RsV, &env->fp_status); 417 RdV = hex_check_sfnan(RdV); 418 arch_fpop_end(env); 419 return RdV; 420 } 421 422 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV) 423 { 424 float64 RddV; 425 arch_fpop_start(env); 426 RddV = int32_to_float64(RsV, &env->fp_status); 427 RddV = hex_check_dfnan(RddV); 428 arch_fpop_end(env); 429 return RddV; 430 } 431 432 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV) 433 { 434 float32 RdV; 435 arch_fpop_start(env); 436 RdV = uint64_to_float32(RssV, &env->fp_status); 437 RdV = hex_check_sfnan(RdV); 438 arch_fpop_end(env); 439 return RdV; 440 } 441 442 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV) 443 { 444 float64 RddV; 445 arch_fpop_start(env); 446 RddV = uint64_to_float64(RssV, &env->fp_status); 447 RddV = hex_check_dfnan(RddV); 448 arch_fpop_end(env); 449 return RddV; 450 } 451 452 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV) 453 { 454 float32 RdV; 455 arch_fpop_start(env); 456 RdV = int64_to_float32(RssV, &env->fp_status); 457 RdV = hex_check_sfnan(RdV); 458 arch_fpop_end(env); 459 return RdV; 460 } 461 462 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV) 463 { 464 float64 RddV; 465 arch_fpop_start(env); 466 RddV = int64_to_float64(RssV, &env->fp_status); 467 RddV = hex_check_dfnan(RddV); 468 arch_fpop_end(env); 469 return RddV; 470 } 471 472 int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV) 473 { 474 int32_t RdV; 475 arch_fpop_start(env); 476 RdV = conv_sf_to_4u(RsV, &env->fp_status); 477 arch_fpop_end(env); 478 return RdV; 479 } 480 481 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV) 482 { 483 int32_t RdV; 484 arch_fpop_start(env); 485 RdV = conv_sf_to_4s(RsV, &env->fp_status); 486 arch_fpop_end(env); 487 return RdV; 488 } 489 490 int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV) 491 { 492 int64_t RddV; 493 arch_fpop_start(env); 494 RddV = conv_sf_to_8u(RsV, &env->fp_status); 495 arch_fpop_end(env); 496 return RddV; 497 } 498 499 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV) 500 { 501 int64_t RddV; 502 arch_fpop_start(env); 503 RddV = conv_sf_to_8s(RsV, &env->fp_status); 504 arch_fpop_end(env); 505 return RddV; 506 } 507 508 int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV) 509 { 510 int32_t RdV; 511 arch_fpop_start(env); 512 RdV = conv_df_to_4u(RssV, &env->fp_status); 513 arch_fpop_end(env); 514 return RdV; 515 } 516 517 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV) 518 { 519 int32_t RdV; 520 arch_fpop_start(env); 521 RdV = conv_df_to_4s(RssV, &env->fp_status); 522 arch_fpop_end(env); 523 return RdV; 524 } 525 526 int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV) 527 { 528 int64_t RddV; 529 arch_fpop_start(env); 530 RddV = conv_df_to_8u(RssV, &env->fp_status); 531 arch_fpop_end(env); 532 return RddV; 533 } 534 535 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV) 536 { 537 int64_t RddV; 538 arch_fpop_start(env); 539 RddV = conv_df_to_8s(RssV, &env->fp_status); 540 arch_fpop_end(env); 541 return RddV; 542 } 543 544 int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV) 545 { 546 int32_t RdV; 547 arch_fpop_start(env); 548 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 549 RdV = conv_sf_to_4u(RsV, &env->fp_status); 550 arch_fpop_end(env); 551 return RdV; 552 } 553 554 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV) 555 { 556 int32_t RdV; 557 arch_fpop_start(env); 558 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 559 RdV = conv_sf_to_4s(RsV, &env->fp_status); 560 arch_fpop_end(env); 561 return RdV; 562 } 563 564 int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV) 565 { 566 int64_t RddV; 567 arch_fpop_start(env); 568 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 569 RddV = conv_sf_to_8u(RsV, &env->fp_status); 570 arch_fpop_end(env); 571 return RddV; 572 } 573 574 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV) 575 { 576 int64_t RddV; 577 arch_fpop_start(env); 578 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 579 RddV = conv_sf_to_8s(RsV, &env->fp_status); 580 arch_fpop_end(env); 581 return RddV; 582 } 583 584 int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV) 585 { 586 int32_t RdV; 587 arch_fpop_start(env); 588 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 589 RdV = conv_df_to_4u(RssV, &env->fp_status); 590 arch_fpop_end(env); 591 return RdV; 592 } 593 594 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV) 595 { 596 int32_t RdV; 597 arch_fpop_start(env); 598 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 599 RdV = conv_df_to_4s(RssV, &env->fp_status); 600 arch_fpop_end(env); 601 return RdV; 602 } 603 604 int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV) 605 { 606 int64_t RddV; 607 arch_fpop_start(env); 608 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 609 RddV = conv_df_to_8u(RssV, &env->fp_status); 610 arch_fpop_end(env); 611 return RddV; 612 } 613 614 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV) 615 { 616 int64_t RddV; 617 arch_fpop_start(env); 618 set_float_rounding_mode(float_round_to_zero, &env->fp_status); 619 RddV = conv_df_to_8s(RssV, &env->fp_status); 620 arch_fpop_end(env); 621 return RddV; 622 } 623 624 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV) 625 { 626 float32 RdV; 627 arch_fpop_start(env); 628 RdV = float32_add(RsV, RtV, &env->fp_status); 629 RdV = hex_check_sfnan(RdV); 630 arch_fpop_end(env); 631 return RdV; 632 } 633 634 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV) 635 { 636 float32 RdV; 637 arch_fpop_start(env); 638 RdV = float32_sub(RsV, RtV, &env->fp_status); 639 RdV = hex_check_sfnan(RdV); 640 arch_fpop_end(env); 641 return RdV; 642 } 643 644 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV) 645 { 646 int32_t PdV; 647 arch_fpop_start(env); 648 PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status)); 649 arch_fpop_end(env); 650 return PdV; 651 } 652 653 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV) 654 { 655 int cmp; 656 int32_t PdV; 657 arch_fpop_start(env); 658 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status); 659 PdV = f8BITSOF(cmp == float_relation_greater); 660 arch_fpop_end(env); 661 return PdV; 662 } 663 664 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV) 665 { 666 int cmp; 667 int32_t PdV; 668 arch_fpop_start(env); 669 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status); 670 PdV = f8BITSOF(cmp == float_relation_greater || 671 cmp == float_relation_equal); 672 arch_fpop_end(env); 673 return PdV; 674 } 675 676 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV) 677 { 678 int32_t PdV; 679 arch_fpop_start(env); 680 PdV = f8BITSOF(float32_is_any_nan(RsV) || 681 float32_is_any_nan(RtV)); 682 arch_fpop_end(env); 683 return PdV; 684 } 685 686 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV) 687 { 688 float32 RdV; 689 arch_fpop_start(env); 690 RdV = float32_maxnum(RsV, RtV, &env->fp_status); 691 RdV = hex_check_sfnan(RdV); 692 arch_fpop_end(env); 693 return RdV; 694 } 695 696 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV) 697 { 698 float32 RdV; 699 arch_fpop_start(env); 700 RdV = float32_minnum(RsV, RtV, &env->fp_status); 701 RdV = hex_check_sfnan(RdV); 702 arch_fpop_end(env); 703 return RdV; 704 } 705 706 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV) 707 { 708 int32_t PdV = 0; 709 arch_fpop_start(env); 710 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) { 711 PdV = 0xff; 712 } 713 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) { 714 PdV = 0xff; 715 } 716 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) { 717 PdV = 0xff; 718 } 719 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) { 720 PdV = 0xff; 721 } 722 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) { 723 PdV = 0xff; 724 } 725 set_float_exception_flags(0, &env->fp_status); 726 arch_fpop_end(env); 727 return PdV; 728 } 729 730 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV) 731 { 732 float32 RdV = 0; 733 int adjust; 734 arch_fpop_start(env); 735 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status); 736 RdV = RsV; 737 arch_fpop_end(env); 738 return RdV; 739 } 740 741 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV) 742 { 743 float32 RdV = 0; 744 int adjust; 745 arch_fpop_start(env); 746 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status); 747 RdV = RtV; 748 arch_fpop_end(env); 749 return RdV; 750 } 751 752 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV) 753 { 754 float32 RdV = 0; 755 int adjust; 756 arch_fpop_start(env); 757 arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status); 758 RdV = RsV; 759 arch_fpop_end(env); 760 return RdV; 761 } 762 763 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV) 764 { 765 float64 RddV; 766 arch_fpop_start(env); 767 RddV = float64_add(RssV, RttV, &env->fp_status); 768 RddV = hex_check_dfnan(RddV); 769 arch_fpop_end(env); 770 return RddV; 771 } 772 773 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV) 774 { 775 float64 RddV; 776 arch_fpop_start(env); 777 RddV = float64_sub(RssV, RttV, &env->fp_status); 778 RddV = hex_check_dfnan(RddV); 779 arch_fpop_end(env); 780 return RddV; 781 } 782 783 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV) 784 { 785 float64 RddV; 786 arch_fpop_start(env); 787 RddV = float64_maxnum(RssV, RttV, &env->fp_status); 788 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) { 789 float_raise(float_flag_invalid, &env->fp_status); 790 } 791 RddV = hex_check_dfnan(RddV); 792 arch_fpop_end(env); 793 return RddV; 794 } 795 796 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV) 797 { 798 float64 RddV; 799 arch_fpop_start(env); 800 RddV = float64_minnum(RssV, RttV, &env->fp_status); 801 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) { 802 float_raise(float_flag_invalid, &env->fp_status); 803 } 804 RddV = hex_check_dfnan(RddV); 805 arch_fpop_end(env); 806 return RddV; 807 } 808 809 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV) 810 { 811 int32_t PdV; 812 arch_fpop_start(env); 813 PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status)); 814 arch_fpop_end(env); 815 return PdV; 816 } 817 818 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV) 819 { 820 int cmp; 821 int32_t PdV; 822 arch_fpop_start(env); 823 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status); 824 PdV = f8BITSOF(cmp == float_relation_greater); 825 arch_fpop_end(env); 826 return PdV; 827 } 828 829 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV) 830 { 831 int cmp; 832 int32_t PdV; 833 arch_fpop_start(env); 834 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status); 835 PdV = f8BITSOF(cmp == float_relation_greater || 836 cmp == float_relation_equal); 837 arch_fpop_end(env); 838 return PdV; 839 } 840 841 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV) 842 { 843 int32_t PdV; 844 arch_fpop_start(env); 845 PdV = f8BITSOF(float64_is_any_nan(RssV) || 846 float64_is_any_nan(RttV)); 847 arch_fpop_end(env); 848 return PdV; 849 } 850 851 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV) 852 { 853 int32_t PdV = 0; 854 arch_fpop_start(env); 855 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) { 856 PdV = 0xff; 857 } 858 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) { 859 PdV = 0xff; 860 } 861 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) { 862 PdV = 0xff; 863 } 864 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) { 865 PdV = 0xff; 866 } 867 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) { 868 PdV = 0xff; 869 } 870 set_float_exception_flags(0, &env->fp_status); 871 arch_fpop_end(env); 872 return PdV; 873 } 874 875 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV) 876 { 877 float32 RdV; 878 arch_fpop_start(env); 879 RdV = internal_mpyf(RsV, RtV, &env->fp_status); 880 RdV = hex_check_sfnan(RdV); 881 arch_fpop_end(env); 882 return RdV; 883 } 884 885 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV, 886 float32 RsV, float32 RtV) 887 { 888 arch_fpop_start(env); 889 RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); 890 RxV = hex_check_sfnan(RxV); 891 arch_fpop_end(env); 892 return RxV; 893 } 894 895 static bool is_zero_prod(float32 a, float32 b) 896 { 897 return ((float32_is_zero(a) && is_finite(b)) || 898 (float32_is_zero(b) && is_finite(a))); 899 } 900 901 static float32 check_nan(float32 dst, float32 x, float_status *fp_status) 902 { 903 float32 ret = dst; 904 if (float32_is_any_nan(x)) { 905 if (extract32(x, 22, 1) == 0) { 906 float_raise(float_flag_invalid, fp_status); 907 } 908 ret = make_float32(0xffffffff); /* nan */ 909 } 910 return ret; 911 } 912 913 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV, 914 float32 RsV, float32 RtV, float32 PuV) 915 { 916 size4s_t tmp; 917 arch_fpop_start(env); 918 RxV = check_nan(RxV, RxV, &env->fp_status); 919 RxV = check_nan(RxV, RsV, &env->fp_status); 920 RxV = check_nan(RxV, RtV, &env->fp_status); 921 tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status); 922 tmp = hex_check_sfnan(tmp); 923 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 924 RxV = tmp; 925 } 926 arch_fpop_end(env); 927 return RxV; 928 } 929 930 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV, 931 float32 RsV, float32 RtV) 932 { 933 float32 neg_RsV; 934 arch_fpop_start(env); 935 neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status); 936 RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status); 937 RxV = hex_check_sfnan(RxV); 938 arch_fpop_end(env); 939 return RxV; 940 } 941 942 static inline bool is_inf_prod(int32_t a, int32_t b) 943 { 944 return (float32_is_infinity(a) && float32_is_infinity(b)) || 945 (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) || 946 (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a)); 947 } 948 949 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, 950 float32 RsV, float32 RtV) 951 { 952 int infinp; 953 int infminusinf; 954 float32 tmp; 955 956 arch_fpop_start(env); 957 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 958 infminusinf = float32_is_infinity(RxV) && 959 is_inf_prod(RsV, RtV) && 960 (fGETBIT(31, RsV ^ RxV ^ RtV) != 0); 961 infinp = float32_is_infinity(RxV) || 962 float32_is_infinity(RtV) || 963 float32_is_infinity(RsV); 964 RxV = check_nan(RxV, RxV, &env->fp_status); 965 RxV = check_nan(RxV, RsV, &env->fp_status); 966 RxV = check_nan(RxV, RtV, &env->fp_status); 967 tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); 968 tmp = hex_check_sfnan(tmp); 969 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 970 RxV = tmp; 971 } 972 set_float_exception_flags(0, &env->fp_status); 973 if (float32_is_infinity(RxV) && !infinp) { 974 RxV = RxV - 1; 975 } 976 if (infminusinf) { 977 RxV = 0; 978 } 979 arch_fpop_end(env); 980 return RxV; 981 } 982 983 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV, 984 float32 RsV, float32 RtV) 985 { 986 int infinp; 987 int infminusinf; 988 float32 tmp; 989 990 arch_fpop_start(env); 991 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 992 infminusinf = float32_is_infinity(RxV) && 993 is_inf_prod(RsV, RtV) && 994 (fGETBIT(31, RsV ^ RxV ^ RtV) == 0); 995 infinp = float32_is_infinity(RxV) || 996 float32_is_infinity(RtV) || 997 float32_is_infinity(RsV); 998 RxV = check_nan(RxV, RxV, &env->fp_status); 999 RxV = check_nan(RxV, RsV, &env->fp_status); 1000 RxV = check_nan(RxV, RtV, &env->fp_status); 1001 float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status); 1002 tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status); 1003 tmp = hex_check_sfnan(tmp); 1004 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1005 RxV = tmp; 1006 } 1007 set_float_exception_flags(0, &env->fp_status); 1008 if (float32_is_infinity(RxV) && !infinp) { 1009 RxV = RxV - 1; 1010 } 1011 if (infminusinf) { 1012 RxV = 0; 1013 } 1014 arch_fpop_end(env); 1015 return RxV; 1016 } 1017 1018 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV) 1019 { 1020 int64_t RddV; 1021 arch_fpop_start(env); 1022 if (float64_is_denormal(RssV) && 1023 (float64_getexp(RttV) >= 512) && 1024 float64_is_normal(RttV)) { 1025 RddV = float64_mul(RssV, make_float64(0x4330000000000000), 1026 &env->fp_status); 1027 RddV = hex_check_dfnan(RddV); 1028 } else if (float64_is_denormal(RttV) && 1029 (float64_getexp(RssV) >= 512) && 1030 float64_is_normal(RssV)) { 1031 RddV = float64_mul(RssV, make_float64(0x3cb0000000000000), 1032 &env->fp_status); 1033 RddV = hex_check_dfnan(RddV); 1034 } else { 1035 RddV = RssV; 1036 } 1037 arch_fpop_end(env); 1038 return RddV; 1039 } 1040 1041 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV, 1042 float64 RssV, float64 RttV) 1043 { 1044 arch_fpop_start(env); 1045 RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status); 1046 RxxV = hex_check_dfnan(RxxV); 1047 arch_fpop_end(env); 1048 return RxxV; 1049 } 1050 1051 static void cancel_slot(CPUHexagonState *env, uint32_t slot) 1052 { 1053 HEX_DEBUG_LOG("Slot %d cancelled\n", slot); 1054 env->slot_cancelled |= (1 << slot); 1055 } 1056 1057 /* These macros can be referenced in the generated helper functions */ 1058 #define warn(...) /* Nothing */ 1059 #define fatal(...) g_assert_not_reached(); 1060 1061 #define BOGUS_HELPER(tag) \ 1062 printf("ERROR: bogus helper: " #tag "\n") 1063 1064 #include "helper_funcs_generated.c.inc" 1065