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 static void probe_store(CPUHexagonState *env, int slot, int mmu_idx) 381 { 382 if (!(env->slot_cancelled & (1 << slot))) { 383 size1u_t width = env->mem_log_stores[slot].width; 384 target_ulong va = env->mem_log_stores[slot].va; 385 uintptr_t ra = GETPC(); 386 probe_write(env, va, width, mmu_idx, ra); 387 } 388 } 389 390 /* Called during packet commit when there are two scalar stores */ 391 void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int mmu_idx) 392 { 393 probe_store(env, 0, mmu_idx); 394 } 395 396 /* 397 * mem_noshuf 398 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual 399 * 400 * If the load is in slot 0 and there is a store in slot1 (that 401 * wasn't cancelled), we have to do the store first. 402 */ 403 static void check_noshuf(CPUHexagonState *env, uint32_t slot) 404 { 405 if (slot == 0 && env->pkt_has_store_s1 && 406 ((env->slot_cancelled & (1 << 1)) == 0)) { 407 HELPER(commit_store)(env, 1); 408 } 409 } 410 411 static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot, 412 target_ulong vaddr) 413 { 414 uintptr_t ra = GETPC(); 415 check_noshuf(env, slot); 416 return cpu_ldub_data_ra(env, vaddr, ra); 417 } 418 419 static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot, 420 target_ulong vaddr) 421 { 422 uintptr_t ra = GETPC(); 423 check_noshuf(env, slot); 424 return cpu_lduw_data_ra(env, vaddr, ra); 425 } 426 427 static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot, 428 target_ulong vaddr) 429 { 430 uintptr_t ra = GETPC(); 431 check_noshuf(env, slot); 432 return cpu_ldl_data_ra(env, vaddr, ra); 433 } 434 435 static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot, 436 target_ulong vaddr) 437 { 438 uintptr_t ra = GETPC(); 439 check_noshuf(env, slot); 440 return cpu_ldq_data_ra(env, vaddr, ra); 441 } 442 443 /* Floating point */ 444 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV) 445 { 446 float64 out_f64; 447 arch_fpop_start(env); 448 out_f64 = float32_to_float64(RsV, &env->fp_status); 449 arch_fpop_end(env); 450 return out_f64; 451 } 452 453 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV) 454 { 455 float32 out_f32; 456 arch_fpop_start(env); 457 out_f32 = float64_to_float32(RssV, &env->fp_status); 458 arch_fpop_end(env); 459 return out_f32; 460 } 461 462 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV) 463 { 464 float32 RdV; 465 arch_fpop_start(env); 466 RdV = uint32_to_float32(RsV, &env->fp_status); 467 arch_fpop_end(env); 468 return RdV; 469 } 470 471 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV) 472 { 473 float64 RddV; 474 arch_fpop_start(env); 475 RddV = uint32_to_float64(RsV, &env->fp_status); 476 arch_fpop_end(env); 477 return RddV; 478 } 479 480 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV) 481 { 482 float32 RdV; 483 arch_fpop_start(env); 484 RdV = int32_to_float32(RsV, &env->fp_status); 485 arch_fpop_end(env); 486 return RdV; 487 } 488 489 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV) 490 { 491 float64 RddV; 492 arch_fpop_start(env); 493 RddV = int32_to_float64(RsV, &env->fp_status); 494 arch_fpop_end(env); 495 return RddV; 496 } 497 498 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV) 499 { 500 float32 RdV; 501 arch_fpop_start(env); 502 RdV = uint64_to_float32(RssV, &env->fp_status); 503 arch_fpop_end(env); 504 return RdV; 505 } 506 507 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV) 508 { 509 float64 RddV; 510 arch_fpop_start(env); 511 RddV = uint64_to_float64(RssV, &env->fp_status); 512 arch_fpop_end(env); 513 return RddV; 514 } 515 516 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV) 517 { 518 float32 RdV; 519 arch_fpop_start(env); 520 RdV = int64_to_float32(RssV, &env->fp_status); 521 arch_fpop_end(env); 522 return RdV; 523 } 524 525 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV) 526 { 527 float64 RddV; 528 arch_fpop_start(env); 529 RddV = int64_to_float64(RssV, &env->fp_status); 530 arch_fpop_end(env); 531 return RddV; 532 } 533 534 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV) 535 { 536 uint32_t RdV; 537 arch_fpop_start(env); 538 /* Hexagon checks the sign before rounding */ 539 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 540 float_raise(float_flag_invalid, &env->fp_status); 541 RdV = 0; 542 } else { 543 RdV = float32_to_uint32(RsV, &env->fp_status); 544 } 545 arch_fpop_end(env); 546 return RdV; 547 } 548 549 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV) 550 { 551 int32_t RdV; 552 arch_fpop_start(env); 553 /* Hexagon returns -1 for NaN */ 554 if (float32_is_any_nan(RsV)) { 555 float_raise(float_flag_invalid, &env->fp_status); 556 RdV = -1; 557 } else { 558 RdV = float32_to_int32(RsV, &env->fp_status); 559 } 560 arch_fpop_end(env); 561 return RdV; 562 } 563 564 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV) 565 { 566 uint64_t RddV; 567 arch_fpop_start(env); 568 /* Hexagon checks the sign before rounding */ 569 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 570 float_raise(float_flag_invalid, &env->fp_status); 571 RddV = 0; 572 } else { 573 RddV = float32_to_uint64(RsV, &env->fp_status); 574 } 575 arch_fpop_end(env); 576 return RddV; 577 } 578 579 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV) 580 { 581 int64_t RddV; 582 arch_fpop_start(env); 583 /* Hexagon returns -1 for NaN */ 584 if (float32_is_any_nan(RsV)) { 585 float_raise(float_flag_invalid, &env->fp_status); 586 RddV = -1; 587 } else { 588 RddV = float32_to_int64(RsV, &env->fp_status); 589 } 590 arch_fpop_end(env); 591 return RddV; 592 } 593 594 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV) 595 { 596 uint32_t RdV; 597 arch_fpop_start(env); 598 /* Hexagon checks the sign before rounding */ 599 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 600 float_raise(float_flag_invalid, &env->fp_status); 601 RdV = 0; 602 } else { 603 RdV = float64_to_uint32(RssV, &env->fp_status); 604 } 605 arch_fpop_end(env); 606 return RdV; 607 } 608 609 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV) 610 { 611 int32_t RdV; 612 arch_fpop_start(env); 613 /* Hexagon returns -1 for NaN */ 614 if (float64_is_any_nan(RssV)) { 615 float_raise(float_flag_invalid, &env->fp_status); 616 RdV = -1; 617 } else { 618 RdV = float64_to_int32(RssV, &env->fp_status); 619 } 620 arch_fpop_end(env); 621 return RdV; 622 } 623 624 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV) 625 { 626 uint64_t RddV; 627 arch_fpop_start(env); 628 /* Hexagon checks the sign before rounding */ 629 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 630 float_raise(float_flag_invalid, &env->fp_status); 631 RddV = 0; 632 } else { 633 RddV = float64_to_uint64(RssV, &env->fp_status); 634 } 635 arch_fpop_end(env); 636 return RddV; 637 } 638 639 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV) 640 { 641 int64_t RddV; 642 arch_fpop_start(env); 643 /* Hexagon returns -1 for NaN */ 644 if (float64_is_any_nan(RssV)) { 645 float_raise(float_flag_invalid, &env->fp_status); 646 RddV = -1; 647 } else { 648 RddV = float64_to_int64(RssV, &env->fp_status); 649 } 650 arch_fpop_end(env); 651 return RddV; 652 } 653 654 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV) 655 { 656 uint32_t RdV; 657 arch_fpop_start(env); 658 /* Hexagon checks the sign before rounding */ 659 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 660 float_raise(float_flag_invalid, &env->fp_status); 661 RdV = 0; 662 } else { 663 RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status); 664 } 665 arch_fpop_end(env); 666 return RdV; 667 } 668 669 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV) 670 { 671 int32_t RdV; 672 arch_fpop_start(env); 673 /* Hexagon returns -1 for NaN */ 674 if (float32_is_any_nan(RsV)) { 675 float_raise(float_flag_invalid, &env->fp_status); 676 RdV = -1; 677 } else { 678 RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status); 679 } 680 arch_fpop_end(env); 681 return RdV; 682 } 683 684 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV) 685 { 686 uint64_t RddV; 687 arch_fpop_start(env); 688 /* Hexagon checks the sign before rounding */ 689 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 690 float_raise(float_flag_invalid, &env->fp_status); 691 RddV = 0; 692 } else { 693 RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status); 694 } 695 arch_fpop_end(env); 696 return RddV; 697 } 698 699 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV) 700 { 701 int64_t RddV; 702 arch_fpop_start(env); 703 /* Hexagon returns -1 for NaN */ 704 if (float32_is_any_nan(RsV)) { 705 float_raise(float_flag_invalid, &env->fp_status); 706 RddV = -1; 707 } else { 708 RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status); 709 } 710 arch_fpop_end(env); 711 return RddV; 712 } 713 714 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV) 715 { 716 uint32_t RdV; 717 arch_fpop_start(env); 718 /* Hexagon checks the sign before rounding */ 719 if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) { 720 float_raise(float_flag_invalid, &env->fp_status); 721 RdV = 0; 722 } else { 723 RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status); 724 } 725 arch_fpop_end(env); 726 return RdV; 727 } 728 729 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV) 730 { 731 int32_t RdV; 732 arch_fpop_start(env); 733 /* Hexagon returns -1 for NaN */ 734 if (float64_is_any_nan(RssV)) { 735 float_raise(float_flag_invalid, &env->fp_status); 736 RdV = -1; 737 } else { 738 RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status); 739 } 740 arch_fpop_end(env); 741 return RdV; 742 } 743 744 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV) 745 { 746 uint64_t RddV; 747 arch_fpop_start(env); 748 /* Hexagon checks the sign before rounding */ 749 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 750 float_raise(float_flag_invalid, &env->fp_status); 751 RddV = 0; 752 } else { 753 RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status); 754 } 755 arch_fpop_end(env); 756 return RddV; 757 } 758 759 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV) 760 { 761 int64_t RddV; 762 arch_fpop_start(env); 763 /* Hexagon returns -1 for NaN */ 764 if (float64_is_any_nan(RssV)) { 765 float_raise(float_flag_invalid, &env->fp_status); 766 RddV = -1; 767 } else { 768 RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status); 769 } 770 arch_fpop_end(env); 771 return RddV; 772 } 773 774 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV) 775 { 776 float32 RdV; 777 arch_fpop_start(env); 778 RdV = float32_add(RsV, RtV, &env->fp_status); 779 arch_fpop_end(env); 780 return RdV; 781 } 782 783 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV) 784 { 785 float32 RdV; 786 arch_fpop_start(env); 787 RdV = float32_sub(RsV, RtV, &env->fp_status); 788 arch_fpop_end(env); 789 return RdV; 790 } 791 792 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV) 793 { 794 int32_t PdV; 795 arch_fpop_start(env); 796 PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status)); 797 arch_fpop_end(env); 798 return PdV; 799 } 800 801 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV) 802 { 803 int cmp; 804 int32_t PdV; 805 arch_fpop_start(env); 806 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status); 807 PdV = f8BITSOF(cmp == float_relation_greater); 808 arch_fpop_end(env); 809 return PdV; 810 } 811 812 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV) 813 { 814 int cmp; 815 int32_t PdV; 816 arch_fpop_start(env); 817 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status); 818 PdV = f8BITSOF(cmp == float_relation_greater || 819 cmp == float_relation_equal); 820 arch_fpop_end(env); 821 return PdV; 822 } 823 824 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV) 825 { 826 int32_t PdV; 827 arch_fpop_start(env); 828 PdV = f8BITSOF(float32_is_any_nan(RsV) || 829 float32_is_any_nan(RtV)); 830 arch_fpop_end(env); 831 return PdV; 832 } 833 834 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV) 835 { 836 float32 RdV; 837 arch_fpop_start(env); 838 RdV = float32_maxnum(RsV, RtV, &env->fp_status); 839 arch_fpop_end(env); 840 return RdV; 841 } 842 843 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV) 844 { 845 float32 RdV; 846 arch_fpop_start(env); 847 RdV = float32_minnum(RsV, RtV, &env->fp_status); 848 arch_fpop_end(env); 849 return RdV; 850 } 851 852 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV) 853 { 854 int32_t PdV = 0; 855 arch_fpop_start(env); 856 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) { 857 PdV = 0xff; 858 } 859 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) { 860 PdV = 0xff; 861 } 862 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) { 863 PdV = 0xff; 864 } 865 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) { 866 PdV = 0xff; 867 } 868 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) { 869 PdV = 0xff; 870 } 871 set_float_exception_flags(0, &env->fp_status); 872 arch_fpop_end(env); 873 return PdV; 874 } 875 876 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV) 877 { 878 float32 RdV = 0; 879 int adjust; 880 arch_fpop_start(env); 881 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status); 882 RdV = RsV; 883 arch_fpop_end(env); 884 return RdV; 885 } 886 887 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV) 888 { 889 float32 RdV = 0; 890 int adjust; 891 arch_fpop_start(env); 892 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status); 893 RdV = RtV; 894 arch_fpop_end(env); 895 return RdV; 896 } 897 898 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV) 899 { 900 float32 RdV = 0; 901 int adjust; 902 arch_fpop_start(env); 903 arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status); 904 RdV = RsV; 905 arch_fpop_end(env); 906 return RdV; 907 } 908 909 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV) 910 { 911 float64 RddV; 912 arch_fpop_start(env); 913 RddV = float64_add(RssV, RttV, &env->fp_status); 914 arch_fpop_end(env); 915 return RddV; 916 } 917 918 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV) 919 { 920 float64 RddV; 921 arch_fpop_start(env); 922 RddV = float64_sub(RssV, RttV, &env->fp_status); 923 arch_fpop_end(env); 924 return RddV; 925 } 926 927 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV) 928 { 929 float64 RddV; 930 arch_fpop_start(env); 931 RddV = float64_maxnum(RssV, RttV, &env->fp_status); 932 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) { 933 float_raise(float_flag_invalid, &env->fp_status); 934 } 935 arch_fpop_end(env); 936 return RddV; 937 } 938 939 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV) 940 { 941 float64 RddV; 942 arch_fpop_start(env); 943 RddV = float64_minnum(RssV, RttV, &env->fp_status); 944 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) { 945 float_raise(float_flag_invalid, &env->fp_status); 946 } 947 arch_fpop_end(env); 948 return RddV; 949 } 950 951 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV) 952 { 953 int32_t PdV; 954 arch_fpop_start(env); 955 PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status)); 956 arch_fpop_end(env); 957 return PdV; 958 } 959 960 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV) 961 { 962 int cmp; 963 int32_t PdV; 964 arch_fpop_start(env); 965 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status); 966 PdV = f8BITSOF(cmp == float_relation_greater); 967 arch_fpop_end(env); 968 return PdV; 969 } 970 971 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV) 972 { 973 int cmp; 974 int32_t PdV; 975 arch_fpop_start(env); 976 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status); 977 PdV = f8BITSOF(cmp == float_relation_greater || 978 cmp == float_relation_equal); 979 arch_fpop_end(env); 980 return PdV; 981 } 982 983 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV) 984 { 985 int32_t PdV; 986 arch_fpop_start(env); 987 PdV = f8BITSOF(float64_is_any_nan(RssV) || 988 float64_is_any_nan(RttV)); 989 arch_fpop_end(env); 990 return PdV; 991 } 992 993 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV) 994 { 995 int32_t PdV = 0; 996 arch_fpop_start(env); 997 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) { 998 PdV = 0xff; 999 } 1000 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) { 1001 PdV = 0xff; 1002 } 1003 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) { 1004 PdV = 0xff; 1005 } 1006 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) { 1007 PdV = 0xff; 1008 } 1009 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) { 1010 PdV = 0xff; 1011 } 1012 set_float_exception_flags(0, &env->fp_status); 1013 arch_fpop_end(env); 1014 return PdV; 1015 } 1016 1017 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV) 1018 { 1019 float32 RdV; 1020 arch_fpop_start(env); 1021 RdV = internal_mpyf(RsV, RtV, &env->fp_status); 1022 arch_fpop_end(env); 1023 return RdV; 1024 } 1025 1026 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV, 1027 float32 RsV, float32 RtV) 1028 { 1029 arch_fpop_start(env); 1030 RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); 1031 arch_fpop_end(env); 1032 return RxV; 1033 } 1034 1035 static bool is_zero_prod(float32 a, float32 b) 1036 { 1037 return ((float32_is_zero(a) && is_finite(b)) || 1038 (float32_is_zero(b) && is_finite(a))); 1039 } 1040 1041 static float32 check_nan(float32 dst, float32 x, float_status *fp_status) 1042 { 1043 float32 ret = dst; 1044 if (float32_is_any_nan(x)) { 1045 if (extract32(x, 22, 1) == 0) { 1046 float_raise(float_flag_invalid, fp_status); 1047 } 1048 ret = make_float32(0xffffffff); /* nan */ 1049 } 1050 return ret; 1051 } 1052 1053 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV, 1054 float32 RsV, float32 RtV, float32 PuV) 1055 { 1056 size4s_t tmp; 1057 arch_fpop_start(env); 1058 RxV = check_nan(RxV, RxV, &env->fp_status); 1059 RxV = check_nan(RxV, RsV, &env->fp_status); 1060 RxV = check_nan(RxV, RtV, &env->fp_status); 1061 tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status); 1062 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1063 RxV = tmp; 1064 } 1065 arch_fpop_end(env); 1066 return RxV; 1067 } 1068 1069 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV, 1070 float32 RsV, float32 RtV) 1071 { 1072 float32 neg_RsV; 1073 arch_fpop_start(env); 1074 neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status); 1075 RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status); 1076 arch_fpop_end(env); 1077 return RxV; 1078 } 1079 1080 static bool is_inf_prod(int32_t a, int32_t b) 1081 { 1082 return (float32_is_infinity(a) && float32_is_infinity(b)) || 1083 (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) || 1084 (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a)); 1085 } 1086 1087 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, 1088 float32 RsV, float32 RtV) 1089 { 1090 bool infinp; 1091 bool infminusinf; 1092 float32 tmp; 1093 1094 arch_fpop_start(env); 1095 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 1096 infminusinf = float32_is_infinity(RxV) && 1097 is_inf_prod(RsV, RtV) && 1098 (fGETBIT(31, RsV ^ RxV ^ RtV) != 0); 1099 infinp = float32_is_infinity(RxV) || 1100 float32_is_infinity(RtV) || 1101 float32_is_infinity(RsV); 1102 RxV = check_nan(RxV, RxV, &env->fp_status); 1103 RxV = check_nan(RxV, RsV, &env->fp_status); 1104 RxV = check_nan(RxV, RtV, &env->fp_status); 1105 tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); 1106 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1107 RxV = tmp; 1108 } 1109 set_float_exception_flags(0, &env->fp_status); 1110 if (float32_is_infinity(RxV) && !infinp) { 1111 RxV = RxV - 1; 1112 } 1113 if (infminusinf) { 1114 RxV = 0; 1115 } 1116 arch_fpop_end(env); 1117 return RxV; 1118 } 1119 1120 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV, 1121 float32 RsV, float32 RtV) 1122 { 1123 bool infinp; 1124 bool infminusinf; 1125 float32 tmp; 1126 1127 arch_fpop_start(env); 1128 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 1129 infminusinf = float32_is_infinity(RxV) && 1130 is_inf_prod(RsV, RtV) && 1131 (fGETBIT(31, RsV ^ RxV ^ RtV) == 0); 1132 infinp = float32_is_infinity(RxV) || 1133 float32_is_infinity(RtV) || 1134 float32_is_infinity(RsV); 1135 RxV = check_nan(RxV, RxV, &env->fp_status); 1136 RxV = check_nan(RxV, RsV, &env->fp_status); 1137 RxV = check_nan(RxV, RtV, &env->fp_status); 1138 float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status); 1139 tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status); 1140 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1141 RxV = tmp; 1142 } 1143 set_float_exception_flags(0, &env->fp_status); 1144 if (float32_is_infinity(RxV) && !infinp) { 1145 RxV = RxV - 1; 1146 } 1147 if (infminusinf) { 1148 RxV = 0; 1149 } 1150 arch_fpop_end(env); 1151 return RxV; 1152 } 1153 1154 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV) 1155 { 1156 int64_t RddV; 1157 arch_fpop_start(env); 1158 if (float64_is_denormal(RssV) && 1159 (float64_getexp(RttV) >= 512) && 1160 float64_is_normal(RttV)) { 1161 RddV = float64_mul(RssV, make_float64(0x4330000000000000), 1162 &env->fp_status); 1163 } else if (float64_is_denormal(RttV) && 1164 (float64_getexp(RssV) >= 512) && 1165 float64_is_normal(RssV)) { 1166 RddV = float64_mul(RssV, make_float64(0x3cb0000000000000), 1167 &env->fp_status); 1168 } else { 1169 RddV = RssV; 1170 } 1171 arch_fpop_end(env); 1172 return RddV; 1173 } 1174 1175 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV, 1176 float64 RssV, float64 RttV) 1177 { 1178 arch_fpop_start(env); 1179 RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status); 1180 arch_fpop_end(env); 1181 return RxxV; 1182 } 1183 1184 static void cancel_slot(CPUHexagonState *env, uint32_t slot) 1185 { 1186 HEX_DEBUG_LOG("Slot %d cancelled\n", slot); 1187 env->slot_cancelled |= (1 << slot); 1188 } 1189 1190 /* These macros can be referenced in the generated helper functions */ 1191 #define warn(...) /* Nothing */ 1192 #define fatal(...) g_assert_not_reached(); 1193 1194 #define BOGUS_HELPER(tag) \ 1195 printf("ERROR: bogus helper: " #tag "\n") 1196 1197 #include "helper_funcs_generated.c.inc" 1198