xref: /qemu/target/hexagon/op_helper.c (revision c3bef3b4)
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"
1485