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