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"
30 #define SF_MANTBITS 23
32 /* Exceptions processing helpers */
33 static void QEMU_NORETURN
do_raise_exception_err(CPUHexagonState
*env
,
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
);
43 void QEMU_NORETURN
HELPER(raise_exception
)(CPUHexagonState
*env
, uint32_t excp
)
45 do_raise_exception_err(env
, excp
, 0);
48 static void log_reg_write(CPUHexagonState
*env
, int rnum
,
49 target_ulong val
, uint32_t slot
)
51 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")",
53 if (val
== env
->gpr
[rnum
]) {
54 HEX_DEBUG_LOG(" NO CHANGE");
58 env
->new_value
[rnum
] = val
;
60 /* Do this so HELPER(debug_commit_end) will know */
61 env
->reg_written
[rnum
] = 1;
65 static void log_pred_write(CPUHexagonState
*env
, int pnum
, target_ulong val
)
67 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
68 " (0x" TARGET_FMT_lx
")\n",
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;
75 env
->new_pred_value
[pnum
] = val
& 0xff;
76 env
->pred_written
|= 1 << pnum
;
80 static void log_store32(CPUHexagonState
*env
, target_ulong addr
,
81 target_ulong val
, int width
, int slot
)
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
;
91 static void log_store64(CPUHexagonState
*env
, target_ulong addr
,
92 int64_t val
, int width
, int slot
)
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
;
102 static void write_new_pc(CPUHexagonState
*env
, target_ulong addr
)
104 HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx
")\n", addr
);
107 * If more than one branch is taken in a packet, only the first one
110 if (env
->branch_taken
) {
111 HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
112 "ignoring the second one\n");
114 fCHECK_PCALIGN(addr
);
115 env
->branch_taken
= 1;
120 /* Handy place to set a breakpoint */
121 void HELPER(debug_start_packet
)(CPUHexagonState
*env
)
123 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx
"\n",
124 env
->gpr
[HEX_REG_PC
]);
126 for (int i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
127 env
->reg_written
[i
] = 0;
131 static int32_t new_pred_value(CPUHexagonState
*env
, int pnum
)
133 return env
->new_pred_value
[pnum
];
136 /* Checks for bookkeeping errors between disassembly context and runtime */
137 void HELPER(debug_check_store_width
)(CPUHexagonState
*env
, int slot
, int check
)
139 if (env
->mem_log_stores
[slot
].width
!= check
) {
140 HEX_DEBUG_LOG("ERROR: %d != %d\n",
141 env
->mem_log_stores
[slot
].width
, check
);
142 g_assert_not_reached();
146 void HELPER(commit_store
)(CPUHexagonState
*env
, int slot_num
)
148 switch (env
->mem_log_stores
[slot_num
].width
) {
150 put_user_u8(env
->mem_log_stores
[slot_num
].data32
,
151 env
->mem_log_stores
[slot_num
].va
);
154 put_user_u16(env
->mem_log_stores
[slot_num
].data32
,
155 env
->mem_log_stores
[slot_num
].va
);
158 put_user_u32(env
->mem_log_stores
[slot_num
].data32
,
159 env
->mem_log_stores
[slot_num
].va
);
162 put_user_u64(env
->mem_log_stores
[slot_num
].data64
,
163 env
->mem_log_stores
[slot_num
].va
);
166 g_assert_not_reached();
170 static void print_store(CPUHexagonState
*env
, int slot
)
172 if (!(env
->slot_cancelled
& (1 << slot
))) {
173 uint8_t width
= env
->mem_log_stores
[slot
].width
;
175 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xff;
176 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx
"] = %" PRId32
177 " (0x%02" PRIx32
")\n",
178 env
->mem_log_stores
[slot
].va
, data
, data
);
179 } else if (width
== 2) {
180 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xffff;
181 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx
"] = %" PRId32
182 " (0x%04" PRIx32
")\n",
183 env
->mem_log_stores
[slot
].va
, data
, data
);
184 } else if (width
== 4) {
185 uint32_t data
= env
->mem_log_stores
[slot
].data32
;
186 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx
"] = %" PRId32
187 " (0x%08" PRIx32
")\n",
188 env
->mem_log_stores
[slot
].va
, data
, data
);
189 } else if (width
== 8) {
190 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx
"] = %" PRId64
191 " (0x%016" PRIx64
")\n",
192 env
->mem_log_stores
[slot
].va
,
193 env
->mem_log_stores
[slot
].data64
,
194 env
->mem_log_stores
[slot
].data64
);
196 HEX_DEBUG_LOG("\tBad store width %d\n", width
);
197 g_assert_not_reached();
202 /* This function is a handy place to set a breakpoint */
203 void HELPER(debug_commit_end
)(CPUHexagonState
*env
, int has_st0
, int has_st1
)
205 bool reg_printed
= false;
206 bool pred_printed
= false;
209 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx
"\n",
211 HEX_DEBUG_LOG("slot_cancelled = %d\n", env
->slot_cancelled
);
213 for (i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
214 if (env
->reg_written
[i
]) {
216 HEX_DEBUG_LOG("Regs written\n");
219 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")\n",
220 i
, env
->new_value
[i
], env
->new_value
[i
]);
224 for (i
= 0; i
< NUM_PREGS
; i
++) {
225 if (env
->pred_written
& (1 << i
)) {
227 HEX_DEBUG_LOG("Predicates written\n");
230 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx
"\n",
231 i
, env
->new_pred_value
[i
]);
235 if (has_st0
|| has_st1
) {
236 HEX_DEBUG_LOG("Stores\n");
245 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx
"\n", env
->next_PC
);
246 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
247 ", insn = " TARGET_FMT_lx
249 env
->gpr
[HEX_REG_QEMU_PKT_CNT
],
250 env
->gpr
[HEX_REG_QEMU_INSN_CNT
]);
254 int32_t HELPER(fcircadd
)(int32_t RxV
, int32_t offset
, int32_t M
, int32_t CS
)
256 int32_t K_const
= sextract32(M
, 24, 4);
257 int32_t length
= sextract32(M
, 0, 17);
258 uint32_t new_ptr
= RxV
+ offset
;
262 if (K_const
== 0 && length
>= 4) {
264 end_addr
= start_addr
+ length
;
267 * Versions v3 and earlier used the K value to specify a power-of-2 size
268 * 2^(K+2) that is greater than the buffer length
270 int32_t mask
= (1 << (K_const
+ 2)) - 1;
271 start_addr
= RxV
& (~mask
);
272 end_addr
= start_addr
| length
;
275 if (new_ptr
>= end_addr
) {
277 } else if (new_ptr
< start_addr
) {
284 uint32_t HELPER(fbrev
)(uint32_t addr
)
287 * Bit reverse the low 16 bits of the address
289 return deposit32(addr
, 0, 16, revbit16(addr
));
292 static float32
build_float32(uint8_t sign
, uint32_t exp
, uint32_t mant
)
296 ((exp
& 0xff) << SF_MANTBITS
) |
297 (mant
& ((1 << SF_MANTBITS
) - 1)));
301 * sfrecipa, sfinvsqrta have two 32-bit results
302 * r0,p0=sfrecipa(r1,r2)
303 * r0,p0=sfinvsqrta(r1)
305 * Since helpers can only return a single value, we pack the two results
306 * into a 64-bit value.
308 uint64_t HELPER(sfrecipa
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
317 arch_fpop_start(env
);
318 if (arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
)) {
320 idx
= (RtV
>> 16) & 0x7f;
321 mant
= (recip_lookup_table
[idx
] << 15) | 1;
322 exp
= SF_BIAS
- (float32_getexp(RtV
) - SF_BIAS
) - 1;
323 RdV
= build_float32(extract32(RtV
, 31, 1), exp
, mant
);
326 return ((uint64_t)RdV
<< 32) | PeV
;
329 uint64_t HELPER(sfinvsqrta
)(CPUHexagonState
*env
, float32 RsV
)
338 arch_fpop_start(env
);
339 if (arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
)) {
341 idx
= (RsV
>> 17) & 0x7f;
342 mant
= (invsqrt_lookup_table
[idx
] << 15);
343 exp
= SF_BIAS
- ((float32_getexp(RsV
) - SF_BIAS
) >> 1) - 1;
344 RdV
= build_float32(extract32(RsV
, 31, 1), exp
, mant
);
347 return ((uint64_t)RdV
<< 32) | PeV
;
350 int64_t HELPER(vacsh_val
)(CPUHexagonState
*env
,
351 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
353 for (int i
= 0; i
< 4; i
++) {
354 int xv
= sextract64(RxxV
, i
* 16, 16);
355 int sv
= sextract64(RssV
, i
* 16, 16);
356 int tv
= sextract64(RttV
, i
* 16, 16);
360 max
= xv
> sv
? xv
: sv
;
361 /* Note that fSATH can set the OVF bit in usr */
362 RxxV
= deposit64(RxxV
, i
* 16, 16, fSATH(max
));
367 int32_t HELPER(vacsh_pred
)(CPUHexagonState
*env
,
368 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
371 for (int i
= 0; i
< 4; i
++) {
372 int xv
= sextract64(RxxV
, i
* 16, 16);
373 int sv
= sextract64(RssV
, i
* 16, 16);
374 int tv
= sextract64(RttV
, i
* 16, 16);
377 PeV
= deposit32(PeV
, i
* 2, 1, (xv
> sv
));
378 PeV
= deposit32(PeV
, i
* 2 + 1, 1, (xv
> sv
));
385 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
387 * If the load is in slot 0 and there is a store in slot1 (that
388 * wasn't cancelled), we have to do the store first.
390 static void check_noshuf(CPUHexagonState
*env
, uint32_t slot
)
392 if (slot
== 0 && env
->pkt_has_store_s1
&&
393 ((env
->slot_cancelled
& (1 << 1)) == 0)) {
394 HELPER(commit_store
)(env
, 1);
398 static uint8_t mem_load1(CPUHexagonState
*env
, uint32_t slot
,
402 check_noshuf(env
, slot
);
403 get_user_u8(retval
, vaddr
);
407 static uint16_t mem_load2(CPUHexagonState
*env
, uint32_t slot
,
411 check_noshuf(env
, slot
);
412 get_user_u16(retval
, vaddr
);
416 static uint32_t mem_load4(CPUHexagonState
*env
, uint32_t slot
,
420 check_noshuf(env
, slot
);
421 get_user_u32(retval
, vaddr
);
425 static uint64_t mem_load8(CPUHexagonState
*env
, uint32_t slot
,
429 check_noshuf(env
, slot
);
430 get_user_u64(retval
, vaddr
);
435 float64
HELPER(conv_sf2df
)(CPUHexagonState
*env
, float32 RsV
)
438 arch_fpop_start(env
);
439 out_f64
= float32_to_float64(RsV
, &env
->fp_status
);
444 float32
HELPER(conv_df2sf
)(CPUHexagonState
*env
, float64 RssV
)
447 arch_fpop_start(env
);
448 out_f32
= float64_to_float32(RssV
, &env
->fp_status
);
453 float32
HELPER(conv_uw2sf
)(CPUHexagonState
*env
, int32_t RsV
)
456 arch_fpop_start(env
);
457 RdV
= uint32_to_float32(RsV
, &env
->fp_status
);
462 float64
HELPER(conv_uw2df
)(CPUHexagonState
*env
, int32_t RsV
)
465 arch_fpop_start(env
);
466 RddV
= uint32_to_float64(RsV
, &env
->fp_status
);
471 float32
HELPER(conv_w2sf
)(CPUHexagonState
*env
, int32_t RsV
)
474 arch_fpop_start(env
);
475 RdV
= int32_to_float32(RsV
, &env
->fp_status
);
480 float64
HELPER(conv_w2df
)(CPUHexagonState
*env
, int32_t RsV
)
483 arch_fpop_start(env
);
484 RddV
= int32_to_float64(RsV
, &env
->fp_status
);
489 float32
HELPER(conv_ud2sf
)(CPUHexagonState
*env
, int64_t RssV
)
492 arch_fpop_start(env
);
493 RdV
= uint64_to_float32(RssV
, &env
->fp_status
);
498 float64
HELPER(conv_ud2df
)(CPUHexagonState
*env
, int64_t RssV
)
501 arch_fpop_start(env
);
502 RddV
= uint64_to_float64(RssV
, &env
->fp_status
);
507 float32
HELPER(conv_d2sf
)(CPUHexagonState
*env
, int64_t RssV
)
510 arch_fpop_start(env
);
511 RdV
= int64_to_float32(RssV
, &env
->fp_status
);
516 float64
HELPER(conv_d2df
)(CPUHexagonState
*env
, int64_t RssV
)
519 arch_fpop_start(env
);
520 RddV
= int64_to_float64(RssV
, &env
->fp_status
);
525 uint32_t HELPER(conv_sf2uw
)(CPUHexagonState
*env
, float32 RsV
)
528 arch_fpop_start(env
);
529 /* Hexagon checks the sign before rounding */
530 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
531 float_raise(float_flag_invalid
, &env
->fp_status
);
534 RdV
= float32_to_uint32(RsV
, &env
->fp_status
);
540 int32_t HELPER(conv_sf2w
)(CPUHexagonState
*env
, float32 RsV
)
543 arch_fpop_start(env
);
544 /* Hexagon returns -1 for NaN */
545 if (float32_is_any_nan(RsV
)) {
546 float_raise(float_flag_invalid
, &env
->fp_status
);
549 RdV
= float32_to_int32(RsV
, &env
->fp_status
);
555 uint64_t HELPER(conv_sf2ud
)(CPUHexagonState
*env
, float32 RsV
)
558 arch_fpop_start(env
);
559 /* Hexagon checks the sign before rounding */
560 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
561 float_raise(float_flag_invalid
, &env
->fp_status
);
564 RddV
= float32_to_uint64(RsV
, &env
->fp_status
);
570 int64_t HELPER(conv_sf2d
)(CPUHexagonState
*env
, float32 RsV
)
573 arch_fpop_start(env
);
574 /* Hexagon returns -1 for NaN */
575 if (float32_is_any_nan(RsV
)) {
576 float_raise(float_flag_invalid
, &env
->fp_status
);
579 RddV
= float32_to_int64(RsV
, &env
->fp_status
);
585 uint32_t HELPER(conv_df2uw
)(CPUHexagonState
*env
, float64 RssV
)
588 arch_fpop_start(env
);
589 /* Hexagon checks the sign before rounding */
590 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
591 float_raise(float_flag_invalid
, &env
->fp_status
);
594 RdV
= float64_to_uint32(RssV
, &env
->fp_status
);
600 int32_t HELPER(conv_df2w
)(CPUHexagonState
*env
, float64 RssV
)
603 arch_fpop_start(env
);
604 /* Hexagon returns -1 for NaN */
605 if (float64_is_any_nan(RssV
)) {
606 float_raise(float_flag_invalid
, &env
->fp_status
);
609 RdV
= float64_to_int32(RssV
, &env
->fp_status
);
615 uint64_t HELPER(conv_df2ud
)(CPUHexagonState
*env
, float64 RssV
)
618 arch_fpop_start(env
);
619 /* Hexagon checks the sign before rounding */
620 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
621 float_raise(float_flag_invalid
, &env
->fp_status
);
624 RddV
= float64_to_uint64(RssV
, &env
->fp_status
);
630 int64_t HELPER(conv_df2d
)(CPUHexagonState
*env
, float64 RssV
)
633 arch_fpop_start(env
);
634 /* Hexagon returns -1 for NaN */
635 if (float64_is_any_nan(RssV
)) {
636 float_raise(float_flag_invalid
, &env
->fp_status
);
639 RddV
= float64_to_int64(RssV
, &env
->fp_status
);
645 uint32_t HELPER(conv_sf2uw_chop
)(CPUHexagonState
*env
, float32 RsV
)
648 arch_fpop_start(env
);
649 /* Hexagon checks the sign before rounding */
650 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
651 float_raise(float_flag_invalid
, &env
->fp_status
);
654 RdV
= float32_to_uint32_round_to_zero(RsV
, &env
->fp_status
);
660 int32_t HELPER(conv_sf2w_chop
)(CPUHexagonState
*env
, float32 RsV
)
663 arch_fpop_start(env
);
664 /* Hexagon returns -1 for NaN */
665 if (float32_is_any_nan(RsV
)) {
666 float_raise(float_flag_invalid
, &env
->fp_status
);
669 RdV
= float32_to_int32_round_to_zero(RsV
, &env
->fp_status
);
675 uint64_t HELPER(conv_sf2ud_chop
)(CPUHexagonState
*env
, float32 RsV
)
678 arch_fpop_start(env
);
679 /* Hexagon checks the sign before rounding */
680 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
681 float_raise(float_flag_invalid
, &env
->fp_status
);
684 RddV
= float32_to_uint64_round_to_zero(RsV
, &env
->fp_status
);
690 int64_t HELPER(conv_sf2d_chop
)(CPUHexagonState
*env
, float32 RsV
)
693 arch_fpop_start(env
);
694 /* Hexagon returns -1 for NaN */
695 if (float32_is_any_nan(RsV
)) {
696 float_raise(float_flag_invalid
, &env
->fp_status
);
699 RddV
= float32_to_int64_round_to_zero(RsV
, &env
->fp_status
);
705 uint32_t HELPER(conv_df2uw_chop
)(CPUHexagonState
*env
, float64 RssV
)
708 arch_fpop_start(env
);
709 /* Hexagon checks the sign before rounding */
710 if (float64_is_neg(RssV
) && !float32_is_any_nan(RssV
)) {
711 float_raise(float_flag_invalid
, &env
->fp_status
);
714 RdV
= float64_to_uint32_round_to_zero(RssV
, &env
->fp_status
);
720 int32_t HELPER(conv_df2w_chop
)(CPUHexagonState
*env
, float64 RssV
)
723 arch_fpop_start(env
);
724 /* Hexagon returns -1 for NaN */
725 if (float64_is_any_nan(RssV
)) {
726 float_raise(float_flag_invalid
, &env
->fp_status
);
729 RdV
= float64_to_int32_round_to_zero(RssV
, &env
->fp_status
);
735 uint64_t HELPER(conv_df2ud_chop
)(CPUHexagonState
*env
, float64 RssV
)
738 arch_fpop_start(env
);
739 /* Hexagon checks the sign before rounding */
740 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
741 float_raise(float_flag_invalid
, &env
->fp_status
);
744 RddV
= float64_to_uint64_round_to_zero(RssV
, &env
->fp_status
);
750 int64_t HELPER(conv_df2d_chop
)(CPUHexagonState
*env
, float64 RssV
)
753 arch_fpop_start(env
);
754 /* Hexagon returns -1 for NaN */
755 if (float64_is_any_nan(RssV
)) {
756 float_raise(float_flag_invalid
, &env
->fp_status
);
759 RddV
= float64_to_int64_round_to_zero(RssV
, &env
->fp_status
);
765 float32
HELPER(sfadd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
768 arch_fpop_start(env
);
769 RdV
= float32_add(RsV
, RtV
, &env
->fp_status
);
774 float32
HELPER(sfsub
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
777 arch_fpop_start(env
);
778 RdV
= float32_sub(RsV
, RtV
, &env
->fp_status
);
783 int32_t HELPER(sfcmpeq
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
786 arch_fpop_start(env
);
787 PdV
= f8BITSOF(float32_eq_quiet(RsV
, RtV
, &env
->fp_status
));
792 int32_t HELPER(sfcmpgt
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
796 arch_fpop_start(env
);
797 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
798 PdV
= f8BITSOF(cmp
== float_relation_greater
);
803 int32_t HELPER(sfcmpge
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
807 arch_fpop_start(env
);
808 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
809 PdV
= f8BITSOF(cmp
== float_relation_greater
||
810 cmp
== float_relation_equal
);
815 int32_t HELPER(sfcmpuo
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
818 arch_fpop_start(env
);
819 PdV
= f8BITSOF(float32_is_any_nan(RsV
) ||
820 float32_is_any_nan(RtV
));
825 float32
HELPER(sfmax
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
828 arch_fpop_start(env
);
829 RdV
= float32_maxnum(RsV
, RtV
, &env
->fp_status
);
834 float32
HELPER(sfmin
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
837 arch_fpop_start(env
);
838 RdV
= float32_minnum(RsV
, RtV
, &env
->fp_status
);
843 int32_t HELPER(sfclass
)(CPUHexagonState
*env
, float32 RsV
, int32_t uiV
)
846 arch_fpop_start(env
);
847 if (fGETBIT(0, uiV
) && float32_is_zero(RsV
)) {
850 if (fGETBIT(1, uiV
) && float32_is_normal(RsV
)) {
853 if (fGETBIT(2, uiV
) && float32_is_denormal(RsV
)) {
856 if (fGETBIT(3, uiV
) && float32_is_infinity(RsV
)) {
859 if (fGETBIT(4, uiV
) && float32_is_any_nan(RsV
)) {
862 set_float_exception_flags(0, &env
->fp_status
);
867 float32
HELPER(sffixupn
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
871 arch_fpop_start(env
);
872 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
878 float32
HELPER(sffixupd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
882 arch_fpop_start(env
);
883 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
889 float32
HELPER(sffixupr
)(CPUHexagonState
*env
, float32 RsV
)
893 arch_fpop_start(env
);
894 arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
);
900 float64
HELPER(dfadd
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
903 arch_fpop_start(env
);
904 RddV
= float64_add(RssV
, RttV
, &env
->fp_status
);
909 float64
HELPER(dfsub
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
912 arch_fpop_start(env
);
913 RddV
= float64_sub(RssV
, RttV
, &env
->fp_status
);
918 float64
HELPER(dfmax
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
921 arch_fpop_start(env
);
922 RddV
= float64_maxnum(RssV
, RttV
, &env
->fp_status
);
923 if (float64_is_any_nan(RssV
) || float64_is_any_nan(RttV
)) {
924 float_raise(float_flag_invalid
, &env
->fp_status
);
930 float64
HELPER(dfmin
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
933 arch_fpop_start(env
);
934 RddV
= float64_minnum(RssV
, RttV
, &env
->fp_status
);
935 if (float64_is_any_nan(RssV
) || float64_is_any_nan(RttV
)) {
936 float_raise(float_flag_invalid
, &env
->fp_status
);
942 int32_t HELPER(dfcmpeq
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
945 arch_fpop_start(env
);
946 PdV
= f8BITSOF(float64_eq_quiet(RssV
, RttV
, &env
->fp_status
));
951 int32_t HELPER(dfcmpgt
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
955 arch_fpop_start(env
);
956 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
957 PdV
= f8BITSOF(cmp
== float_relation_greater
);
962 int32_t HELPER(dfcmpge
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
966 arch_fpop_start(env
);
967 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
968 PdV
= f8BITSOF(cmp
== float_relation_greater
||
969 cmp
== float_relation_equal
);
974 int32_t HELPER(dfcmpuo
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
977 arch_fpop_start(env
);
978 PdV
= f8BITSOF(float64_is_any_nan(RssV
) ||
979 float64_is_any_nan(RttV
));
984 int32_t HELPER(dfclass
)(CPUHexagonState
*env
, float64 RssV
, int32_t uiV
)
987 arch_fpop_start(env
);
988 if (fGETBIT(0, uiV
) && float64_is_zero(RssV
)) {
991 if (fGETBIT(1, uiV
) && float64_is_normal(RssV
)) {
994 if (fGETBIT(2, uiV
) && float64_is_denormal(RssV
)) {
997 if (fGETBIT(3, uiV
) && float64_is_infinity(RssV
)) {
1000 if (fGETBIT(4, uiV
) && float64_is_any_nan(RssV
)) {
1003 set_float_exception_flags(0, &env
->fp_status
);
1008 float32
HELPER(sfmpy
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
1011 arch_fpop_start(env
);
1012 RdV
= internal_mpyf(RsV
, RtV
, &env
->fp_status
);
1017 float32
HELPER(sffma
)(CPUHexagonState
*env
, float32 RxV
,
1018 float32 RsV
, float32 RtV
)
1020 arch_fpop_start(env
);
1021 RxV
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1026 static bool is_zero_prod(float32 a
, float32 b
)
1028 return ((float32_is_zero(a
) && is_finite(b
)) ||
1029 (float32_is_zero(b
) && is_finite(a
)));
1032 static float32
check_nan(float32 dst
, float32 x
, float_status
*fp_status
)
1035 if (float32_is_any_nan(x
)) {
1036 if (extract32(x
, 22, 1) == 0) {
1037 float_raise(float_flag_invalid
, fp_status
);
1039 ret
= make_float32(0xffffffff); /* nan */
1044 float32
HELPER(sffma_sc
)(CPUHexagonState
*env
, float32 RxV
,
1045 float32 RsV
, float32 RtV
, float32 PuV
)
1048 arch_fpop_start(env
);
1049 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1050 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1051 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1052 tmp
= internal_fmafx(RsV
, RtV
, RxV
, fSXTN(8, 64, PuV
), &env
->fp_status
);
1053 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1060 float32
HELPER(sffms
)(CPUHexagonState
*env
, float32 RxV
,
1061 float32 RsV
, float32 RtV
)
1064 arch_fpop_start(env
);
1065 neg_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1066 RxV
= internal_fmafx(neg_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1071 static bool is_inf_prod(int32_t a
, int32_t b
)
1073 return (float32_is_infinity(a
) && float32_is_infinity(b
)) ||
1074 (float32_is_infinity(a
) && is_finite(b
) && !float32_is_zero(b
)) ||
1075 (float32_is_infinity(b
) && is_finite(a
) && !float32_is_zero(a
));
1078 float32
HELPER(sffma_lib
)(CPUHexagonState
*env
, float32 RxV
,
1079 float32 RsV
, float32 RtV
)
1085 arch_fpop_start(env
);
1086 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1087 infminusinf
= float32_is_infinity(RxV
) &&
1088 is_inf_prod(RsV
, RtV
) &&
1089 (fGETBIT(31, RsV
^ RxV
^ RtV
) != 0);
1090 infinp
= float32_is_infinity(RxV
) ||
1091 float32_is_infinity(RtV
) ||
1092 float32_is_infinity(RsV
);
1093 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1094 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1095 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1096 tmp
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1097 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1100 set_float_exception_flags(0, &env
->fp_status
);
1101 if (float32_is_infinity(RxV
) && !infinp
) {
1111 float32
HELPER(sffms_lib
)(CPUHexagonState
*env
, float32 RxV
,
1112 float32 RsV
, float32 RtV
)
1118 arch_fpop_start(env
);
1119 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1120 infminusinf
= float32_is_infinity(RxV
) &&
1121 is_inf_prod(RsV
, RtV
) &&
1122 (fGETBIT(31, RsV
^ RxV
^ RtV
) == 0);
1123 infinp
= float32_is_infinity(RxV
) ||
1124 float32_is_infinity(RtV
) ||
1125 float32_is_infinity(RsV
);
1126 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1127 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1128 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1129 float32 minus_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1130 tmp
= internal_fmafx(minus_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1131 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1134 set_float_exception_flags(0, &env
->fp_status
);
1135 if (float32_is_infinity(RxV
) && !infinp
) {
1145 float64
HELPER(dfmpyfix
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1148 arch_fpop_start(env
);
1149 if (float64_is_denormal(RssV
) &&
1150 (float64_getexp(RttV
) >= 512) &&
1151 float64_is_normal(RttV
)) {
1152 RddV
= float64_mul(RssV
, make_float64(0x4330000000000000),
1154 } else if (float64_is_denormal(RttV
) &&
1155 (float64_getexp(RssV
) >= 512) &&
1156 float64_is_normal(RssV
)) {
1157 RddV
= float64_mul(RssV
, make_float64(0x3cb0000000000000),
1166 float64
HELPER(dfmpyhh
)(CPUHexagonState
*env
, float64 RxxV
,
1167 float64 RssV
, float64 RttV
)
1169 arch_fpop_start(env
);
1170 RxxV
= internal_mpyhh(RssV
, RttV
, RxxV
, &env
->fp_status
);
1175 static void cancel_slot(CPUHexagonState
*env
, uint32_t slot
)
1177 HEX_DEBUG_LOG("Slot %d cancelled\n", slot
);
1178 env
->slot_cancelled
|= (1 << slot
);
1181 /* These macros can be referenced in the generated helper functions */
1182 #define warn(...) /* Nothing */
1183 #define fatal(...) g_assert_not_reached();
1185 #define BOGUS_HELPER(tag) \
1186 printf("ERROR: bogus helper: " #tag "\n")
1188 #include "helper_funcs_generated.c.inc"