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"
20 #include "exec/helper-proto.h"
21 #include "fpu/softfloat.h"
26 #include "hex_arch_types.h"
31 #define SF_MANTBITS 23
33 /* Exceptions processing helpers */
34 static void QEMU_NORETURN
do_raise_exception_err(CPUHexagonState
*env
,
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
")",
54 if (val
== env
->gpr
[rnum
]) {
55 HEX_DEBUG_LOG(" NO CHANGE");
59 env
->new_value
[rnum
] = val
;
61 /* Do this so HELPER(debug_commit_end) will know */
62 env
->reg_written
[rnum
] = 1;
66 static inline void log_pred_write(CPUHexagonState
*env
, int pnum
,
69 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
70 " (0x" TARGET_FMT_lx
")\n",
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;
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
112 if (env
->branch_taken
) {
113 HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
114 "ignoring the second one\n");
116 fCHECK_PCALIGN(addr
);
117 env
->branch_taken
= 1;
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;
135 static inline int32_t new_pred_value(CPUHexagonState
*env
, int pnum
)
137 return env
->new_pred_value
[pnum
];
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();
152 void HELPER(commit_store
)(CPUHexagonState
*env
, int slot_num
)
154 switch (env
->mem_log_stores
[slot_num
].width
) {
156 put_user_u8(env
->mem_log_stores
[slot_num
].data32
,
157 env
->mem_log_stores
[slot_num
].va
);
160 put_user_u16(env
->mem_log_stores
[slot_num
].data32
,
161 env
->mem_log_stores
[slot_num
].va
);
164 put_user_u32(env
->mem_log_stores
[slot_num
].data32
,
165 env
->mem_log_stores
[slot_num
].va
);
168 put_user_u64(env
->mem_log_stores
[slot_num
].data64
,
169 env
->mem_log_stores
[slot_num
].va
);
172 g_assert_not_reached();
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
;
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
);
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;
216 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx
"\n",
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
]) {
223 HEX_DEBUG_LOG("Regs written\n");
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
)) {
234 HEX_DEBUG_LOG("Predicates written\n");
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");
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
256 env
->gpr
[HEX_REG_QEMU_PKT_CNT
],
257 env
->gpr
[HEX_REG_QEMU_INSN_CNT
]);
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
) {
271 } else if (new_ptr
< start_addr
) {
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
) {
293 } else if (new_ptr
< start_addr
) {
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
);
312 static float64
hex_check_dfnan(float64 x
)
314 if (float64_is_any_nan(x
)) {
315 return make_float64(0xFFFFFFFFFFFFFFFFULL
);
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
,
339 check_noshuf(env
, slot
);
340 get_user_u8(retval
, vaddr
);
344 static inline uint16_t mem_load2(CPUHexagonState
*env
, uint32_t slot
,
348 check_noshuf(env
, slot
);
349 get_user_u16(retval
, vaddr
);
353 static inline uint32_t mem_load4(CPUHexagonState
*env
, uint32_t slot
,
357 check_noshuf(env
, slot
);
358 get_user_u32(retval
, vaddr
);
362 static inline uint64_t mem_load8(CPUHexagonState
*env
, uint32_t slot
,
366 check_noshuf(env
, slot
);
367 get_user_u64(retval
, vaddr
);
372 float64
HELPER(conv_sf2df
)(CPUHexagonState
*env
, float32 RsV
)
375 arch_fpop_start(env
);
376 out_f64
= float32_to_float64(RsV
, &env
->fp_status
);
377 out_f64
= hex_check_dfnan(out_f64
);
382 float32
HELPER(conv_df2sf
)(CPUHexagonState
*env
, float64 RssV
)
385 arch_fpop_start(env
);
386 out_f32
= float64_to_float32(RssV
, &env
->fp_status
);
387 out_f32
= hex_check_sfnan(out_f32
);
392 float32
HELPER(conv_uw2sf
)(CPUHexagonState
*env
, int32_t RsV
)
395 arch_fpop_start(env
);
396 RdV
= uint32_to_float32(RsV
, &env
->fp_status
);
397 RdV
= hex_check_sfnan(RdV
);
402 float64
HELPER(conv_uw2df
)(CPUHexagonState
*env
, int32_t RsV
)
405 arch_fpop_start(env
);
406 RddV
= uint32_to_float64(RsV
, &env
->fp_status
);
407 RddV
= hex_check_dfnan(RddV
);
412 float32
HELPER(conv_w2sf
)(CPUHexagonState
*env
, int32_t RsV
)
415 arch_fpop_start(env
);
416 RdV
= int32_to_float32(RsV
, &env
->fp_status
);
417 RdV
= hex_check_sfnan(RdV
);
422 float64
HELPER(conv_w2df
)(CPUHexagonState
*env
, int32_t RsV
)
425 arch_fpop_start(env
);
426 RddV
= int32_to_float64(RsV
, &env
->fp_status
);
427 RddV
= hex_check_dfnan(RddV
);
432 float32
HELPER(conv_ud2sf
)(CPUHexagonState
*env
, int64_t RssV
)
435 arch_fpop_start(env
);
436 RdV
= uint64_to_float32(RssV
, &env
->fp_status
);
437 RdV
= hex_check_sfnan(RdV
);
442 float64
HELPER(conv_ud2df
)(CPUHexagonState
*env
, int64_t RssV
)
445 arch_fpop_start(env
);
446 RddV
= uint64_to_float64(RssV
, &env
->fp_status
);
447 RddV
= hex_check_dfnan(RddV
);
452 float32
HELPER(conv_d2sf
)(CPUHexagonState
*env
, int64_t RssV
)
455 arch_fpop_start(env
);
456 RdV
= int64_to_float32(RssV
, &env
->fp_status
);
457 RdV
= hex_check_sfnan(RdV
);
462 float64
HELPER(conv_d2df
)(CPUHexagonState
*env
, int64_t RssV
)
465 arch_fpop_start(env
);
466 RddV
= int64_to_float64(RssV
, &env
->fp_status
);
467 RddV
= hex_check_dfnan(RddV
);
472 int32_t HELPER(conv_sf2uw
)(CPUHexagonState
*env
, float32 RsV
)
475 arch_fpop_start(env
);
476 RdV
= conv_sf_to_4u(RsV
, &env
->fp_status
);
481 int32_t HELPER(conv_sf2w
)(CPUHexagonState
*env
, float32 RsV
)
484 arch_fpop_start(env
);
485 RdV
= conv_sf_to_4s(RsV
, &env
->fp_status
);
490 int64_t HELPER(conv_sf2ud
)(CPUHexagonState
*env
, float32 RsV
)
493 arch_fpop_start(env
);
494 RddV
= conv_sf_to_8u(RsV
, &env
->fp_status
);
499 int64_t HELPER(conv_sf2d
)(CPUHexagonState
*env
, float32 RsV
)
502 arch_fpop_start(env
);
503 RddV
= conv_sf_to_8s(RsV
, &env
->fp_status
);
508 int32_t HELPER(conv_df2uw
)(CPUHexagonState
*env
, float64 RssV
)
511 arch_fpop_start(env
);
512 RdV
= conv_df_to_4u(RssV
, &env
->fp_status
);
517 int32_t HELPER(conv_df2w
)(CPUHexagonState
*env
, float64 RssV
)
520 arch_fpop_start(env
);
521 RdV
= conv_df_to_4s(RssV
, &env
->fp_status
);
526 int64_t HELPER(conv_df2ud
)(CPUHexagonState
*env
, float64 RssV
)
529 arch_fpop_start(env
);
530 RddV
= conv_df_to_8u(RssV
, &env
->fp_status
);
535 int64_t HELPER(conv_df2d
)(CPUHexagonState
*env
, float64 RssV
)
538 arch_fpop_start(env
);
539 RddV
= conv_df_to_8s(RssV
, &env
->fp_status
);
544 int32_t HELPER(conv_sf2uw_chop
)(CPUHexagonState
*env
, float32 RsV
)
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
);
554 int32_t HELPER(conv_sf2w_chop
)(CPUHexagonState
*env
, float32 RsV
)
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
);
564 int64_t HELPER(conv_sf2ud_chop
)(CPUHexagonState
*env
, float32 RsV
)
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
);
574 int64_t HELPER(conv_sf2d_chop
)(CPUHexagonState
*env
, float32 RsV
)
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
);
584 int32_t HELPER(conv_df2uw_chop
)(CPUHexagonState
*env
, float64 RssV
)
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
);
594 int32_t HELPER(conv_df2w_chop
)(CPUHexagonState
*env
, float64 RssV
)
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
);
604 int64_t HELPER(conv_df2ud_chop
)(CPUHexagonState
*env
, float64 RssV
)
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
);
614 int64_t HELPER(conv_df2d_chop
)(CPUHexagonState
*env
, float64 RssV
)
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
);
624 float32
HELPER(sfadd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
627 arch_fpop_start(env
);
628 RdV
= float32_add(RsV
, RtV
, &env
->fp_status
);
629 RdV
= hex_check_sfnan(RdV
);
634 float32
HELPER(sfsub
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
637 arch_fpop_start(env
);
638 RdV
= float32_sub(RsV
, RtV
, &env
->fp_status
);
639 RdV
= hex_check_sfnan(RdV
);
644 int32_t HELPER(sfcmpeq
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
647 arch_fpop_start(env
);
648 PdV
= f8BITSOF(float32_eq_quiet(RsV
, RtV
, &env
->fp_status
));
653 int32_t HELPER(sfcmpgt
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
657 arch_fpop_start(env
);
658 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
659 PdV
= f8BITSOF(cmp
== float_relation_greater
);
664 int32_t HELPER(sfcmpge
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
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
);
676 int32_t HELPER(sfcmpuo
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
679 arch_fpop_start(env
);
680 PdV
= f8BITSOF(float32_is_any_nan(RsV
) ||
681 float32_is_any_nan(RtV
));
686 float32
HELPER(sfmax
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
689 arch_fpop_start(env
);
690 RdV
= float32_maxnum(RsV
, RtV
, &env
->fp_status
);
691 RdV
= hex_check_sfnan(RdV
);
696 float32
HELPER(sfmin
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
699 arch_fpop_start(env
);
700 RdV
= float32_minnum(RsV
, RtV
, &env
->fp_status
);
701 RdV
= hex_check_sfnan(RdV
);
706 int32_t HELPER(sfclass
)(CPUHexagonState
*env
, float32 RsV
, int32_t uiV
)
709 arch_fpop_start(env
);
710 if (fGETBIT(0, uiV
) && float32_is_zero(RsV
)) {
713 if (fGETBIT(1, uiV
) && float32_is_normal(RsV
)) {
716 if (fGETBIT(2, uiV
) && float32_is_denormal(RsV
)) {
719 if (fGETBIT(3, uiV
) && float32_is_infinity(RsV
)) {
722 if (fGETBIT(4, uiV
) && float32_is_any_nan(RsV
)) {
725 set_float_exception_flags(0, &env
->fp_status
);
730 float32
HELPER(sffixupn
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
734 arch_fpop_start(env
);
735 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
741 float32
HELPER(sffixupd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
745 arch_fpop_start(env
);
746 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
752 float32
HELPER(sffixupr
)(CPUHexagonState
*env
, float32 RsV
)
756 arch_fpop_start(env
);
757 arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
);
763 float64
HELPER(dfadd
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
766 arch_fpop_start(env
);
767 RddV
= float64_add(RssV
, RttV
, &env
->fp_status
);
768 RddV
= hex_check_dfnan(RddV
);
773 float64
HELPER(dfsub
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
776 arch_fpop_start(env
);
777 RddV
= float64_sub(RssV
, RttV
, &env
->fp_status
);
778 RddV
= hex_check_dfnan(RddV
);
783 float64
HELPER(dfmax
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
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
);
796 float64
HELPER(dfmin
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
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
);
809 int32_t HELPER(dfcmpeq
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
812 arch_fpop_start(env
);
813 PdV
= f8BITSOF(float64_eq_quiet(RssV
, RttV
, &env
->fp_status
));
818 int32_t HELPER(dfcmpgt
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
822 arch_fpop_start(env
);
823 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
824 PdV
= f8BITSOF(cmp
== float_relation_greater
);
829 int32_t HELPER(dfcmpge
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
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
);
841 int32_t HELPER(dfcmpuo
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
844 arch_fpop_start(env
);
845 PdV
= f8BITSOF(float64_is_any_nan(RssV
) ||
846 float64_is_any_nan(RttV
));
851 int32_t HELPER(dfclass
)(CPUHexagonState
*env
, float64 RssV
, int32_t uiV
)
854 arch_fpop_start(env
);
855 if (fGETBIT(0, uiV
) && float64_is_zero(RssV
)) {
858 if (fGETBIT(1, uiV
) && float64_is_normal(RssV
)) {
861 if (fGETBIT(2, uiV
) && float64_is_denormal(RssV
)) {
864 if (fGETBIT(3, uiV
) && float64_is_infinity(RssV
)) {
867 if (fGETBIT(4, uiV
) && float64_is_any_nan(RssV
)) {
870 set_float_exception_flags(0, &env
->fp_status
);
875 float32
HELPER(sfmpy
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
878 arch_fpop_start(env
);
879 RdV
= internal_mpyf(RsV
, RtV
, &env
->fp_status
);
880 RdV
= hex_check_sfnan(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
);
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
)
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 */
913 float32
HELPER(sffma_sc
)(CPUHexagonState
*env
, float32 RxV
,
914 float32 RsV
, float32 RtV
, float32 PuV
)
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
))) {
930 float32
HELPER(sffms
)(CPUHexagonState
*env
, float32 RxV
,
931 float32 RsV
, float32 RtV
)
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
);
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
)
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
))) {
972 set_float_exception_flags(0, &env
->fp_status
);
973 if (float32_is_infinity(RxV
) && !infinp
) {
983 float32
HELPER(sffms_lib
)(CPUHexagonState
*env
, float32 RxV
,
984 float32 RsV
, float32 RtV
)
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
))) {
1007 set_float_exception_flags(0, &env
->fp_status
);
1008 if (float32_is_infinity(RxV
) && !infinp
) {
1018 float64
HELPER(dfmpyfix
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
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),
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),
1033 RddV
= hex_check_dfnan(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
);
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"