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