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