scsi: move host_status handling into SCSI drivers
[qemu/ar7.git] / target / hexagon / op_helper.c
blob2c6d7185792cb0ae8d3379ab4bda65ae73c86192
1 /*
2 * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
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.
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.
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/>.
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"
30 #define SF_BIAS 127
31 #define SF_MANTBITS 23
33 /* Exceptions processing helpers */
34 static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
35 uint32_t exception,
36 uintptr_t pc)
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);
44 void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
46 do_raise_exception_err(env, excp, 0);
49 static inline void log_reg_write(CPUHexagonState *env, int rnum,
50 target_ulong val, uint32_t slot)
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");
57 HEX_DEBUG_LOG("\n");
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
66 static inline void log_pred_write(CPUHexagonState *env, int pnum,
67 target_ulong val)
69 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
70 " (0x" TARGET_FMT_lx ")\n",
71 pnum, val, val);
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;
82 static inline void log_store32(CPUHexagonState *env, target_ulong addr,
83 target_ulong val, int width, int slot)
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;
93 static inline void log_store64(CPUHexagonState *env, target_ulong addr,
94 int64_t val, int width, int slot)
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;
104 static inline void write_new_pc(CPUHexagonState *env, target_ulong addr)
106 HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
109 * If more than one branch is taken in a packet, only the first one
110 * is actually done.
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;
122 #if HEX_DEBUG
123 /* Handy place to set a breakpoint */
124 void HELPER(debug_start_packet)(CPUHexagonState *env)
126 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
127 env->gpr[HEX_REG_PC]);
129 for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
130 env->reg_written[i] = 0;
133 #endif
135 static inline int32_t new_pred_value(CPUHexagonState *env, int pnum)
137 return env->new_pred_value[pnum];
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)
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();
150 #endif
152 void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
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();
176 #if HEX_DEBUG
177 static void print_store(CPUHexagonState *env, int slot)
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();
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)
212 bool reg_printed = false;
213 bool pred_printed = false;
214 int i;
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);
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;
226 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
227 i, env->new_value[i], env->new_value[i]);
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;
237 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
238 i, env->new_pred_value[i]);
242 if (has_st0 || has_st1) {
243 HEX_DEBUG_LOG("Stores\n");
244 if (has_st0) {
245 print_store(env, 0);
247 if (has_st1) {
248 print_store(env, 1);
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]);
260 #endif
262 static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
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;
269 if (new_ptr >= end_addr) {
270 new_ptr -= length;
271 } else if (new_ptr < start_addr) {
272 new_ptr += length;
275 return new_ptr;
278 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
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;
287 if (K_const == 0 && length >= 4) {
288 return fcircadd_v4(RxV, offset, M, CS);
291 if (new_ptr >= end_addr) {
292 new_ptr -= length;
293 } else if (new_ptr < start_addr) {
294 new_ptr += length;
297 return new_ptr;
301 * Hexagon FP operations return ~0 insteat of NaN
302 * The hex_check_sfnan/hex_check_dfnan functions perform this check
304 static float32 hex_check_sfnan(float32 x)
306 if (float32_is_any_nan(x)) {
307 return make_float32(0xFFFFFFFFU);
309 return x;
312 static float64 hex_check_dfnan(float64 x)
314 if (float64_is_any_nan(x)) {
315 return make_float64(0xFFFFFFFFFFFFFFFFULL);
317 return x;
321 * mem_noshuf
322 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
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.
327 static void check_noshuf(CPUHexagonState *env, uint32_t slot)
329 if (slot == 0 && env->pkt_has_store_s1 &&
330 ((env->slot_cancelled & (1 << 1)) == 0)) {
331 HELPER(commit_store)(env, 1);
335 static inline uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
336 target_ulong vaddr)
338 uint8_t retval;
339 check_noshuf(env, slot);
340 get_user_u8(retval, vaddr);
341 return retval;
344 static inline uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
345 target_ulong vaddr)
347 uint16_t retval;
348 check_noshuf(env, slot);
349 get_user_u16(retval, vaddr);
350 return retval;
353 static inline uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
354 target_ulong vaddr)
356 uint32_t retval;
357 check_noshuf(env, slot);
358 get_user_u32(retval, vaddr);
359 return retval;
362 static inline uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
363 target_ulong vaddr)
365 uint64_t retval;
366 check_noshuf(env, slot);
367 get_user_u64(retval, vaddr);
368 return retval;
371 /* Floating point */
372 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
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;
382 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
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;
392 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
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;
402 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
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;
412 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
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;
422 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
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;
432 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
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;
442 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
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;
452 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
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;
462 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
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;
472 int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
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;
481 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
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;
490 int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
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;
499 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
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;
508 int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
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;
517 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
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;
526 int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
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;
535 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
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;
544 int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
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;
554 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
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;
564 int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
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;
574 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
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;
584 int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
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;
594 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
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;
604 int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
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;
614 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
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;
624 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
634 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
644 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
653 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
664 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
676 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
686 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
696 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
706 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
708 int32_t PdV = 0;
709 arch_fpop_start(env);
710 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
711 PdV = 0xff;
713 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
714 PdV = 0xff;
716 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
717 PdV = 0xff;
719 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
720 PdV = 0xff;
722 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
723 PdV = 0xff;
725 set_float_exception_flags(0, &env->fp_status);
726 arch_fpop_end(env);
727 return PdV;
730 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
741 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
752 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
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;
763 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
773 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
783 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
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);
791 RddV = hex_check_dfnan(RddV);
792 arch_fpop_end(env);
793 return RddV;
796 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
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);
804 RddV = hex_check_dfnan(RddV);
805 arch_fpop_end(env);
806 return RddV;
809 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
818 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
829 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
841 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
851 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
853 int32_t PdV = 0;
854 arch_fpop_start(env);
855 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
856 PdV = 0xff;
858 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
859 PdV = 0xff;
861 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
862 PdV = 0xff;
864 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
865 PdV = 0xff;
867 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
868 PdV = 0xff;
870 set_float_exception_flags(0, &env->fp_status);
871 arch_fpop_end(env);
872 return PdV;
875 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
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;
885 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
886 float32 RsV, float32 RtV)
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;
895 static bool is_zero_prod(float32 a, float32 b)
897 return ((float32_is_zero(a) && is_finite(b)) ||
898 (float32_is_zero(b) && is_finite(a)));
901 static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
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);
908 ret = make_float32(0xffffffff); /* nan */
910 return ret;
913 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
914 float32 RsV, float32 RtV, float32 PuV)
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;
926 arch_fpop_end(env);
927 return RxV;
930 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
931 float32 RsV, float32 RtV)
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;
942 static inline bool is_inf_prod(int32_t a, int32_t b)
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));
949 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
950 float32 RsV, float32 RtV)
952 int infinp;
953 int infminusinf;
954 float32 tmp;
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;
972 set_float_exception_flags(0, &env->fp_status);
973 if (float32_is_infinity(RxV) && !infinp) {
974 RxV = RxV - 1;
976 if (infminusinf) {
977 RxV = 0;
979 arch_fpop_end(env);
980 return RxV;
983 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
984 float32 RsV, float32 RtV)
986 int infinp;
987 int infminusinf;
988 float32 tmp;
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;
1007 set_float_exception_flags(0, &env->fp_status);
1008 if (float32_is_infinity(RxV) && !infinp) {
1009 RxV = RxV - 1;
1011 if (infminusinf) {
1012 RxV = 0;
1014 arch_fpop_end(env);
1015 return RxV;
1018 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
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;
1037 arch_fpop_end(env);
1038 return RddV;
1041 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1042 float64 RssV, float64 RttV)
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;
1051 static void cancel_slot(CPUHexagonState *env, uint32_t slot)
1053 HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
1054 env->slot_cancelled |= (1 << slot);
1057 /* These macros can be referenced in the generated helper functions */
1058 #define warn(...) /* Nothing */
1059 #define fatal(...) g_assert_not_reached();
1061 #define BOGUS_HELPER(tag) \
1062 printf("ERROR: bogus helper: " #tag "\n")
1064 #include "helper_funcs_generated.c.inc"