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