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