xref: /openbmc/qemu/target/hexagon/op_helper.c (revision ac12b601)
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.h"
20 #include "exec/helper-proto.h"
21 #include "fpu/softfloat.h"
22 #include "cpu.h"
23 #include "internal.h"
24 #include "macros.h"
25 #include "arch.h"
26 #include "hex_arch_types.h"
27 #include "fma_emu.h"
28 
29 #define SF_BIAS        127
30 #define SF_MANTBITS    23
31 
32 /* Exceptions processing helpers */
33 static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
34                                                  uint32_t exception,
35                                                  uintptr_t pc)
36 {
37     CPUState *cs = env_cpu(env);
38     qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
39     cs->exception_index = exception;
40     cpu_loop_exit_restore(cs, pc);
41 }
42 
43 void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
44 {
45     do_raise_exception_err(env, excp, 0);
46 }
47 
48 static void log_reg_write(CPUHexagonState *env, int rnum,
49                           target_ulong val, uint32_t slot)
50 {
51     HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
52                   rnum, val, val);
53     if (val == env->gpr[rnum]) {
54         HEX_DEBUG_LOG(" NO CHANGE");
55     }
56     HEX_DEBUG_LOG("\n");
57 
58     env->new_value[rnum] = val;
59     if (HEX_DEBUG) {
60         /* Do this so HELPER(debug_commit_end) will know */
61         env->reg_written[rnum] = 1;
62     }
63 }
64 
65 static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
66 {
67     HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
68                   " (0x" TARGET_FMT_lx ")\n",
69                   pnum, val, val);
70 
71     /* Multiple writes to the same preg are and'ed together */
72     if (env->pred_written & (1 << pnum)) {
73         env->new_pred_value[pnum] &= val & 0xff;
74     } else {
75         env->new_pred_value[pnum] = val & 0xff;
76         env->pred_written |= 1 << pnum;
77     }
78 }
79 
80 static void log_store32(CPUHexagonState *env, target_ulong addr,
81                         target_ulong val, int width, int slot)
82 {
83     HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
84                   ", %" PRId32 " [0x08%" PRIx32 "])\n",
85                   width, addr, val, val);
86     env->mem_log_stores[slot].va = addr;
87     env->mem_log_stores[slot].width = width;
88     env->mem_log_stores[slot].data32 = val;
89 }
90 
91 static void log_store64(CPUHexagonState *env, target_ulong addr,
92                         int64_t val, int width, int slot)
93 {
94     HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
95                   ", %" PRId64 " [0x016%" PRIx64 "])\n",
96                    width, addr, val, val);
97     env->mem_log_stores[slot].va = addr;
98     env->mem_log_stores[slot].width = width;
99     env->mem_log_stores[slot].data64 = val;
100 }
101 
102 static void write_new_pc(CPUHexagonState *env, target_ulong addr)
103 {
104     HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
105 
106     /*
107      * If more than one branch is taken in a packet, only the first one
108      * is actually done.
109      */
110     if (env->branch_taken) {
111         HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
112                       "ignoring the second one\n");
113     } else {
114         fCHECK_PCALIGN(addr);
115         env->branch_taken = 1;
116         env->next_PC = addr;
117     }
118 }
119 
120 /* Handy place to set a breakpoint */
121 void HELPER(debug_start_packet)(CPUHexagonState *env)
122 {
123     HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
124                   env->gpr[HEX_REG_PC]);
125 
126     for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
127         env->reg_written[i] = 0;
128     }
129 }
130 
131 static int32_t new_pred_value(CPUHexagonState *env, int pnum)
132 {
133     return env->new_pred_value[pnum];
134 }
135 
136 /* Checks for bookkeeping errors between disassembly context and runtime */
137 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
138 {
139     if (env->mem_log_stores[slot].width != check) {
140         HEX_DEBUG_LOG("ERROR: %d != %d\n",
141                       env->mem_log_stores[slot].width, check);
142         g_assert_not_reached();
143     }
144 }
145 
146 void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
147 {
148     switch (env->mem_log_stores[slot_num].width) {
149     case 1:
150         put_user_u8(env->mem_log_stores[slot_num].data32,
151                     env->mem_log_stores[slot_num].va);
152         break;
153     case 2:
154         put_user_u16(env->mem_log_stores[slot_num].data32,
155                      env->mem_log_stores[slot_num].va);
156         break;
157     case 4:
158         put_user_u32(env->mem_log_stores[slot_num].data32,
159                      env->mem_log_stores[slot_num].va);
160         break;
161     case 8:
162         put_user_u64(env->mem_log_stores[slot_num].data64,
163                      env->mem_log_stores[slot_num].va);
164         break;
165     default:
166         g_assert_not_reached();
167     }
168 }
169 
170 static void print_store(CPUHexagonState *env, int slot)
171 {
172     if (!(env->slot_cancelled & (1 << slot))) {
173         uint8_t width = env->mem_log_stores[slot].width;
174         if (width == 1) {
175             uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
176             HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
177                           " (0x%02" PRIx32 ")\n",
178                           env->mem_log_stores[slot].va, data, data);
179         } else if (width == 2) {
180             uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
181             HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
182                           " (0x%04" PRIx32 ")\n",
183                           env->mem_log_stores[slot].va, data, data);
184         } else if (width == 4) {
185             uint32_t data = env->mem_log_stores[slot].data32;
186             HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
187                           " (0x%08" PRIx32 ")\n",
188                           env->mem_log_stores[slot].va, data, data);
189         } else if (width == 8) {
190             HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
191                           " (0x%016" PRIx64 ")\n",
192                           env->mem_log_stores[slot].va,
193                           env->mem_log_stores[slot].data64,
194                           env->mem_log_stores[slot].data64);
195         } else {
196             HEX_DEBUG_LOG("\tBad store width %d\n", width);
197             g_assert_not_reached();
198         }
199     }
200 }
201 
202 /* This function is a handy place to set a breakpoint */
203 void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
204 {
205     bool reg_printed = false;
206     bool pred_printed = false;
207     int i;
208 
209     HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n",
210                   env->this_PC);
211     HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
212 
213     for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
214         if (env->reg_written[i]) {
215             if (!reg_printed) {
216                 HEX_DEBUG_LOG("Regs written\n");
217                 reg_printed = true;
218             }
219             HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
220                           i, env->new_value[i], env->new_value[i]);
221         }
222     }
223 
224     for (i = 0; i < NUM_PREGS; i++) {
225         if (env->pred_written & (1 << i)) {
226             if (!pred_printed) {
227                 HEX_DEBUG_LOG("Predicates written\n");
228                 pred_printed = true;
229             }
230             HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
231                           i, env->new_pred_value[i]);
232         }
233     }
234 
235     if (has_st0 || has_st1) {
236         HEX_DEBUG_LOG("Stores\n");
237         if (has_st0) {
238             print_store(env, 0);
239         }
240         if (has_st1) {
241             print_store(env, 1);
242         }
243     }
244 
245     HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC);
246     HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
247                   ", insn = " TARGET_FMT_lx
248                   "\n",
249                   env->gpr[HEX_REG_QEMU_PKT_CNT],
250                   env->gpr[HEX_REG_QEMU_INSN_CNT]);
251 
252 }
253 
254 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
255 {
256     int32_t K_const = sextract32(M, 24, 4);
257     int32_t length = sextract32(M, 0, 17);
258     uint32_t new_ptr = RxV + offset;
259     uint32_t start_addr;
260     uint32_t end_addr;
261 
262     if (K_const == 0 && length >= 4) {
263         start_addr = CS;
264         end_addr = start_addr + length;
265     } else {
266         /*
267          * Versions v3 and earlier used the K value to specify a power-of-2 size
268          * 2^(K+2) that is greater than the buffer length
269          */
270         int32_t mask = (1 << (K_const + 2)) - 1;
271         start_addr = RxV & (~mask);
272         end_addr = start_addr | length;
273     }
274 
275     if (new_ptr >= end_addr) {
276         new_ptr -= length;
277     } else if (new_ptr < start_addr) {
278         new_ptr += length;
279     }
280 
281     return new_ptr;
282 }
283 
284 uint32_t HELPER(fbrev)(uint32_t addr)
285 {
286     /*
287      *  Bit reverse the low 16 bits of the address
288      */
289     return deposit32(addr, 0, 16, revbit16(addr));
290 }
291 
292 static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
293 {
294     return make_float32(
295         ((sign & 1) << 31) |
296         ((exp & 0xff) << SF_MANTBITS) |
297         (mant & ((1 << SF_MANTBITS) - 1)));
298 }
299 
300 /*
301  * sfrecipa, sfinvsqrta have two 32-bit results
302  *     r0,p0=sfrecipa(r1,r2)
303  *     r0,p0=sfinvsqrta(r1)
304  *
305  * Since helpers can only return a single value, we pack the two results
306  * into a 64-bit value.
307  */
308 uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
309 {
310     int32_t PeV = 0;
311     float32 RdV;
312     int idx;
313     int adjust;
314     int mant;
315     int exp;
316 
317     arch_fpop_start(env);
318     if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
319         PeV = adjust;
320         idx = (RtV >> 16) & 0x7f;
321         mant = (recip_lookup_table[idx] << 15) | 1;
322         exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
323         RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
324     }
325     arch_fpop_end(env);
326     return ((uint64_t)RdV << 32) | PeV;
327 }
328 
329 uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
330 {
331     int PeV = 0;
332     float32 RdV;
333     int idx;
334     int adjust;
335     int mant;
336     int exp;
337 
338     arch_fpop_start(env);
339     if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
340         PeV = adjust;
341         idx = (RsV >> 17) & 0x7f;
342         mant = (invsqrt_lookup_table[idx] << 15);
343         exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
344         RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
345     }
346     arch_fpop_end(env);
347     return ((uint64_t)RdV << 32) | PeV;
348 }
349 
350 int64_t HELPER(vacsh_val)(CPUHexagonState *env,
351                            int64_t RxxV, int64_t RssV, int64_t RttV)
352 {
353     for (int i = 0; i < 4; i++) {
354         int xv = sextract64(RxxV, i * 16, 16);
355         int sv = sextract64(RssV, i * 16, 16);
356         int tv = sextract64(RttV, i * 16, 16);
357         int max;
358         xv = xv + tv;
359         sv = sv - tv;
360         max = xv > sv ? xv : sv;
361         /* Note that fSATH can set the OVF bit in usr */
362         RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
363     }
364     return RxxV;
365 }
366 
367 int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
368                            int64_t RxxV, int64_t RssV, int64_t RttV)
369 {
370     int32_t PeV = 0;
371     for (int i = 0; i < 4; i++) {
372         int xv = sextract64(RxxV, i * 16, 16);
373         int sv = sextract64(RssV, i * 16, 16);
374         int tv = sextract64(RttV, i * 16, 16);
375         xv = xv + tv;
376         sv = sv - tv;
377         PeV = deposit32(PeV, i * 2, 1, (xv > sv));
378         PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
379     }
380     return PeV;
381 }
382 
383 /*
384  * mem_noshuf
385  * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
386  *
387  * If the load is in slot 0 and there is a store in slot1 (that
388  * wasn't cancelled), we have to do the store first.
389  */
390 static void check_noshuf(CPUHexagonState *env, uint32_t slot)
391 {
392     if (slot == 0 && env->pkt_has_store_s1 &&
393         ((env->slot_cancelled & (1 << 1)) == 0)) {
394         HELPER(commit_store)(env, 1);
395     }
396 }
397 
398 static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
399                          target_ulong vaddr)
400 {
401     uint8_t retval;
402     check_noshuf(env, slot);
403     get_user_u8(retval, vaddr);
404     return retval;
405 }
406 
407 static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
408                           target_ulong vaddr)
409 {
410     uint16_t retval;
411     check_noshuf(env, slot);
412     get_user_u16(retval, vaddr);
413     return retval;
414 }
415 
416 static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
417                           target_ulong vaddr)
418 {
419     uint32_t retval;
420     check_noshuf(env, slot);
421     get_user_u32(retval, vaddr);
422     return retval;
423 }
424 
425 static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
426                           target_ulong vaddr)
427 {
428     uint64_t retval;
429     check_noshuf(env, slot);
430     get_user_u64(retval, vaddr);
431     return retval;
432 }
433 
434 /* Floating point */
435 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
436 {
437     float64 out_f64;
438     arch_fpop_start(env);
439     out_f64 = float32_to_float64(RsV, &env->fp_status);
440     arch_fpop_end(env);
441     return out_f64;
442 }
443 
444 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
445 {
446     float32 out_f32;
447     arch_fpop_start(env);
448     out_f32 = float64_to_float32(RssV, &env->fp_status);
449     arch_fpop_end(env);
450     return out_f32;
451 }
452 
453 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
454 {
455     float32 RdV;
456     arch_fpop_start(env);
457     RdV = uint32_to_float32(RsV, &env->fp_status);
458     arch_fpop_end(env);
459     return RdV;
460 }
461 
462 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
463 {
464     float64 RddV;
465     arch_fpop_start(env);
466     RddV = uint32_to_float64(RsV, &env->fp_status);
467     arch_fpop_end(env);
468     return RddV;
469 }
470 
471 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
472 {
473     float32 RdV;
474     arch_fpop_start(env);
475     RdV = int32_to_float32(RsV, &env->fp_status);
476     arch_fpop_end(env);
477     return RdV;
478 }
479 
480 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
481 {
482     float64 RddV;
483     arch_fpop_start(env);
484     RddV = int32_to_float64(RsV, &env->fp_status);
485     arch_fpop_end(env);
486     return RddV;
487 }
488 
489 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
490 {
491     float32 RdV;
492     arch_fpop_start(env);
493     RdV = uint64_to_float32(RssV, &env->fp_status);
494     arch_fpop_end(env);
495     return RdV;
496 }
497 
498 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
499 {
500     float64 RddV;
501     arch_fpop_start(env);
502     RddV = uint64_to_float64(RssV, &env->fp_status);
503     arch_fpop_end(env);
504     return RddV;
505 }
506 
507 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
508 {
509     float32 RdV;
510     arch_fpop_start(env);
511     RdV = int64_to_float32(RssV, &env->fp_status);
512     arch_fpop_end(env);
513     return RdV;
514 }
515 
516 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
517 {
518     float64 RddV;
519     arch_fpop_start(env);
520     RddV = int64_to_float64(RssV, &env->fp_status);
521     arch_fpop_end(env);
522     return RddV;
523 }
524 
525 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
526 {
527     uint32_t RdV;
528     arch_fpop_start(env);
529     /* Hexagon checks the sign before rounding */
530     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
531         float_raise(float_flag_invalid, &env->fp_status);
532         RdV = 0;
533     } else {
534         RdV = float32_to_uint32(RsV, &env->fp_status);
535     }
536     arch_fpop_end(env);
537     return RdV;
538 }
539 
540 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
541 {
542     int32_t RdV;
543     arch_fpop_start(env);
544     /* Hexagon returns -1 for NaN */
545     if (float32_is_any_nan(RsV)) {
546         float_raise(float_flag_invalid, &env->fp_status);
547         RdV = -1;
548     } else {
549         RdV = float32_to_int32(RsV, &env->fp_status);
550     }
551     arch_fpop_end(env);
552     return RdV;
553 }
554 
555 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
556 {
557     uint64_t RddV;
558     arch_fpop_start(env);
559     /* Hexagon checks the sign before rounding */
560     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
561         float_raise(float_flag_invalid, &env->fp_status);
562         RddV = 0;
563     } else {
564         RddV = float32_to_uint64(RsV, &env->fp_status);
565     }
566     arch_fpop_end(env);
567     return RddV;
568 }
569 
570 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
571 {
572     int64_t RddV;
573     arch_fpop_start(env);
574     /* Hexagon returns -1 for NaN */
575     if (float32_is_any_nan(RsV)) {
576         float_raise(float_flag_invalid, &env->fp_status);
577         RddV = -1;
578     } else {
579         RddV = float32_to_int64(RsV, &env->fp_status);
580     }
581     arch_fpop_end(env);
582     return RddV;
583 }
584 
585 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
586 {
587     uint32_t RdV;
588     arch_fpop_start(env);
589     /* Hexagon checks the sign before rounding */
590     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
591         float_raise(float_flag_invalid, &env->fp_status);
592         RdV = 0;
593     } else {
594         RdV = float64_to_uint32(RssV, &env->fp_status);
595     }
596     arch_fpop_end(env);
597     return RdV;
598 }
599 
600 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
601 {
602     int32_t RdV;
603     arch_fpop_start(env);
604     /* Hexagon returns -1 for NaN */
605     if (float64_is_any_nan(RssV)) {
606         float_raise(float_flag_invalid, &env->fp_status);
607         RdV = -1;
608     } else {
609         RdV = float64_to_int32(RssV, &env->fp_status);
610     }
611     arch_fpop_end(env);
612     return RdV;
613 }
614 
615 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
616 {
617     uint64_t RddV;
618     arch_fpop_start(env);
619     /* Hexagon checks the sign before rounding */
620     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
621         float_raise(float_flag_invalid, &env->fp_status);
622         RddV = 0;
623     } else {
624         RddV = float64_to_uint64(RssV, &env->fp_status);
625     }
626     arch_fpop_end(env);
627     return RddV;
628 }
629 
630 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
631 {
632     int64_t RddV;
633     arch_fpop_start(env);
634     /* Hexagon returns -1 for NaN */
635     if (float64_is_any_nan(RssV)) {
636         float_raise(float_flag_invalid, &env->fp_status);
637         RddV = -1;
638     } else {
639         RddV = float64_to_int64(RssV, &env->fp_status);
640     }
641     arch_fpop_end(env);
642     return RddV;
643 }
644 
645 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
646 {
647     uint32_t RdV;
648     arch_fpop_start(env);
649     /* Hexagon checks the sign before rounding */
650     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
651         float_raise(float_flag_invalid, &env->fp_status);
652         RdV = 0;
653     } else {
654         RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
655     }
656     arch_fpop_end(env);
657     return RdV;
658 }
659 
660 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
661 {
662     int32_t RdV;
663     arch_fpop_start(env);
664     /* Hexagon returns -1 for NaN */
665     if (float32_is_any_nan(RsV)) {
666         float_raise(float_flag_invalid, &env->fp_status);
667         RdV = -1;
668     } else {
669         RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
670     }
671     arch_fpop_end(env);
672     return RdV;
673 }
674 
675 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
676 {
677     uint64_t RddV;
678     arch_fpop_start(env);
679     /* Hexagon checks the sign before rounding */
680     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
681         float_raise(float_flag_invalid, &env->fp_status);
682         RddV = 0;
683     } else {
684         RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
685     }
686     arch_fpop_end(env);
687     return RddV;
688 }
689 
690 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
691 {
692     int64_t RddV;
693     arch_fpop_start(env);
694     /* Hexagon returns -1 for NaN */
695     if (float32_is_any_nan(RsV)) {
696         float_raise(float_flag_invalid, &env->fp_status);
697         RddV = -1;
698     } else {
699         RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
700     }
701     arch_fpop_end(env);
702     return RddV;
703 }
704 
705 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
706 {
707     uint32_t RdV;
708     arch_fpop_start(env);
709     /* Hexagon checks the sign before rounding */
710     if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
711         float_raise(float_flag_invalid, &env->fp_status);
712         RdV = 0;
713     } else {
714         RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
715     }
716     arch_fpop_end(env);
717     return RdV;
718 }
719 
720 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
721 {
722     int32_t RdV;
723     arch_fpop_start(env);
724     /* Hexagon returns -1 for NaN */
725     if (float64_is_any_nan(RssV)) {
726         float_raise(float_flag_invalid, &env->fp_status);
727         RdV = -1;
728     } else {
729         RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
730     }
731     arch_fpop_end(env);
732     return RdV;
733 }
734 
735 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
736 {
737     uint64_t RddV;
738     arch_fpop_start(env);
739     /* Hexagon checks the sign before rounding */
740     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
741         float_raise(float_flag_invalid, &env->fp_status);
742         RddV = 0;
743     } else {
744         RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
745     }
746     arch_fpop_end(env);
747     return RddV;
748 }
749 
750 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
751 {
752     int64_t RddV;
753     arch_fpop_start(env);
754     /* Hexagon returns -1 for NaN */
755     if (float64_is_any_nan(RssV)) {
756         float_raise(float_flag_invalid, &env->fp_status);
757         RddV = -1;
758     } else {
759         RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
760     }
761     arch_fpop_end(env);
762     return RddV;
763 }
764 
765 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
766 {
767     float32 RdV;
768     arch_fpop_start(env);
769     RdV = float32_add(RsV, RtV, &env->fp_status);
770     arch_fpop_end(env);
771     return RdV;
772 }
773 
774 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
775 {
776     float32 RdV;
777     arch_fpop_start(env);
778     RdV = float32_sub(RsV, RtV, &env->fp_status);
779     arch_fpop_end(env);
780     return RdV;
781 }
782 
783 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
784 {
785     int32_t PdV;
786     arch_fpop_start(env);
787     PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
788     arch_fpop_end(env);
789     return PdV;
790 }
791 
792 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
793 {
794     int cmp;
795     int32_t PdV;
796     arch_fpop_start(env);
797     cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
798     PdV = f8BITSOF(cmp == float_relation_greater);
799     arch_fpop_end(env);
800     return PdV;
801 }
802 
803 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
804 {
805     int cmp;
806     int32_t PdV;
807     arch_fpop_start(env);
808     cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
809     PdV = f8BITSOF(cmp == float_relation_greater ||
810                    cmp == float_relation_equal);
811     arch_fpop_end(env);
812     return PdV;
813 }
814 
815 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
816 {
817     int32_t PdV;
818     arch_fpop_start(env);
819     PdV = f8BITSOF(float32_is_any_nan(RsV) ||
820                    float32_is_any_nan(RtV));
821     arch_fpop_end(env);
822     return PdV;
823 }
824 
825 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
826 {
827     float32 RdV;
828     arch_fpop_start(env);
829     RdV = float32_maxnum(RsV, RtV, &env->fp_status);
830     arch_fpop_end(env);
831     return RdV;
832 }
833 
834 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
835 {
836     float32 RdV;
837     arch_fpop_start(env);
838     RdV = float32_minnum(RsV, RtV, &env->fp_status);
839     arch_fpop_end(env);
840     return RdV;
841 }
842 
843 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
844 {
845     int32_t PdV = 0;
846     arch_fpop_start(env);
847     if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
848         PdV = 0xff;
849     }
850     if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
851         PdV = 0xff;
852     }
853     if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
854         PdV = 0xff;
855     }
856     if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
857         PdV = 0xff;
858     }
859     if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
860         PdV = 0xff;
861     }
862     set_float_exception_flags(0, &env->fp_status);
863     arch_fpop_end(env);
864     return PdV;
865 }
866 
867 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
868 {
869     float32 RdV = 0;
870     int adjust;
871     arch_fpop_start(env);
872     arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
873     RdV = RsV;
874     arch_fpop_end(env);
875     return RdV;
876 }
877 
878 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
879 {
880     float32 RdV = 0;
881     int adjust;
882     arch_fpop_start(env);
883     arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
884     RdV = RtV;
885     arch_fpop_end(env);
886     return RdV;
887 }
888 
889 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
890 {
891     float32 RdV = 0;
892     int adjust;
893     arch_fpop_start(env);
894     arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
895     RdV = RsV;
896     arch_fpop_end(env);
897     return RdV;
898 }
899 
900 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
901 {
902     float64 RddV;
903     arch_fpop_start(env);
904     RddV = float64_add(RssV, RttV, &env->fp_status);
905     arch_fpop_end(env);
906     return RddV;
907 }
908 
909 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
910 {
911     float64 RddV;
912     arch_fpop_start(env);
913     RddV = float64_sub(RssV, RttV, &env->fp_status);
914     arch_fpop_end(env);
915     return RddV;
916 }
917 
918 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
919 {
920     float64 RddV;
921     arch_fpop_start(env);
922     RddV = float64_maxnum(RssV, RttV, &env->fp_status);
923     if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
924         float_raise(float_flag_invalid, &env->fp_status);
925     }
926     arch_fpop_end(env);
927     return RddV;
928 }
929 
930 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
931 {
932     float64 RddV;
933     arch_fpop_start(env);
934     RddV = float64_minnum(RssV, RttV, &env->fp_status);
935     if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
936         float_raise(float_flag_invalid, &env->fp_status);
937     }
938     arch_fpop_end(env);
939     return RddV;
940 }
941 
942 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
943 {
944     int32_t PdV;
945     arch_fpop_start(env);
946     PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
947     arch_fpop_end(env);
948     return PdV;
949 }
950 
951 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
952 {
953     int cmp;
954     int32_t PdV;
955     arch_fpop_start(env);
956     cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
957     PdV = f8BITSOF(cmp == float_relation_greater);
958     arch_fpop_end(env);
959     return PdV;
960 }
961 
962 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
963 {
964     int cmp;
965     int32_t PdV;
966     arch_fpop_start(env);
967     cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
968     PdV = f8BITSOF(cmp == float_relation_greater ||
969                    cmp == float_relation_equal);
970     arch_fpop_end(env);
971     return PdV;
972 }
973 
974 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
975 {
976     int32_t PdV;
977     arch_fpop_start(env);
978     PdV = f8BITSOF(float64_is_any_nan(RssV) ||
979                    float64_is_any_nan(RttV));
980     arch_fpop_end(env);
981     return PdV;
982 }
983 
984 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
985 {
986     int32_t PdV = 0;
987     arch_fpop_start(env);
988     if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
989         PdV = 0xff;
990     }
991     if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
992         PdV = 0xff;
993     }
994     if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
995         PdV = 0xff;
996     }
997     if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
998         PdV = 0xff;
999     }
1000     if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
1001         PdV = 0xff;
1002     }
1003     set_float_exception_flags(0, &env->fp_status);
1004     arch_fpop_end(env);
1005     return PdV;
1006 }
1007 
1008 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
1009 {
1010     float32 RdV;
1011     arch_fpop_start(env);
1012     RdV = internal_mpyf(RsV, RtV, &env->fp_status);
1013     arch_fpop_end(env);
1014     return RdV;
1015 }
1016 
1017 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
1018                       float32 RsV, float32 RtV)
1019 {
1020     arch_fpop_start(env);
1021     RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1022     arch_fpop_end(env);
1023     return RxV;
1024 }
1025 
1026 static bool is_zero_prod(float32 a, float32 b)
1027 {
1028     return ((float32_is_zero(a) && is_finite(b)) ||
1029             (float32_is_zero(b) && is_finite(a)));
1030 }
1031 
1032 static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
1033 {
1034     float32 ret = dst;
1035     if (float32_is_any_nan(x)) {
1036         if (extract32(x, 22, 1) == 0) {
1037             float_raise(float_flag_invalid, fp_status);
1038         }
1039         ret = make_float32(0xffffffff);    /* nan */
1040     }
1041     return ret;
1042 }
1043 
1044 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
1045                          float32 RsV, float32 RtV, float32 PuV)
1046 {
1047     size4s_t tmp;
1048     arch_fpop_start(env);
1049     RxV = check_nan(RxV, RxV, &env->fp_status);
1050     RxV = check_nan(RxV, RsV, &env->fp_status);
1051     RxV = check_nan(RxV, RtV, &env->fp_status);
1052     tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
1053     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1054         RxV = tmp;
1055     }
1056     arch_fpop_end(env);
1057     return RxV;
1058 }
1059 
1060 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
1061                       float32 RsV, float32 RtV)
1062 {
1063     float32 neg_RsV;
1064     arch_fpop_start(env);
1065     neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1066     RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
1067     arch_fpop_end(env);
1068     return RxV;
1069 }
1070 
1071 static bool is_inf_prod(int32_t a, int32_t b)
1072 {
1073     return (float32_is_infinity(a) && float32_is_infinity(b)) ||
1074            (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
1075            (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
1076 }
1077 
1078 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
1079                           float32 RsV, float32 RtV)
1080 {
1081     bool infinp;
1082     bool infminusinf;
1083     float32 tmp;
1084 
1085     arch_fpop_start(env);
1086     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1087     infminusinf = float32_is_infinity(RxV) &&
1088                   is_inf_prod(RsV, RtV) &&
1089                   (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
1090     infinp = float32_is_infinity(RxV) ||
1091              float32_is_infinity(RtV) ||
1092              float32_is_infinity(RsV);
1093     RxV = check_nan(RxV, RxV, &env->fp_status);
1094     RxV = check_nan(RxV, RsV, &env->fp_status);
1095     RxV = check_nan(RxV, RtV, &env->fp_status);
1096     tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1097     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1098         RxV = tmp;
1099     }
1100     set_float_exception_flags(0, &env->fp_status);
1101     if (float32_is_infinity(RxV) && !infinp) {
1102         RxV = RxV - 1;
1103     }
1104     if (infminusinf) {
1105         RxV = 0;
1106     }
1107     arch_fpop_end(env);
1108     return RxV;
1109 }
1110 
1111 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
1112                           float32 RsV, float32 RtV)
1113 {
1114     bool infinp;
1115     bool infminusinf;
1116     float32 tmp;
1117 
1118     arch_fpop_start(env);
1119     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1120     infminusinf = float32_is_infinity(RxV) &&
1121                   is_inf_prod(RsV, RtV) &&
1122                   (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
1123     infinp = float32_is_infinity(RxV) ||
1124              float32_is_infinity(RtV) ||
1125              float32_is_infinity(RsV);
1126     RxV = check_nan(RxV, RxV, &env->fp_status);
1127     RxV = check_nan(RxV, RsV, &env->fp_status);
1128     RxV = check_nan(RxV, RtV, &env->fp_status);
1129     float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1130     tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
1131     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1132         RxV = tmp;
1133     }
1134     set_float_exception_flags(0, &env->fp_status);
1135     if (float32_is_infinity(RxV) && !infinp) {
1136         RxV = RxV - 1;
1137     }
1138     if (infminusinf) {
1139         RxV = 0;
1140     }
1141     arch_fpop_end(env);
1142     return RxV;
1143 }
1144 
1145 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
1146 {
1147     int64_t RddV;
1148     arch_fpop_start(env);
1149     if (float64_is_denormal(RssV) &&
1150         (float64_getexp(RttV) >= 512) &&
1151         float64_is_normal(RttV)) {
1152         RddV = float64_mul(RssV, make_float64(0x4330000000000000),
1153                            &env->fp_status);
1154     } else if (float64_is_denormal(RttV) &&
1155                (float64_getexp(RssV) >= 512) &&
1156                float64_is_normal(RssV)) {
1157         RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
1158                            &env->fp_status);
1159     } else {
1160         RddV = RssV;
1161     }
1162     arch_fpop_end(env);
1163     return RddV;
1164 }
1165 
1166 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1167                         float64 RssV, float64 RttV)
1168 {
1169     arch_fpop_start(env);
1170     RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
1171     arch_fpop_end(env);
1172     return RxxV;
1173 }
1174 
1175 static void cancel_slot(CPUHexagonState *env, uint32_t slot)
1176 {
1177     HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
1178     env->slot_cancelled |= (1 << slot);
1179 }
1180 
1181 /* These macros can be referenced in the generated helper functions */
1182 #define warn(...) /* Nothing */
1183 #define fatal(...) g_assert_not_reached();
1184 
1185 #define BOGUS_HELPER(tag) \
1186     printf("ERROR: bogus helper: " #tag "\n")
1187 
1188 #include "helper_funcs_generated.c.inc"
1189