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