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