xref: /openbmc/qemu/target/hexagon/op_helper.c (revision 62a4db55)
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 /*
381  * mem_noshuf
382  * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
383  *
384  * If the load is in slot 0 and there is a store in slot1 (that
385  * wasn't cancelled), we have to do the store first.
386  */
387 static void check_noshuf(CPUHexagonState *env, uint32_t slot)
388 {
389     if (slot == 0 && env->pkt_has_store_s1 &&
390         ((env->slot_cancelled & (1 << 1)) == 0)) {
391         HELPER(commit_store)(env, 1);
392     }
393 }
394 
395 static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
396                          target_ulong vaddr)
397 {
398     uintptr_t ra = GETPC();
399     check_noshuf(env, slot);
400     return cpu_ldub_data_ra(env, vaddr, ra);
401 }
402 
403 static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
404                           target_ulong vaddr)
405 {
406     uintptr_t ra = GETPC();
407     check_noshuf(env, slot);
408     return cpu_lduw_data_ra(env, vaddr, ra);
409 }
410 
411 static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
412                           target_ulong vaddr)
413 {
414     uintptr_t ra = GETPC();
415     check_noshuf(env, slot);
416     return cpu_ldl_data_ra(env, vaddr, ra);
417 }
418 
419 static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
420                           target_ulong vaddr)
421 {
422     uintptr_t ra = GETPC();
423     check_noshuf(env, slot);
424     return cpu_ldq_data_ra(env, vaddr, ra);
425 }
426 
427 /* Floating point */
428 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
429 {
430     float64 out_f64;
431     arch_fpop_start(env);
432     out_f64 = float32_to_float64(RsV, &env->fp_status);
433     arch_fpop_end(env);
434     return out_f64;
435 }
436 
437 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
438 {
439     float32 out_f32;
440     arch_fpop_start(env);
441     out_f32 = float64_to_float32(RssV, &env->fp_status);
442     arch_fpop_end(env);
443     return out_f32;
444 }
445 
446 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
447 {
448     float32 RdV;
449     arch_fpop_start(env);
450     RdV = uint32_to_float32(RsV, &env->fp_status);
451     arch_fpop_end(env);
452     return RdV;
453 }
454 
455 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
456 {
457     float64 RddV;
458     arch_fpop_start(env);
459     RddV = uint32_to_float64(RsV, &env->fp_status);
460     arch_fpop_end(env);
461     return RddV;
462 }
463 
464 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
465 {
466     float32 RdV;
467     arch_fpop_start(env);
468     RdV = int32_to_float32(RsV, &env->fp_status);
469     arch_fpop_end(env);
470     return RdV;
471 }
472 
473 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
474 {
475     float64 RddV;
476     arch_fpop_start(env);
477     RddV = int32_to_float64(RsV, &env->fp_status);
478     arch_fpop_end(env);
479     return RddV;
480 }
481 
482 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
483 {
484     float32 RdV;
485     arch_fpop_start(env);
486     RdV = uint64_to_float32(RssV, &env->fp_status);
487     arch_fpop_end(env);
488     return RdV;
489 }
490 
491 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
492 {
493     float64 RddV;
494     arch_fpop_start(env);
495     RddV = uint64_to_float64(RssV, &env->fp_status);
496     arch_fpop_end(env);
497     return RddV;
498 }
499 
500 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
501 {
502     float32 RdV;
503     arch_fpop_start(env);
504     RdV = int64_to_float32(RssV, &env->fp_status);
505     arch_fpop_end(env);
506     return RdV;
507 }
508 
509 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
510 {
511     float64 RddV;
512     arch_fpop_start(env);
513     RddV = int64_to_float64(RssV, &env->fp_status);
514     arch_fpop_end(env);
515     return RddV;
516 }
517 
518 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
519 {
520     uint32_t RdV;
521     arch_fpop_start(env);
522     /* Hexagon checks the sign before rounding */
523     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
524         float_raise(float_flag_invalid, &env->fp_status);
525         RdV = 0;
526     } else {
527         RdV = float32_to_uint32(RsV, &env->fp_status);
528     }
529     arch_fpop_end(env);
530     return RdV;
531 }
532 
533 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
534 {
535     int32_t RdV;
536     arch_fpop_start(env);
537     /* Hexagon returns -1 for NaN */
538     if (float32_is_any_nan(RsV)) {
539         float_raise(float_flag_invalid, &env->fp_status);
540         RdV = -1;
541     } else {
542         RdV = float32_to_int32(RsV, &env->fp_status);
543     }
544     arch_fpop_end(env);
545     return RdV;
546 }
547 
548 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
549 {
550     uint64_t RddV;
551     arch_fpop_start(env);
552     /* Hexagon checks the sign before rounding */
553     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
554         float_raise(float_flag_invalid, &env->fp_status);
555         RddV = 0;
556     } else {
557         RddV = float32_to_uint64(RsV, &env->fp_status);
558     }
559     arch_fpop_end(env);
560     return RddV;
561 }
562 
563 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
564 {
565     int64_t RddV;
566     arch_fpop_start(env);
567     /* Hexagon returns -1 for NaN */
568     if (float32_is_any_nan(RsV)) {
569         float_raise(float_flag_invalid, &env->fp_status);
570         RddV = -1;
571     } else {
572         RddV = float32_to_int64(RsV, &env->fp_status);
573     }
574     arch_fpop_end(env);
575     return RddV;
576 }
577 
578 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
579 {
580     uint32_t RdV;
581     arch_fpop_start(env);
582     /* Hexagon checks the sign before rounding */
583     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
584         float_raise(float_flag_invalid, &env->fp_status);
585         RdV = 0;
586     } else {
587         RdV = float64_to_uint32(RssV, &env->fp_status);
588     }
589     arch_fpop_end(env);
590     return RdV;
591 }
592 
593 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
594 {
595     int32_t RdV;
596     arch_fpop_start(env);
597     /* Hexagon returns -1 for NaN */
598     if (float64_is_any_nan(RssV)) {
599         float_raise(float_flag_invalid, &env->fp_status);
600         RdV = -1;
601     } else {
602         RdV = float64_to_int32(RssV, &env->fp_status);
603     }
604     arch_fpop_end(env);
605     return RdV;
606 }
607 
608 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
609 {
610     uint64_t RddV;
611     arch_fpop_start(env);
612     /* Hexagon checks the sign before rounding */
613     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
614         float_raise(float_flag_invalid, &env->fp_status);
615         RddV = 0;
616     } else {
617         RddV = float64_to_uint64(RssV, &env->fp_status);
618     }
619     arch_fpop_end(env);
620     return RddV;
621 }
622 
623 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
624 {
625     int64_t RddV;
626     arch_fpop_start(env);
627     /* Hexagon returns -1 for NaN */
628     if (float64_is_any_nan(RssV)) {
629         float_raise(float_flag_invalid, &env->fp_status);
630         RddV = -1;
631     } else {
632         RddV = float64_to_int64(RssV, &env->fp_status);
633     }
634     arch_fpop_end(env);
635     return RddV;
636 }
637 
638 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
639 {
640     uint32_t RdV;
641     arch_fpop_start(env);
642     /* Hexagon checks the sign before rounding */
643     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
644         float_raise(float_flag_invalid, &env->fp_status);
645         RdV = 0;
646     } else {
647         RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
648     }
649     arch_fpop_end(env);
650     return RdV;
651 }
652 
653 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
654 {
655     int32_t RdV;
656     arch_fpop_start(env);
657     /* Hexagon returns -1 for NaN */
658     if (float32_is_any_nan(RsV)) {
659         float_raise(float_flag_invalid, &env->fp_status);
660         RdV = -1;
661     } else {
662         RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
663     }
664     arch_fpop_end(env);
665     return RdV;
666 }
667 
668 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
669 {
670     uint64_t RddV;
671     arch_fpop_start(env);
672     /* Hexagon checks the sign before rounding */
673     if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
674         float_raise(float_flag_invalid, &env->fp_status);
675         RddV = 0;
676     } else {
677         RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
678     }
679     arch_fpop_end(env);
680     return RddV;
681 }
682 
683 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
684 {
685     int64_t RddV;
686     arch_fpop_start(env);
687     /* Hexagon returns -1 for NaN */
688     if (float32_is_any_nan(RsV)) {
689         float_raise(float_flag_invalid, &env->fp_status);
690         RddV = -1;
691     } else {
692         RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
693     }
694     arch_fpop_end(env);
695     return RddV;
696 }
697 
698 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
699 {
700     uint32_t RdV;
701     arch_fpop_start(env);
702     /* Hexagon checks the sign before rounding */
703     if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
704         float_raise(float_flag_invalid, &env->fp_status);
705         RdV = 0;
706     } else {
707         RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
708     }
709     arch_fpop_end(env);
710     return RdV;
711 }
712 
713 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
714 {
715     int32_t RdV;
716     arch_fpop_start(env);
717     /* Hexagon returns -1 for NaN */
718     if (float64_is_any_nan(RssV)) {
719         float_raise(float_flag_invalid, &env->fp_status);
720         RdV = -1;
721     } else {
722         RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
723     }
724     arch_fpop_end(env);
725     return RdV;
726 }
727 
728 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
729 {
730     uint64_t RddV;
731     arch_fpop_start(env);
732     /* Hexagon checks the sign before rounding */
733     if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
734         float_raise(float_flag_invalid, &env->fp_status);
735         RddV = 0;
736     } else {
737         RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
738     }
739     arch_fpop_end(env);
740     return RddV;
741 }
742 
743 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
744 {
745     int64_t RddV;
746     arch_fpop_start(env);
747     /* Hexagon returns -1 for NaN */
748     if (float64_is_any_nan(RssV)) {
749         float_raise(float_flag_invalid, &env->fp_status);
750         RddV = -1;
751     } else {
752         RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
753     }
754     arch_fpop_end(env);
755     return RddV;
756 }
757 
758 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
759 {
760     float32 RdV;
761     arch_fpop_start(env);
762     RdV = float32_add(RsV, RtV, &env->fp_status);
763     arch_fpop_end(env);
764     return RdV;
765 }
766 
767 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
768 {
769     float32 RdV;
770     arch_fpop_start(env);
771     RdV = float32_sub(RsV, RtV, &env->fp_status);
772     arch_fpop_end(env);
773     return RdV;
774 }
775 
776 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
777 {
778     int32_t PdV;
779     arch_fpop_start(env);
780     PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
781     arch_fpop_end(env);
782     return PdV;
783 }
784 
785 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
786 {
787     int cmp;
788     int32_t PdV;
789     arch_fpop_start(env);
790     cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
791     PdV = f8BITSOF(cmp == float_relation_greater);
792     arch_fpop_end(env);
793     return PdV;
794 }
795 
796 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
797 {
798     int cmp;
799     int32_t PdV;
800     arch_fpop_start(env);
801     cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
802     PdV = f8BITSOF(cmp == float_relation_greater ||
803                    cmp == float_relation_equal);
804     arch_fpop_end(env);
805     return PdV;
806 }
807 
808 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
809 {
810     int32_t PdV;
811     arch_fpop_start(env);
812     PdV = f8BITSOF(float32_is_any_nan(RsV) ||
813                    float32_is_any_nan(RtV));
814     arch_fpop_end(env);
815     return PdV;
816 }
817 
818 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
819 {
820     float32 RdV;
821     arch_fpop_start(env);
822     RdV = float32_maxnum(RsV, RtV, &env->fp_status);
823     arch_fpop_end(env);
824     return RdV;
825 }
826 
827 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
828 {
829     float32 RdV;
830     arch_fpop_start(env);
831     RdV = float32_minnum(RsV, RtV, &env->fp_status);
832     arch_fpop_end(env);
833     return RdV;
834 }
835 
836 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
837 {
838     int32_t PdV = 0;
839     arch_fpop_start(env);
840     if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
841         PdV = 0xff;
842     }
843     if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
844         PdV = 0xff;
845     }
846     if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
847         PdV = 0xff;
848     }
849     if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
850         PdV = 0xff;
851     }
852     if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
853         PdV = 0xff;
854     }
855     set_float_exception_flags(0, &env->fp_status);
856     arch_fpop_end(env);
857     return PdV;
858 }
859 
860 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
861 {
862     float32 RdV = 0;
863     int adjust;
864     arch_fpop_start(env);
865     arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
866     RdV = RsV;
867     arch_fpop_end(env);
868     return RdV;
869 }
870 
871 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
872 {
873     float32 RdV = 0;
874     int adjust;
875     arch_fpop_start(env);
876     arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
877     RdV = RtV;
878     arch_fpop_end(env);
879     return RdV;
880 }
881 
882 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
883 {
884     float32 RdV = 0;
885     int adjust;
886     arch_fpop_start(env);
887     arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
888     RdV = RsV;
889     arch_fpop_end(env);
890     return RdV;
891 }
892 
893 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
894 {
895     float64 RddV;
896     arch_fpop_start(env);
897     RddV = float64_add(RssV, RttV, &env->fp_status);
898     arch_fpop_end(env);
899     return RddV;
900 }
901 
902 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
903 {
904     float64 RddV;
905     arch_fpop_start(env);
906     RddV = float64_sub(RssV, RttV, &env->fp_status);
907     arch_fpop_end(env);
908     return RddV;
909 }
910 
911 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
912 {
913     float64 RddV;
914     arch_fpop_start(env);
915     RddV = float64_maxnum(RssV, RttV, &env->fp_status);
916     if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
917         float_raise(float_flag_invalid, &env->fp_status);
918     }
919     arch_fpop_end(env);
920     return RddV;
921 }
922 
923 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
924 {
925     float64 RddV;
926     arch_fpop_start(env);
927     RddV = float64_minnum(RssV, RttV, &env->fp_status);
928     if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
929         float_raise(float_flag_invalid, &env->fp_status);
930     }
931     arch_fpop_end(env);
932     return RddV;
933 }
934 
935 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
936 {
937     int32_t PdV;
938     arch_fpop_start(env);
939     PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
940     arch_fpop_end(env);
941     return PdV;
942 }
943 
944 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
945 {
946     int cmp;
947     int32_t PdV;
948     arch_fpop_start(env);
949     cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
950     PdV = f8BITSOF(cmp == float_relation_greater);
951     arch_fpop_end(env);
952     return PdV;
953 }
954 
955 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
956 {
957     int cmp;
958     int32_t PdV;
959     arch_fpop_start(env);
960     cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
961     PdV = f8BITSOF(cmp == float_relation_greater ||
962                    cmp == float_relation_equal);
963     arch_fpop_end(env);
964     return PdV;
965 }
966 
967 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
968 {
969     int32_t PdV;
970     arch_fpop_start(env);
971     PdV = f8BITSOF(float64_is_any_nan(RssV) ||
972                    float64_is_any_nan(RttV));
973     arch_fpop_end(env);
974     return PdV;
975 }
976 
977 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
978 {
979     int32_t PdV = 0;
980     arch_fpop_start(env);
981     if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
982         PdV = 0xff;
983     }
984     if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
985         PdV = 0xff;
986     }
987     if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
988         PdV = 0xff;
989     }
990     if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
991         PdV = 0xff;
992     }
993     if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
994         PdV = 0xff;
995     }
996     set_float_exception_flags(0, &env->fp_status);
997     arch_fpop_end(env);
998     return PdV;
999 }
1000 
1001 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
1002 {
1003     float32 RdV;
1004     arch_fpop_start(env);
1005     RdV = internal_mpyf(RsV, RtV, &env->fp_status);
1006     arch_fpop_end(env);
1007     return RdV;
1008 }
1009 
1010 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
1011                       float32 RsV, float32 RtV)
1012 {
1013     arch_fpop_start(env);
1014     RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1015     arch_fpop_end(env);
1016     return RxV;
1017 }
1018 
1019 static bool is_zero_prod(float32 a, float32 b)
1020 {
1021     return ((float32_is_zero(a) && is_finite(b)) ||
1022             (float32_is_zero(b) && is_finite(a)));
1023 }
1024 
1025 static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
1026 {
1027     float32 ret = dst;
1028     if (float32_is_any_nan(x)) {
1029         if (extract32(x, 22, 1) == 0) {
1030             float_raise(float_flag_invalid, fp_status);
1031         }
1032         ret = make_float32(0xffffffff);    /* nan */
1033     }
1034     return ret;
1035 }
1036 
1037 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
1038                          float32 RsV, float32 RtV, float32 PuV)
1039 {
1040     size4s_t tmp;
1041     arch_fpop_start(env);
1042     RxV = check_nan(RxV, RxV, &env->fp_status);
1043     RxV = check_nan(RxV, RsV, &env->fp_status);
1044     RxV = check_nan(RxV, RtV, &env->fp_status);
1045     tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
1046     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1047         RxV = tmp;
1048     }
1049     arch_fpop_end(env);
1050     return RxV;
1051 }
1052 
1053 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
1054                       float32 RsV, float32 RtV)
1055 {
1056     float32 neg_RsV;
1057     arch_fpop_start(env);
1058     neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1059     RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
1060     arch_fpop_end(env);
1061     return RxV;
1062 }
1063 
1064 static bool is_inf_prod(int32_t a, int32_t b)
1065 {
1066     return (float32_is_infinity(a) && float32_is_infinity(b)) ||
1067            (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
1068            (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
1069 }
1070 
1071 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
1072                           float32 RsV, float32 RtV)
1073 {
1074     bool infinp;
1075     bool infminusinf;
1076     float32 tmp;
1077 
1078     arch_fpop_start(env);
1079     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1080     infminusinf = float32_is_infinity(RxV) &&
1081                   is_inf_prod(RsV, RtV) &&
1082                   (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
1083     infinp = float32_is_infinity(RxV) ||
1084              float32_is_infinity(RtV) ||
1085              float32_is_infinity(RsV);
1086     RxV = check_nan(RxV, RxV, &env->fp_status);
1087     RxV = check_nan(RxV, RsV, &env->fp_status);
1088     RxV = check_nan(RxV, RtV, &env->fp_status);
1089     tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1090     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1091         RxV = tmp;
1092     }
1093     set_float_exception_flags(0, &env->fp_status);
1094     if (float32_is_infinity(RxV) && !infinp) {
1095         RxV = RxV - 1;
1096     }
1097     if (infminusinf) {
1098         RxV = 0;
1099     }
1100     arch_fpop_end(env);
1101     return RxV;
1102 }
1103 
1104 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
1105                           float32 RsV, float32 RtV)
1106 {
1107     bool infinp;
1108     bool infminusinf;
1109     float32 tmp;
1110 
1111     arch_fpop_start(env);
1112     set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1113     infminusinf = float32_is_infinity(RxV) &&
1114                   is_inf_prod(RsV, RtV) &&
1115                   (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
1116     infinp = float32_is_infinity(RxV) ||
1117              float32_is_infinity(RtV) ||
1118              float32_is_infinity(RsV);
1119     RxV = check_nan(RxV, RxV, &env->fp_status);
1120     RxV = check_nan(RxV, RsV, &env->fp_status);
1121     RxV = check_nan(RxV, RtV, &env->fp_status);
1122     float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1123     tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
1124     if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1125         RxV = tmp;
1126     }
1127     set_float_exception_flags(0, &env->fp_status);
1128     if (float32_is_infinity(RxV) && !infinp) {
1129         RxV = RxV - 1;
1130     }
1131     if (infminusinf) {
1132         RxV = 0;
1133     }
1134     arch_fpop_end(env);
1135     return RxV;
1136 }
1137 
1138 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
1139 {
1140     int64_t RddV;
1141     arch_fpop_start(env);
1142     if (float64_is_denormal(RssV) &&
1143         (float64_getexp(RttV) >= 512) &&
1144         float64_is_normal(RttV)) {
1145         RddV = float64_mul(RssV, make_float64(0x4330000000000000),
1146                            &env->fp_status);
1147     } else if (float64_is_denormal(RttV) &&
1148                (float64_getexp(RssV) >= 512) &&
1149                float64_is_normal(RssV)) {
1150         RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
1151                            &env->fp_status);
1152     } else {
1153         RddV = RssV;
1154     }
1155     arch_fpop_end(env);
1156     return RddV;
1157 }
1158 
1159 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1160                         float64 RssV, float64 RttV)
1161 {
1162     arch_fpop_start(env);
1163     RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
1164     arch_fpop_end(env);
1165     return RxxV;
1166 }
1167 
1168 static void cancel_slot(CPUHexagonState *env, uint32_t slot)
1169 {
1170     HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
1171     env->slot_cancelled |= (1 << slot);
1172 }
1173 
1174 /* These macros can be referenced in the generated helper functions */
1175 #define warn(...) /* Nothing */
1176 #define fatal(...) g_assert_not_reached();
1177 
1178 #define BOGUS_HELPER(tag) \
1179     printf("ERROR: bogus helper: " #tag "\n")
1180 
1181 #include "helper_funcs_generated.c.inc"
1182