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