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