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