1 /* 2 * Copyright(c) 2019-2023 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 #include "mmvec/mmvec.h" 31 #include "mmvec/macros.h" 32 #include "op_helper.h" 33 #include "translate.h" 34 35 #define SF_BIAS 127 36 #define SF_MANTBITS 23 37 38 /* Exceptions processing helpers */ 39 static G_NORETURN 40 void do_raise_exception_err(CPUHexagonState *env, 41 uint32_t exception, 42 uintptr_t pc) 43 { 44 CPUState *cs = env_cpu(env); 45 qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception); 46 cs->exception_index = exception; 47 cpu_loop_exit_restore(cs, pc); 48 } 49 50 G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp) 51 { 52 do_raise_exception_err(env, excp, 0); 53 } 54 55 void log_store32(CPUHexagonState *env, target_ulong addr, 56 target_ulong val, int width, int slot) 57 { 58 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx 59 ", %" PRId32 " [0x08%" PRIx32 "])\n", 60 width, addr, val, val); 61 env->mem_log_stores[slot].va = addr; 62 env->mem_log_stores[slot].width = width; 63 env->mem_log_stores[slot].data32 = val; 64 } 65 66 void log_store64(CPUHexagonState *env, target_ulong addr, 67 int64_t val, int width, int slot) 68 { 69 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx 70 ", %" PRId64 " [0x016%" PRIx64 "])\n", 71 width, addr, val, val); 72 env->mem_log_stores[slot].va = addr; 73 env->mem_log_stores[slot].width = width; 74 env->mem_log_stores[slot].data64 = val; 75 } 76 77 /* Handy place to set a breakpoint */ 78 void HELPER(debug_start_packet)(CPUHexagonState *env) 79 { 80 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n", 81 env->gpr[HEX_REG_PC]); 82 83 for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) { 84 env->reg_written[i] = 0; 85 } 86 } 87 88 /* Checks for bookkeeping errors between disassembly context and runtime */ 89 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check) 90 { 91 if (env->mem_log_stores[slot].width != check) { 92 HEX_DEBUG_LOG("ERROR: %d != %d\n", 93 env->mem_log_stores[slot].width, check); 94 g_assert_not_reached(); 95 } 96 } 97 98 static void commit_store(CPUHexagonState *env, int slot_num, uintptr_t ra) 99 { 100 uint8_t width = env->mem_log_stores[slot_num].width; 101 target_ulong va = env->mem_log_stores[slot_num].va; 102 103 switch (width) { 104 case 1: 105 cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra); 106 break; 107 case 2: 108 cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra); 109 break; 110 case 4: 111 cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra); 112 break; 113 case 8: 114 cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra); 115 break; 116 default: 117 g_assert_not_reached(); 118 } 119 } 120 121 void HELPER(commit_store)(CPUHexagonState *env, int slot_num) 122 { 123 uintptr_t ra = GETPC(); 124 commit_store(env, slot_num, ra); 125 } 126 127 void HELPER(gather_store)(CPUHexagonState *env, uint32_t addr, int slot) 128 { 129 mem_gather_store(env, addr, slot); 130 } 131 132 void HELPER(commit_hvx_stores)(CPUHexagonState *env) 133 { 134 uintptr_t ra = GETPC(); 135 136 /* Normal (possibly masked) vector store */ 137 for (int i = 0; i < VSTORES_MAX; i++) { 138 if (env->vstore_pending[i]) { 139 env->vstore_pending[i] = 0; 140 target_ulong va = env->vstore[i].va; 141 int size = env->vstore[i].size; 142 for (int j = 0; j < size; j++) { 143 if (test_bit(j, env->vstore[i].mask)) { 144 cpu_stb_data_ra(env, va + j, env->vstore[i].data.ub[j], ra); 145 } 146 } 147 } 148 } 149 150 /* Scatter store */ 151 if (env->vtcm_pending) { 152 env->vtcm_pending = false; 153 if (env->vtcm_log.op) { 154 /* Need to perform the scatter read/modify/write at commit time */ 155 if (env->vtcm_log.op_size == 2) { 156 SCATTER_OP_WRITE_TO_MEM(uint16_t); 157 } else if (env->vtcm_log.op_size == 4) { 158 /* Word Scatter += */ 159 SCATTER_OP_WRITE_TO_MEM(uint32_t); 160 } else { 161 g_assert_not_reached(); 162 } 163 } else { 164 for (int i = 0; i < sizeof(MMVector); i++) { 165 if (test_bit(i, env->vtcm_log.mask)) { 166 cpu_stb_data_ra(env, env->vtcm_log.va[i], 167 env->vtcm_log.data.ub[i], ra); 168 clear_bit(i, env->vtcm_log.mask); 169 env->vtcm_log.data.ub[i] = 0; 170 } 171 172 } 173 } 174 } 175 } 176 177 static void print_store(CPUHexagonState *env, int slot) 178 { 179 if (!(env->slot_cancelled & (1 << slot))) { 180 uint8_t width = env->mem_log_stores[slot].width; 181 if (width == 1) { 182 uint32_t data = env->mem_log_stores[slot].data32 & 0xff; 183 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32 184 " (0x%02" PRIx32 ")\n", 185 env->mem_log_stores[slot].va, data, data); 186 } else if (width == 2) { 187 uint32_t data = env->mem_log_stores[slot].data32 & 0xffff; 188 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32 189 " (0x%04" PRIx32 ")\n", 190 env->mem_log_stores[slot].va, data, data); 191 } else if (width == 4) { 192 uint32_t data = env->mem_log_stores[slot].data32; 193 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32 194 " (0x%08" PRIx32 ")\n", 195 env->mem_log_stores[slot].va, data, data); 196 } else if (width == 8) { 197 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64 198 " (0x%016" PRIx64 ")\n", 199 env->mem_log_stores[slot].va, 200 env->mem_log_stores[slot].data64, 201 env->mem_log_stores[slot].data64); 202 } else { 203 HEX_DEBUG_LOG("\tBad store width %d\n", width); 204 g_assert_not_reached(); 205 } 206 } 207 } 208 209 /* This function is a handy place to set a breakpoint */ 210 void HELPER(debug_commit_end)(CPUHexagonState *env, uint32_t this_PC, 211 int pred_written, int has_st0, int has_st1) 212 { 213 bool reg_printed = false; 214 bool pred_printed = false; 215 int i; 216 217 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n", this_PC); 218 HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled); 219 220 for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { 221 if (env->reg_written[i]) { 222 if (!reg_printed) { 223 HEX_DEBUG_LOG("Regs written\n"); 224 reg_printed = true; 225 } 226 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n", 227 i, env->gpr[i], env->gpr[i]); 228 } 229 } 230 231 for (i = 0; i < NUM_PREGS; i++) { 232 if (pred_written & (1 << i)) { 233 if (!pred_printed) { 234 HEX_DEBUG_LOG("Predicates written\n"); 235 pred_printed = true; 236 } 237 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n", 238 i, env->pred[i]); 239 } 240 } 241 242 if (has_st0 || has_st1) { 243 HEX_DEBUG_LOG("Stores\n"); 244 if (has_st0) { 245 print_store(env, 0); 246 } 247 if (has_st1) { 248 print_store(env, 1); 249 } 250 } 251 252 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->gpr[HEX_REG_PC]); 253 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx 254 ", insn = " TARGET_FMT_lx 255 ", hvx = " TARGET_FMT_lx "\n", 256 env->gpr[HEX_REG_QEMU_PKT_CNT], 257 env->gpr[HEX_REG_QEMU_INSN_CNT], 258 env->gpr[HEX_REG_QEMU_HVX_CNT]); 259 260 } 261 262 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) 263 { 264 uint32_t K_const = extract32(M, 24, 4); 265 uint32_t length = extract32(M, 0, 17); 266 uint32_t new_ptr = RxV + offset; 267 uint32_t start_addr; 268 uint32_t end_addr; 269 270 if (K_const == 0 && length >= 4) { 271 start_addr = CS; 272 end_addr = start_addr + length; 273 } else { 274 /* 275 * Versions v3 and earlier used the K value to specify a power-of-2 size 276 * 2^(K+2) that is greater than the buffer length 277 */ 278 int32_t mask = (1 << (K_const + 2)) - 1; 279 start_addr = RxV & (~mask); 280 end_addr = start_addr | length; 281 } 282 283 if (new_ptr >= end_addr) { 284 new_ptr -= length; 285 } else if (new_ptr < start_addr) { 286 new_ptr += length; 287 } 288 289 return new_ptr; 290 } 291 292 uint32_t HELPER(fbrev)(uint32_t addr) 293 { 294 /* 295 * Bit reverse the low 16 bits of the address 296 */ 297 return deposit32(addr, 0, 16, revbit16(addr)); 298 } 299 300 static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant) 301 { 302 return make_float32( 303 ((sign & 1) << 31) | 304 ((exp & 0xff) << SF_MANTBITS) | 305 (mant & ((1 << SF_MANTBITS) - 1))); 306 } 307 308 /* 309 * sfrecipa, sfinvsqrta have two 32-bit results 310 * r0,p0=sfrecipa(r1,r2) 311 * r0,p0=sfinvsqrta(r1) 312 * 313 * Since helpers can only return a single value, we pack the two results 314 * into a 64-bit value. 315 */ 316 uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV) 317 { 318 int32_t PeV = 0; 319 float32 RdV; 320 int idx; 321 int adjust; 322 int mant; 323 int exp; 324 325 arch_fpop_start(env); 326 if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) { 327 PeV = adjust; 328 idx = (RtV >> 16) & 0x7f; 329 mant = (recip_lookup_table[idx] << 15) | 1; 330 exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1; 331 RdV = build_float32(extract32(RtV, 31, 1), exp, mant); 332 } 333 arch_fpop_end(env); 334 return ((uint64_t)RdV << 32) | PeV; 335 } 336 337 uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV) 338 { 339 int PeV = 0; 340 float32 RdV; 341 int idx; 342 int adjust; 343 int mant; 344 int exp; 345 346 arch_fpop_start(env); 347 if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) { 348 PeV = adjust; 349 idx = (RsV >> 17) & 0x7f; 350 mant = (invsqrt_lookup_table[idx] << 15); 351 exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1; 352 RdV = build_float32(extract32(RsV, 31, 1), exp, mant); 353 } 354 arch_fpop_end(env); 355 return ((uint64_t)RdV << 32) | PeV; 356 } 357 358 int64_t HELPER(vacsh_val)(CPUHexagonState *env, 359 int64_t RxxV, int64_t RssV, int64_t RttV, 360 uint32_t pkt_need_commit) 361 { 362 for (int i = 0; i < 4; i++) { 363 int xv = sextract64(RxxV, i * 16, 16); 364 int sv = sextract64(RssV, i * 16, 16); 365 int tv = sextract64(RttV, i * 16, 16); 366 int max; 367 xv = xv + tv; 368 sv = sv - tv; 369 max = xv > sv ? xv : sv; 370 /* Note that fSATH can set the OVF bit in usr */ 371 RxxV = deposit64(RxxV, i * 16, 16, fSATH(max)); 372 } 373 return RxxV; 374 } 375 376 int32_t HELPER(vacsh_pred)(CPUHexagonState *env, 377 int64_t RxxV, int64_t RssV, int64_t RttV) 378 { 379 int32_t PeV = 0; 380 for (int i = 0; i < 4; i++) { 381 int xv = sextract64(RxxV, i * 16, 16); 382 int sv = sextract64(RssV, i * 16, 16); 383 int tv = sextract64(RttV, i * 16, 16); 384 xv = xv + tv; 385 sv = sv - tv; 386 PeV = deposit32(PeV, i * 2, 1, (xv > sv)); 387 PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv)); 388 } 389 return PeV; 390 } 391 392 int64_t HELPER(cabacdecbin_val)(int64_t RssV, int64_t RttV) 393 { 394 int64_t RddV = 0; 395 size4u_t state; 396 size4u_t valMPS; 397 size4u_t bitpos; 398 size4u_t range; 399 size4u_t offset; 400 size4u_t rLPS; 401 size4u_t rMPS; 402 403 state = fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0); 404 valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8); 405 bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0); 406 range = fGETWORD(0, RssV); 407 offset = fGETWORD(1, RssV); 408 409 /* calculate rLPS */ 410 range <<= bitpos; 411 offset <<= bitpos; 412 rLPS = rLPS_table_64x4[state][(range >> 29) & 3]; 413 rLPS = rLPS << 23; /* left aligned */ 414 415 /* calculate rMPS */ 416 rMPS = (range & 0xff800000) - rLPS; 417 418 /* most probable region */ 419 if (offset < rMPS) { 420 RddV = AC_next_state_MPS_64[state]; 421 fINSERT_RANGE(RddV, 8, 8, valMPS); 422 fINSERT_RANGE(RddV, 31, 23, (rMPS >> 23)); 423 fSETWORD(1, RddV, offset); 424 } 425 /* least probable region */ 426 else { 427 RddV = AC_next_state_LPS_64[state]; 428 fINSERT_RANGE(RddV, 8, 8, ((!state) ? (1 - valMPS) : (valMPS))); 429 fINSERT_RANGE(RddV, 31, 23, (rLPS >> 23)); 430 fSETWORD(1, RddV, (offset - rMPS)); 431 } 432 return RddV; 433 } 434 435 int32_t HELPER(cabacdecbin_pred)(int64_t RssV, int64_t RttV) 436 { 437 int32_t p0 = 0; 438 size4u_t state; 439 size4u_t valMPS; 440 size4u_t bitpos; 441 size4u_t range; 442 size4u_t offset; 443 size4u_t rLPS; 444 size4u_t rMPS; 445 446 state = fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0); 447 valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8); 448 bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0); 449 range = fGETWORD(0, RssV); 450 offset = fGETWORD(1, RssV); 451 452 /* calculate rLPS */ 453 range <<= bitpos; 454 offset <<= bitpos; 455 rLPS = rLPS_table_64x4[state][(range >> 29) & 3]; 456 rLPS = rLPS << 23; /* left aligned */ 457 458 /* calculate rMPS */ 459 rMPS = (range & 0xff800000) - rLPS; 460 461 /* most probable region */ 462 if (offset < rMPS) { 463 p0 = valMPS; 464 465 } 466 /* least probable region */ 467 else { 468 p0 = valMPS ^ 1; 469 } 470 return p0; 471 } 472 473 static void probe_store(CPUHexagonState *env, int slot, int mmu_idx, 474 bool is_predicated, uintptr_t retaddr) 475 { 476 if (!is_predicated || !(env->slot_cancelled & (1 << slot))) { 477 size1u_t width = env->mem_log_stores[slot].width; 478 target_ulong va = env->mem_log_stores[slot].va; 479 probe_write(env, va, width, mmu_idx, retaddr); 480 } 481 } 482 483 /* 484 * Called from a mem_noshuf packet to make sure the load doesn't 485 * raise an exception 486 */ 487 void HELPER(probe_noshuf_load)(CPUHexagonState *env, target_ulong va, 488 int size, int mmu_idx) 489 { 490 uintptr_t retaddr = GETPC(); 491 probe_read(env, va, size, mmu_idx, retaddr); 492 } 493 494 /* Called during packet commit when there are two scalar stores */ 495 void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int args) 496 { 497 int mmu_idx = FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, MMU_IDX); 498 bool is_predicated = 499 FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED); 500 uintptr_t ra = GETPC(); 501 probe_store(env, 0, mmu_idx, is_predicated, ra); 502 } 503 504 static void probe_hvx_stores(CPUHexagonState *env, int mmu_idx, 505 uintptr_t retaddr) 506 { 507 /* Normal (possibly masked) vector store */ 508 for (int i = 0; i < VSTORES_MAX; i++) { 509 if (env->vstore_pending[i]) { 510 target_ulong va = env->vstore[i].va; 511 int size = env->vstore[i].size; 512 for (int j = 0; j < size; j++) { 513 if (test_bit(j, env->vstore[i].mask)) { 514 probe_write(env, va + j, 1, mmu_idx, retaddr); 515 } 516 } 517 } 518 } 519 520 /* Scatter store */ 521 if (env->vtcm_pending) { 522 if (env->vtcm_log.op) { 523 /* Need to perform the scatter read/modify/write at commit time */ 524 if (env->vtcm_log.op_size == 2) { 525 SCATTER_OP_PROBE_MEM(size2u_t, mmu_idx, retaddr); 526 } else if (env->vtcm_log.op_size == 4) { 527 /* Word Scatter += */ 528 SCATTER_OP_PROBE_MEM(size4u_t, mmu_idx, retaddr); 529 } else { 530 g_assert_not_reached(); 531 } 532 } else { 533 for (int i = 0; i < sizeof(MMVector); i++) { 534 if (test_bit(i, env->vtcm_log.mask)) { 535 probe_write(env, env->vtcm_log.va[i], 1, mmu_idx, retaddr); 536 } 537 538 } 539 } 540 } 541 } 542 543 void HELPER(probe_hvx_stores)(CPUHexagonState *env, int mmu_idx) 544 { 545 uintptr_t retaddr = GETPC(); 546 probe_hvx_stores(env, mmu_idx, retaddr); 547 } 548 549 void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask) 550 { 551 bool has_st0 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST0); 552 bool has_st1 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST1); 553 bool has_hvx_stores = 554 FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_HVX_STORES); 555 bool s0_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED); 556 bool s1_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED); 557 int mmu_idx = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX); 558 uintptr_t ra = GETPC(); 559 560 if (has_st0) { 561 probe_store(env, 0, mmu_idx, s0_is_pred, ra); 562 } 563 if (has_st1) { 564 probe_store(env, 1, mmu_idx, s1_is_pred, ra); 565 } 566 if (has_hvx_stores) { 567 probe_hvx_stores(env, mmu_idx, ra); 568 } 569 } 570 571 #ifndef CONFIG_HEXAGON_IDEF_PARSER 572 /* 573 * mem_noshuf 574 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual 575 * 576 * If the load is in slot 0 and there is a store in slot1 (that 577 * wasn't cancelled), we have to do the store first. 578 */ 579 static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1, 580 uint32_t slot, target_ulong vaddr, int size, 581 uintptr_t ra) 582 { 583 if (slot == 0 && pkt_has_store_s1 && 584 ((env->slot_cancelled & (1 << 1)) == 0)) { 585 probe_read(env, vaddr, size, MMU_USER_IDX, ra); 586 commit_store(env, 1, ra); 587 } 588 } 589 #endif 590 591 /* Floating point */ 592 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV) 593 { 594 float64 out_f64; 595 arch_fpop_start(env); 596 out_f64 = float32_to_float64(RsV, &env->fp_status); 597 arch_fpop_end(env); 598 return out_f64; 599 } 600 601 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV) 602 { 603 float32 out_f32; 604 arch_fpop_start(env); 605 out_f32 = float64_to_float32(RssV, &env->fp_status); 606 arch_fpop_end(env); 607 return out_f32; 608 } 609 610 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV) 611 { 612 float32 RdV; 613 arch_fpop_start(env); 614 RdV = uint32_to_float32(RsV, &env->fp_status); 615 arch_fpop_end(env); 616 return RdV; 617 } 618 619 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV) 620 { 621 float64 RddV; 622 arch_fpop_start(env); 623 RddV = uint32_to_float64(RsV, &env->fp_status); 624 arch_fpop_end(env); 625 return RddV; 626 } 627 628 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV) 629 { 630 float32 RdV; 631 arch_fpop_start(env); 632 RdV = int32_to_float32(RsV, &env->fp_status); 633 arch_fpop_end(env); 634 return RdV; 635 } 636 637 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV) 638 { 639 float64 RddV; 640 arch_fpop_start(env); 641 RddV = int32_to_float64(RsV, &env->fp_status); 642 arch_fpop_end(env); 643 return RddV; 644 } 645 646 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV) 647 { 648 float32 RdV; 649 arch_fpop_start(env); 650 RdV = uint64_to_float32(RssV, &env->fp_status); 651 arch_fpop_end(env); 652 return RdV; 653 } 654 655 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV) 656 { 657 float64 RddV; 658 arch_fpop_start(env); 659 RddV = uint64_to_float64(RssV, &env->fp_status); 660 arch_fpop_end(env); 661 return RddV; 662 } 663 664 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV) 665 { 666 float32 RdV; 667 arch_fpop_start(env); 668 RdV = int64_to_float32(RssV, &env->fp_status); 669 arch_fpop_end(env); 670 return RdV; 671 } 672 673 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV) 674 { 675 float64 RddV; 676 arch_fpop_start(env); 677 RddV = int64_to_float64(RssV, &env->fp_status); 678 arch_fpop_end(env); 679 return RddV; 680 } 681 682 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV) 683 { 684 uint32_t RdV; 685 arch_fpop_start(env); 686 /* Hexagon checks the sign before rounding */ 687 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 688 float_raise(float_flag_invalid, &env->fp_status); 689 RdV = 0; 690 } else { 691 RdV = float32_to_uint32(RsV, &env->fp_status); 692 } 693 arch_fpop_end(env); 694 return RdV; 695 } 696 697 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV) 698 { 699 int32_t RdV; 700 arch_fpop_start(env); 701 /* Hexagon returns -1 for NaN */ 702 if (float32_is_any_nan(RsV)) { 703 float_raise(float_flag_invalid, &env->fp_status); 704 RdV = -1; 705 } else { 706 RdV = float32_to_int32(RsV, &env->fp_status); 707 } 708 arch_fpop_end(env); 709 return RdV; 710 } 711 712 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV) 713 { 714 uint64_t RddV; 715 arch_fpop_start(env); 716 /* Hexagon checks the sign before rounding */ 717 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 718 float_raise(float_flag_invalid, &env->fp_status); 719 RddV = 0; 720 } else { 721 RddV = float32_to_uint64(RsV, &env->fp_status); 722 } 723 arch_fpop_end(env); 724 return RddV; 725 } 726 727 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV) 728 { 729 int64_t RddV; 730 arch_fpop_start(env); 731 /* Hexagon returns -1 for NaN */ 732 if (float32_is_any_nan(RsV)) { 733 float_raise(float_flag_invalid, &env->fp_status); 734 RddV = -1; 735 } else { 736 RddV = float32_to_int64(RsV, &env->fp_status); 737 } 738 arch_fpop_end(env); 739 return RddV; 740 } 741 742 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV) 743 { 744 uint32_t RdV; 745 arch_fpop_start(env); 746 /* Hexagon checks the sign before rounding */ 747 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 748 float_raise(float_flag_invalid, &env->fp_status); 749 RdV = 0; 750 } else { 751 RdV = float64_to_uint32(RssV, &env->fp_status); 752 } 753 arch_fpop_end(env); 754 return RdV; 755 } 756 757 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV) 758 { 759 int32_t RdV; 760 arch_fpop_start(env); 761 /* Hexagon returns -1 for NaN */ 762 if (float64_is_any_nan(RssV)) { 763 float_raise(float_flag_invalid, &env->fp_status); 764 RdV = -1; 765 } else { 766 RdV = float64_to_int32(RssV, &env->fp_status); 767 } 768 arch_fpop_end(env); 769 return RdV; 770 } 771 772 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV) 773 { 774 uint64_t RddV; 775 arch_fpop_start(env); 776 /* Hexagon checks the sign before rounding */ 777 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 778 float_raise(float_flag_invalid, &env->fp_status); 779 RddV = 0; 780 } else { 781 RddV = float64_to_uint64(RssV, &env->fp_status); 782 } 783 arch_fpop_end(env); 784 return RddV; 785 } 786 787 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV) 788 { 789 int64_t RddV; 790 arch_fpop_start(env); 791 /* Hexagon returns -1 for NaN */ 792 if (float64_is_any_nan(RssV)) { 793 float_raise(float_flag_invalid, &env->fp_status); 794 RddV = -1; 795 } else { 796 RddV = float64_to_int64(RssV, &env->fp_status); 797 } 798 arch_fpop_end(env); 799 return RddV; 800 } 801 802 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV) 803 { 804 uint32_t RdV; 805 arch_fpop_start(env); 806 /* Hexagon checks the sign before rounding */ 807 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 808 float_raise(float_flag_invalid, &env->fp_status); 809 RdV = 0; 810 } else { 811 RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status); 812 } 813 arch_fpop_end(env); 814 return RdV; 815 } 816 817 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV) 818 { 819 int32_t RdV; 820 arch_fpop_start(env); 821 /* Hexagon returns -1 for NaN */ 822 if (float32_is_any_nan(RsV)) { 823 float_raise(float_flag_invalid, &env->fp_status); 824 RdV = -1; 825 } else { 826 RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status); 827 } 828 arch_fpop_end(env); 829 return RdV; 830 } 831 832 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV) 833 { 834 uint64_t RddV; 835 arch_fpop_start(env); 836 /* Hexagon checks the sign before rounding */ 837 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) { 838 float_raise(float_flag_invalid, &env->fp_status); 839 RddV = 0; 840 } else { 841 RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status); 842 } 843 arch_fpop_end(env); 844 return RddV; 845 } 846 847 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV) 848 { 849 int64_t RddV; 850 arch_fpop_start(env); 851 /* Hexagon returns -1 for NaN */ 852 if (float32_is_any_nan(RsV)) { 853 float_raise(float_flag_invalid, &env->fp_status); 854 RddV = -1; 855 } else { 856 RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status); 857 } 858 arch_fpop_end(env); 859 return RddV; 860 } 861 862 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV) 863 { 864 uint32_t RdV; 865 arch_fpop_start(env); 866 /* Hexagon checks the sign before rounding */ 867 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 868 float_raise(float_flag_invalid, &env->fp_status); 869 RdV = 0; 870 } else { 871 RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status); 872 } 873 arch_fpop_end(env); 874 return RdV; 875 } 876 877 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV) 878 { 879 int32_t RdV; 880 arch_fpop_start(env); 881 /* Hexagon returns -1 for NaN */ 882 if (float64_is_any_nan(RssV)) { 883 float_raise(float_flag_invalid, &env->fp_status); 884 RdV = -1; 885 } else { 886 RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status); 887 } 888 arch_fpop_end(env); 889 return RdV; 890 } 891 892 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV) 893 { 894 uint64_t RddV; 895 arch_fpop_start(env); 896 /* Hexagon checks the sign before rounding */ 897 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) { 898 float_raise(float_flag_invalid, &env->fp_status); 899 RddV = 0; 900 } else { 901 RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status); 902 } 903 arch_fpop_end(env); 904 return RddV; 905 } 906 907 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV) 908 { 909 int64_t RddV; 910 arch_fpop_start(env); 911 /* Hexagon returns -1 for NaN */ 912 if (float64_is_any_nan(RssV)) { 913 float_raise(float_flag_invalid, &env->fp_status); 914 RddV = -1; 915 } else { 916 RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status); 917 } 918 arch_fpop_end(env); 919 return RddV; 920 } 921 922 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV) 923 { 924 float32 RdV; 925 arch_fpop_start(env); 926 RdV = float32_add(RsV, RtV, &env->fp_status); 927 arch_fpop_end(env); 928 return RdV; 929 } 930 931 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV) 932 { 933 float32 RdV; 934 arch_fpop_start(env); 935 RdV = float32_sub(RsV, RtV, &env->fp_status); 936 arch_fpop_end(env); 937 return RdV; 938 } 939 940 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV) 941 { 942 int32_t PdV; 943 arch_fpop_start(env); 944 PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status)); 945 arch_fpop_end(env); 946 return PdV; 947 } 948 949 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV) 950 { 951 int cmp; 952 int32_t PdV; 953 arch_fpop_start(env); 954 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status); 955 PdV = f8BITSOF(cmp == float_relation_greater); 956 arch_fpop_end(env); 957 return PdV; 958 } 959 960 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV) 961 { 962 int cmp; 963 int32_t PdV; 964 arch_fpop_start(env); 965 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status); 966 PdV = f8BITSOF(cmp == float_relation_greater || 967 cmp == float_relation_equal); 968 arch_fpop_end(env); 969 return PdV; 970 } 971 972 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV) 973 { 974 int32_t PdV; 975 arch_fpop_start(env); 976 PdV = f8BITSOF(float32_unordered_quiet(RsV, RtV, &env->fp_status)); 977 arch_fpop_end(env); 978 return PdV; 979 } 980 981 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV) 982 { 983 float32 RdV; 984 arch_fpop_start(env); 985 RdV = float32_maximum_number(RsV, RtV, &env->fp_status); 986 arch_fpop_end(env); 987 return RdV; 988 } 989 990 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV) 991 { 992 float32 RdV; 993 arch_fpop_start(env); 994 RdV = float32_minimum_number(RsV, RtV, &env->fp_status); 995 arch_fpop_end(env); 996 return RdV; 997 } 998 999 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV) 1000 { 1001 int32_t PdV = 0; 1002 arch_fpop_start(env); 1003 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) { 1004 PdV = 0xff; 1005 } 1006 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) { 1007 PdV = 0xff; 1008 } 1009 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) { 1010 PdV = 0xff; 1011 } 1012 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) { 1013 PdV = 0xff; 1014 } 1015 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) { 1016 PdV = 0xff; 1017 } 1018 set_float_exception_flags(0, &env->fp_status); 1019 arch_fpop_end(env); 1020 return PdV; 1021 } 1022 1023 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV) 1024 { 1025 float32 RdV = 0; 1026 int adjust; 1027 arch_fpop_start(env); 1028 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status); 1029 RdV = RsV; 1030 arch_fpop_end(env); 1031 return RdV; 1032 } 1033 1034 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV) 1035 { 1036 float32 RdV = 0; 1037 int adjust; 1038 arch_fpop_start(env); 1039 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status); 1040 RdV = RtV; 1041 arch_fpop_end(env); 1042 return RdV; 1043 } 1044 1045 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV) 1046 { 1047 float32 RdV = 0; 1048 int adjust; 1049 arch_fpop_start(env); 1050 arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status); 1051 RdV = RsV; 1052 arch_fpop_end(env); 1053 return RdV; 1054 } 1055 1056 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV) 1057 { 1058 float64 RddV; 1059 arch_fpop_start(env); 1060 RddV = float64_add(RssV, RttV, &env->fp_status); 1061 arch_fpop_end(env); 1062 return RddV; 1063 } 1064 1065 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV) 1066 { 1067 float64 RddV; 1068 arch_fpop_start(env); 1069 RddV = float64_sub(RssV, RttV, &env->fp_status); 1070 arch_fpop_end(env); 1071 return RddV; 1072 } 1073 1074 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV) 1075 { 1076 float64 RddV; 1077 arch_fpop_start(env); 1078 RddV = float64_maximum_number(RssV, RttV, &env->fp_status); 1079 arch_fpop_end(env); 1080 return RddV; 1081 } 1082 1083 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV) 1084 { 1085 float64 RddV; 1086 arch_fpop_start(env); 1087 RddV = float64_minimum_number(RssV, RttV, &env->fp_status); 1088 arch_fpop_end(env); 1089 return RddV; 1090 } 1091 1092 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV) 1093 { 1094 int32_t PdV; 1095 arch_fpop_start(env); 1096 PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status)); 1097 arch_fpop_end(env); 1098 return PdV; 1099 } 1100 1101 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV) 1102 { 1103 int cmp; 1104 int32_t PdV; 1105 arch_fpop_start(env); 1106 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status); 1107 PdV = f8BITSOF(cmp == float_relation_greater); 1108 arch_fpop_end(env); 1109 return PdV; 1110 } 1111 1112 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV) 1113 { 1114 int cmp; 1115 int32_t PdV; 1116 arch_fpop_start(env); 1117 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status); 1118 PdV = f8BITSOF(cmp == float_relation_greater || 1119 cmp == float_relation_equal); 1120 arch_fpop_end(env); 1121 return PdV; 1122 } 1123 1124 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV) 1125 { 1126 int32_t PdV; 1127 arch_fpop_start(env); 1128 PdV = f8BITSOF(float64_unordered_quiet(RssV, RttV, &env->fp_status)); 1129 arch_fpop_end(env); 1130 return PdV; 1131 } 1132 1133 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV) 1134 { 1135 int32_t PdV = 0; 1136 arch_fpop_start(env); 1137 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) { 1138 PdV = 0xff; 1139 } 1140 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) { 1141 PdV = 0xff; 1142 } 1143 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) { 1144 PdV = 0xff; 1145 } 1146 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) { 1147 PdV = 0xff; 1148 } 1149 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) { 1150 PdV = 0xff; 1151 } 1152 set_float_exception_flags(0, &env->fp_status); 1153 arch_fpop_end(env); 1154 return PdV; 1155 } 1156 1157 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV) 1158 { 1159 float32 RdV; 1160 arch_fpop_start(env); 1161 RdV = internal_mpyf(RsV, RtV, &env->fp_status); 1162 arch_fpop_end(env); 1163 return RdV; 1164 } 1165 1166 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV, 1167 float32 RsV, float32 RtV) 1168 { 1169 arch_fpop_start(env); 1170 RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); 1171 arch_fpop_end(env); 1172 return RxV; 1173 } 1174 1175 static bool is_zero_prod(float32 a, float32 b) 1176 { 1177 return ((float32_is_zero(a) && is_finite(b)) || 1178 (float32_is_zero(b) && is_finite(a))); 1179 } 1180 1181 static float32 check_nan(float32 dst, float32 x, float_status *fp_status) 1182 { 1183 float32 ret = dst; 1184 if (float32_is_any_nan(x)) { 1185 if (extract32(x, 22, 1) == 0) { 1186 float_raise(float_flag_invalid, fp_status); 1187 } 1188 ret = make_float32(0xffffffff); /* nan */ 1189 } 1190 return ret; 1191 } 1192 1193 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV, 1194 float32 RsV, float32 RtV, float32 PuV) 1195 { 1196 size4s_t tmp; 1197 arch_fpop_start(env); 1198 RxV = check_nan(RxV, RxV, &env->fp_status); 1199 RxV = check_nan(RxV, RsV, &env->fp_status); 1200 RxV = check_nan(RxV, RtV, &env->fp_status); 1201 tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status); 1202 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1203 RxV = tmp; 1204 } 1205 arch_fpop_end(env); 1206 return RxV; 1207 } 1208 1209 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV, 1210 float32 RsV, float32 RtV) 1211 { 1212 float32 neg_RsV; 1213 arch_fpop_start(env); 1214 neg_RsV = float32_set_sign(RsV, float32_is_neg(RsV) ? 0 : 1); 1215 RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status); 1216 arch_fpop_end(env); 1217 return RxV; 1218 } 1219 1220 static bool is_inf_prod(int32_t a, int32_t b) 1221 { 1222 return (float32_is_infinity(a) && float32_is_infinity(b)) || 1223 (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) || 1224 (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a)); 1225 } 1226 1227 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, 1228 float32 RsV, float32 RtV) 1229 { 1230 bool infinp; 1231 bool infminusinf; 1232 float32 tmp; 1233 1234 arch_fpop_start(env); 1235 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 1236 infminusinf = float32_is_infinity(RxV) && 1237 is_inf_prod(RsV, RtV) && 1238 (fGETBIT(31, RsV ^ RxV ^ RtV) != 0); 1239 infinp = float32_is_infinity(RxV) || 1240 float32_is_infinity(RtV) || 1241 float32_is_infinity(RsV); 1242 RxV = check_nan(RxV, RxV, &env->fp_status); 1243 RxV = check_nan(RxV, RsV, &env->fp_status); 1244 RxV = check_nan(RxV, RtV, &env->fp_status); 1245 tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status); 1246 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1247 RxV = tmp; 1248 } 1249 set_float_exception_flags(0, &env->fp_status); 1250 if (float32_is_infinity(RxV) && !infinp) { 1251 RxV = RxV - 1; 1252 } 1253 if (infminusinf) { 1254 RxV = 0; 1255 } 1256 arch_fpop_end(env); 1257 return RxV; 1258 } 1259 1260 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV, 1261 float32 RsV, float32 RtV) 1262 { 1263 bool infinp; 1264 bool infminusinf; 1265 float32 tmp; 1266 1267 arch_fpop_start(env); 1268 set_float_rounding_mode(float_round_nearest_even, &env->fp_status); 1269 infminusinf = float32_is_infinity(RxV) && 1270 is_inf_prod(RsV, RtV) && 1271 (fGETBIT(31, RsV ^ RxV ^ RtV) == 0); 1272 infinp = float32_is_infinity(RxV) || 1273 float32_is_infinity(RtV) || 1274 float32_is_infinity(RsV); 1275 RxV = check_nan(RxV, RxV, &env->fp_status); 1276 RxV = check_nan(RxV, RsV, &env->fp_status); 1277 RxV = check_nan(RxV, RtV, &env->fp_status); 1278 float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status); 1279 tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status); 1280 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) { 1281 RxV = tmp; 1282 } 1283 set_float_exception_flags(0, &env->fp_status); 1284 if (float32_is_infinity(RxV) && !infinp) { 1285 RxV = RxV - 1; 1286 } 1287 if (infminusinf) { 1288 RxV = 0; 1289 } 1290 arch_fpop_end(env); 1291 return RxV; 1292 } 1293 1294 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV) 1295 { 1296 int64_t RddV; 1297 arch_fpop_start(env); 1298 if (float64_is_denormal(RssV) && 1299 (float64_getexp(RttV) >= 512) && 1300 float64_is_normal(RttV)) { 1301 RddV = float64_mul(RssV, make_float64(0x4330000000000000), 1302 &env->fp_status); 1303 } else if (float64_is_denormal(RttV) && 1304 (float64_getexp(RssV) >= 512) && 1305 float64_is_normal(RssV)) { 1306 RddV = float64_mul(RssV, make_float64(0x3cb0000000000000), 1307 &env->fp_status); 1308 } else { 1309 RddV = RssV; 1310 } 1311 arch_fpop_end(env); 1312 return RddV; 1313 } 1314 1315 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV, 1316 float64 RssV, float64 RttV) 1317 { 1318 arch_fpop_start(env); 1319 RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status); 1320 arch_fpop_end(env); 1321 return RxxV; 1322 } 1323 1324 /* Histogram instructions */ 1325 1326 void HELPER(vhist)(CPUHexagonState *env) 1327 { 1328 MMVector *input = &env->tmp_VRegs[0]; 1329 1330 for (int lane = 0; lane < 8; lane++) { 1331 for (int i = 0; i < sizeof(MMVector) / 8; ++i) { 1332 unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i]; 1333 unsigned char regno = value >> 3; 1334 unsigned char element = value & 7; 1335 1336 env->VRegs[regno].uh[(sizeof(MMVector) / 16) * lane + element]++; 1337 } 1338 } 1339 } 1340 1341 void HELPER(vhistq)(CPUHexagonState *env) 1342 { 1343 MMVector *input = &env->tmp_VRegs[0]; 1344 1345 for (int lane = 0; lane < 8; lane++) { 1346 for (int i = 0; i < sizeof(MMVector) / 8; ++i) { 1347 unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i]; 1348 unsigned char regno = value >> 3; 1349 unsigned char element = value & 7; 1350 1351 if (fGETQBIT(env->qtmp, sizeof(MMVector) / 8 * lane + i)) { 1352 env->VRegs[regno].uh[ 1353 (sizeof(MMVector) / 16) * lane + element]++; 1354 } 1355 } 1356 } 1357 } 1358 1359 void HELPER(vwhist256)(CPUHexagonState *env) 1360 { 1361 MMVector *input = &env->tmp_VRegs[0]; 1362 1363 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1364 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1365 unsigned int weight = fGETUBYTE(1, input->h[i]); 1366 unsigned int vindex = (bucket >> 3) & 0x1F; 1367 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7); 1368 1369 env->VRegs[vindex].uh[elindex] = 1370 env->VRegs[vindex].uh[elindex] + weight; 1371 } 1372 } 1373 1374 void HELPER(vwhist256q)(CPUHexagonState *env) 1375 { 1376 MMVector *input = &env->tmp_VRegs[0]; 1377 1378 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1379 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1380 unsigned int weight = fGETUBYTE(1, input->h[i]); 1381 unsigned int vindex = (bucket >> 3) & 0x1F; 1382 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7); 1383 1384 if (fGETQBIT(env->qtmp, 2 * i)) { 1385 env->VRegs[vindex].uh[elindex] = 1386 env->VRegs[vindex].uh[elindex] + weight; 1387 } 1388 } 1389 } 1390 1391 void HELPER(vwhist256_sat)(CPUHexagonState *env) 1392 { 1393 MMVector *input = &env->tmp_VRegs[0]; 1394 1395 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1396 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1397 unsigned int weight = fGETUBYTE(1, input->h[i]); 1398 unsigned int vindex = (bucket >> 3) & 0x1F; 1399 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7); 1400 1401 env->VRegs[vindex].uh[elindex] = 1402 fVSATUH(env->VRegs[vindex].uh[elindex] + weight); 1403 } 1404 } 1405 1406 void HELPER(vwhist256q_sat)(CPUHexagonState *env) 1407 { 1408 MMVector *input = &env->tmp_VRegs[0]; 1409 1410 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1411 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1412 unsigned int weight = fGETUBYTE(1, input->h[i]); 1413 unsigned int vindex = (bucket >> 3) & 0x1F; 1414 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7); 1415 1416 if (fGETQBIT(env->qtmp, 2 * i)) { 1417 env->VRegs[vindex].uh[elindex] = 1418 fVSATUH(env->VRegs[vindex].uh[elindex] + weight); 1419 } 1420 } 1421 } 1422 1423 void HELPER(vwhist128)(CPUHexagonState *env) 1424 { 1425 MMVector *input = &env->tmp_VRegs[0]; 1426 1427 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1428 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1429 unsigned int weight = fGETUBYTE(1, input->h[i]); 1430 unsigned int vindex = (bucket >> 3) & 0x1F; 1431 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3); 1432 1433 env->VRegs[vindex].uw[elindex] = 1434 env->VRegs[vindex].uw[elindex] + weight; 1435 } 1436 } 1437 1438 void HELPER(vwhist128q)(CPUHexagonState *env) 1439 { 1440 MMVector *input = &env->tmp_VRegs[0]; 1441 1442 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1443 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1444 unsigned int weight = fGETUBYTE(1, input->h[i]); 1445 unsigned int vindex = (bucket >> 3) & 0x1F; 1446 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3); 1447 1448 if (fGETQBIT(env->qtmp, 2 * i)) { 1449 env->VRegs[vindex].uw[elindex] = 1450 env->VRegs[vindex].uw[elindex] + weight; 1451 } 1452 } 1453 } 1454 1455 void HELPER(vwhist128m)(CPUHexagonState *env, int32_t uiV) 1456 { 1457 MMVector *input = &env->tmp_VRegs[0]; 1458 1459 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1460 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1461 unsigned int weight = fGETUBYTE(1, input->h[i]); 1462 unsigned int vindex = (bucket >> 3) & 0x1F; 1463 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3); 1464 1465 if ((bucket & 1) == uiV) { 1466 env->VRegs[vindex].uw[elindex] = 1467 env->VRegs[vindex].uw[elindex] + weight; 1468 } 1469 } 1470 } 1471 1472 void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV) 1473 { 1474 MMVector *input = &env->tmp_VRegs[0]; 1475 1476 for (int i = 0; i < (sizeof(MMVector) / 2); i++) { 1477 unsigned int bucket = fGETUBYTE(0, input->h[i]); 1478 unsigned int weight = fGETUBYTE(1, input->h[i]); 1479 unsigned int vindex = (bucket >> 3) & 0x1F; 1480 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3); 1481 1482 if (((bucket & 1) == uiV) && fGETQBIT(env->qtmp, 2 * i)) { 1483 env->VRegs[vindex].uw[elindex] = 1484 env->VRegs[vindex].uw[elindex] + weight; 1485 } 1486 } 1487 } 1488 1489 /* These macros can be referenced in the generated helper functions */ 1490 #define warn(...) /* Nothing */ 1491 #define fatal(...) g_assert_not_reached(); 1492 1493 #define BOGUS_HELPER(tag) \ 1494 printf("ERROR: bogus helper: " #tag "\n") 1495 1496 #include "helper_funcs_generated.c.inc" 1497