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/exec-all.h"
21 #include "exec/cpu_ldst.h"
22 #include "exec/helper-proto.h"
23 #include "fpu/softfloat.h"
28 #include "hex_arch_types.h"
32 #define SF_MANTBITS 23
34 /* Exceptions processing helpers */
35 static void QEMU_NORETURN
do_raise_exception_err(CPUHexagonState
*env
,
39 CPUState
*cs
= env_cpu(env
);
40 qemu_log_mask(CPU_LOG_INT
, "%s: %d\n", __func__
, exception
);
41 cs
->exception_index
= exception
;
42 cpu_loop_exit_restore(cs
, pc
);
45 void QEMU_NORETURN
HELPER(raise_exception
)(CPUHexagonState
*env
, uint32_t excp
)
47 do_raise_exception_err(env
, excp
, 0);
50 static void log_reg_write(CPUHexagonState
*env
, int rnum
,
51 target_ulong val
, uint32_t slot
)
53 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")",
55 if (val
== env
->gpr
[rnum
]) {
56 HEX_DEBUG_LOG(" NO CHANGE");
60 env
->new_value
[rnum
] = val
;
62 /* Do this so HELPER(debug_commit_end) will know */
63 env
->reg_written
[rnum
] = 1;
67 static void log_pred_write(CPUHexagonState
*env
, int pnum
, target_ulong val
)
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 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 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 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;
122 /* Handy place to set a breakpoint */
123 void HELPER(debug_start_packet
)(CPUHexagonState
*env
)
125 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx
"\n",
126 env
->gpr
[HEX_REG_PC
]);
128 for (int i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
129 env
->reg_written
[i
] = 0;
133 /* Checks for bookkeeping errors between disassembly context and runtime */
134 void HELPER(debug_check_store_width
)(CPUHexagonState
*env
, int slot
, int check
)
136 if (env
->mem_log_stores
[slot
].width
!= check
) {
137 HEX_DEBUG_LOG("ERROR: %d != %d\n",
138 env
->mem_log_stores
[slot
].width
, check
);
139 g_assert_not_reached();
143 void HELPER(commit_store
)(CPUHexagonState
*env
, int slot_num
)
145 uintptr_t ra
= GETPC();
146 uint8_t width
= env
->mem_log_stores
[slot_num
].width
;
147 target_ulong va
= env
->mem_log_stores
[slot_num
].va
;
151 cpu_stb_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
154 cpu_stw_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
157 cpu_stl_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
160 cpu_stq_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data64
, ra
);
163 g_assert_not_reached();
167 static void print_store(CPUHexagonState
*env
, int slot
)
169 if (!(env
->slot_cancelled
& (1 << slot
))) {
170 uint8_t width
= env
->mem_log_stores
[slot
].width
;
172 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xff;
173 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx
"] = %" PRId32
174 " (0x%02" PRIx32
")\n",
175 env
->mem_log_stores
[slot
].va
, data
, data
);
176 } else if (width
== 2) {
177 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xffff;
178 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx
"] = %" PRId32
179 " (0x%04" PRIx32
")\n",
180 env
->mem_log_stores
[slot
].va
, data
, data
);
181 } else if (width
== 4) {
182 uint32_t data
= env
->mem_log_stores
[slot
].data32
;
183 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx
"] = %" PRId32
184 " (0x%08" PRIx32
")\n",
185 env
->mem_log_stores
[slot
].va
, data
, data
);
186 } else if (width
== 8) {
187 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx
"] = %" PRId64
188 " (0x%016" PRIx64
")\n",
189 env
->mem_log_stores
[slot
].va
,
190 env
->mem_log_stores
[slot
].data64
,
191 env
->mem_log_stores
[slot
].data64
);
193 HEX_DEBUG_LOG("\tBad store width %d\n", width
);
194 g_assert_not_reached();
199 /* This function is a handy place to set a breakpoint */
200 void HELPER(debug_commit_end
)(CPUHexagonState
*env
, int has_st0
, int has_st1
)
202 bool reg_printed
= false;
203 bool pred_printed
= false;
206 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx
"\n",
208 HEX_DEBUG_LOG("slot_cancelled = %d\n", env
->slot_cancelled
);
210 for (i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
211 if (env
->reg_written
[i
]) {
213 HEX_DEBUG_LOG("Regs written\n");
216 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")\n",
217 i
, env
->new_value
[i
], env
->new_value
[i
]);
221 for (i
= 0; i
< NUM_PREGS
; i
++) {
222 if (env
->pred_written
& (1 << i
)) {
224 HEX_DEBUG_LOG("Predicates written\n");
227 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx
"\n",
228 i
, env
->new_pred_value
[i
]);
232 if (has_st0
|| has_st1
) {
233 HEX_DEBUG_LOG("Stores\n");
242 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx
"\n", env
->next_PC
);
243 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
244 ", insn = " TARGET_FMT_lx
246 env
->gpr
[HEX_REG_QEMU_PKT_CNT
],
247 env
->gpr
[HEX_REG_QEMU_INSN_CNT
]);
251 int32_t HELPER(fcircadd
)(int32_t RxV
, int32_t offset
, int32_t M
, int32_t CS
)
253 int32_t K_const
= sextract32(M
, 24, 4);
254 int32_t length
= sextract32(M
, 0, 17);
255 uint32_t new_ptr
= RxV
+ offset
;
259 if (K_const
== 0 && length
>= 4) {
261 end_addr
= start_addr
+ length
;
264 * Versions v3 and earlier used the K value to specify a power-of-2 size
265 * 2^(K+2) that is greater than the buffer length
267 int32_t mask
= (1 << (K_const
+ 2)) - 1;
268 start_addr
= RxV
& (~mask
);
269 end_addr
= start_addr
| length
;
272 if (new_ptr
>= end_addr
) {
274 } else if (new_ptr
< start_addr
) {
281 uint32_t HELPER(fbrev
)(uint32_t addr
)
284 * Bit reverse the low 16 bits of the address
286 return deposit32(addr
, 0, 16, revbit16(addr
));
289 static float32
build_float32(uint8_t sign
, uint32_t exp
, uint32_t mant
)
293 ((exp
& 0xff) << SF_MANTBITS
) |
294 (mant
& ((1 << SF_MANTBITS
) - 1)));
298 * sfrecipa, sfinvsqrta have two 32-bit results
299 * r0,p0=sfrecipa(r1,r2)
300 * r0,p0=sfinvsqrta(r1)
302 * Since helpers can only return a single value, we pack the two results
303 * into a 64-bit value.
305 uint64_t HELPER(sfrecipa
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
314 arch_fpop_start(env
);
315 if (arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
)) {
317 idx
= (RtV
>> 16) & 0x7f;
318 mant
= (recip_lookup_table
[idx
] << 15) | 1;
319 exp
= SF_BIAS
- (float32_getexp(RtV
) - SF_BIAS
) - 1;
320 RdV
= build_float32(extract32(RtV
, 31, 1), exp
, mant
);
323 return ((uint64_t)RdV
<< 32) | PeV
;
326 uint64_t HELPER(sfinvsqrta
)(CPUHexagonState
*env
, float32 RsV
)
335 arch_fpop_start(env
);
336 if (arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
)) {
338 idx
= (RsV
>> 17) & 0x7f;
339 mant
= (invsqrt_lookup_table
[idx
] << 15);
340 exp
= SF_BIAS
- ((float32_getexp(RsV
) - SF_BIAS
) >> 1) - 1;
341 RdV
= build_float32(extract32(RsV
, 31, 1), exp
, mant
);
344 return ((uint64_t)RdV
<< 32) | PeV
;
347 int64_t HELPER(vacsh_val
)(CPUHexagonState
*env
,
348 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
350 for (int i
= 0; i
< 4; i
++) {
351 int xv
= sextract64(RxxV
, i
* 16, 16);
352 int sv
= sextract64(RssV
, i
* 16, 16);
353 int tv
= sextract64(RttV
, i
* 16, 16);
357 max
= xv
> sv
? xv
: sv
;
358 /* Note that fSATH can set the OVF bit in usr */
359 RxxV
= deposit64(RxxV
, i
* 16, 16, fSATH(max
));
364 int32_t HELPER(vacsh_pred
)(CPUHexagonState
*env
,
365 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
368 for (int i
= 0; i
< 4; i
++) {
369 int xv
= sextract64(RxxV
, i
* 16, 16);
370 int sv
= sextract64(RssV
, i
* 16, 16);
371 int tv
= sextract64(RttV
, i
* 16, 16);
374 PeV
= deposit32(PeV
, i
* 2, 1, (xv
> sv
));
375 PeV
= deposit32(PeV
, i
* 2 + 1, 1, (xv
> sv
));
382 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
384 * If the load is in slot 0 and there is a store in slot1 (that
385 * wasn't cancelled), we have to do the store first.
387 static void check_noshuf(CPUHexagonState
*env
, uint32_t slot
)
389 if (slot
== 0 && env
->pkt_has_store_s1
&&
390 ((env
->slot_cancelled
& (1 << 1)) == 0)) {
391 HELPER(commit_store
)(env
, 1);
395 static uint8_t mem_load1(CPUHexagonState
*env
, uint32_t slot
,
398 uintptr_t ra
= GETPC();
399 check_noshuf(env
, slot
);
400 return cpu_ldub_data_ra(env
, vaddr
, ra
);
403 static uint16_t mem_load2(CPUHexagonState
*env
, uint32_t slot
,
406 uintptr_t ra
= GETPC();
407 check_noshuf(env
, slot
);
408 return cpu_lduw_data_ra(env
, vaddr
, ra
);
411 static uint32_t mem_load4(CPUHexagonState
*env
, uint32_t slot
,
414 uintptr_t ra
= GETPC();
415 check_noshuf(env
, slot
);
416 return cpu_ldl_data_ra(env
, vaddr
, ra
);
419 static uint64_t mem_load8(CPUHexagonState
*env
, uint32_t slot
,
422 uintptr_t ra
= GETPC();
423 check_noshuf(env
, slot
);
424 return cpu_ldq_data_ra(env
, vaddr
, ra
);
428 float64
HELPER(conv_sf2df
)(CPUHexagonState
*env
, float32 RsV
)
431 arch_fpop_start(env
);
432 out_f64
= float32_to_float64(RsV
, &env
->fp_status
);
437 float32
HELPER(conv_df2sf
)(CPUHexagonState
*env
, float64 RssV
)
440 arch_fpop_start(env
);
441 out_f32
= float64_to_float32(RssV
, &env
->fp_status
);
446 float32
HELPER(conv_uw2sf
)(CPUHexagonState
*env
, int32_t RsV
)
449 arch_fpop_start(env
);
450 RdV
= uint32_to_float32(RsV
, &env
->fp_status
);
455 float64
HELPER(conv_uw2df
)(CPUHexagonState
*env
, int32_t RsV
)
458 arch_fpop_start(env
);
459 RddV
= uint32_to_float64(RsV
, &env
->fp_status
);
464 float32
HELPER(conv_w2sf
)(CPUHexagonState
*env
, int32_t RsV
)
467 arch_fpop_start(env
);
468 RdV
= int32_to_float32(RsV
, &env
->fp_status
);
473 float64
HELPER(conv_w2df
)(CPUHexagonState
*env
, int32_t RsV
)
476 arch_fpop_start(env
);
477 RddV
= int32_to_float64(RsV
, &env
->fp_status
);
482 float32
HELPER(conv_ud2sf
)(CPUHexagonState
*env
, int64_t RssV
)
485 arch_fpop_start(env
);
486 RdV
= uint64_to_float32(RssV
, &env
->fp_status
);
491 float64
HELPER(conv_ud2df
)(CPUHexagonState
*env
, int64_t RssV
)
494 arch_fpop_start(env
);
495 RddV
= uint64_to_float64(RssV
, &env
->fp_status
);
500 float32
HELPER(conv_d2sf
)(CPUHexagonState
*env
, int64_t RssV
)
503 arch_fpop_start(env
);
504 RdV
= int64_to_float32(RssV
, &env
->fp_status
);
509 float64
HELPER(conv_d2df
)(CPUHexagonState
*env
, int64_t RssV
)
512 arch_fpop_start(env
);
513 RddV
= int64_to_float64(RssV
, &env
->fp_status
);
518 uint32_t HELPER(conv_sf2uw
)(CPUHexagonState
*env
, float32 RsV
)
521 arch_fpop_start(env
);
522 /* Hexagon checks the sign before rounding */
523 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
524 float_raise(float_flag_invalid
, &env
->fp_status
);
527 RdV
= float32_to_uint32(RsV
, &env
->fp_status
);
533 int32_t HELPER(conv_sf2w
)(CPUHexagonState
*env
, float32 RsV
)
536 arch_fpop_start(env
);
537 /* Hexagon returns -1 for NaN */
538 if (float32_is_any_nan(RsV
)) {
539 float_raise(float_flag_invalid
, &env
->fp_status
);
542 RdV
= float32_to_int32(RsV
, &env
->fp_status
);
548 uint64_t HELPER(conv_sf2ud
)(CPUHexagonState
*env
, float32 RsV
)
551 arch_fpop_start(env
);
552 /* Hexagon checks the sign before rounding */
553 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
554 float_raise(float_flag_invalid
, &env
->fp_status
);
557 RddV
= float32_to_uint64(RsV
, &env
->fp_status
);
563 int64_t HELPER(conv_sf2d
)(CPUHexagonState
*env
, float32 RsV
)
566 arch_fpop_start(env
);
567 /* Hexagon returns -1 for NaN */
568 if (float32_is_any_nan(RsV
)) {
569 float_raise(float_flag_invalid
, &env
->fp_status
);
572 RddV
= float32_to_int64(RsV
, &env
->fp_status
);
578 uint32_t HELPER(conv_df2uw
)(CPUHexagonState
*env
, float64 RssV
)
581 arch_fpop_start(env
);
582 /* Hexagon checks the sign before rounding */
583 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
584 float_raise(float_flag_invalid
, &env
->fp_status
);
587 RdV
= float64_to_uint32(RssV
, &env
->fp_status
);
593 int32_t HELPER(conv_df2w
)(CPUHexagonState
*env
, float64 RssV
)
596 arch_fpop_start(env
);
597 /* Hexagon returns -1 for NaN */
598 if (float64_is_any_nan(RssV
)) {
599 float_raise(float_flag_invalid
, &env
->fp_status
);
602 RdV
= float64_to_int32(RssV
, &env
->fp_status
);
608 uint64_t HELPER(conv_df2ud
)(CPUHexagonState
*env
, float64 RssV
)
611 arch_fpop_start(env
);
612 /* Hexagon checks the sign before rounding */
613 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
614 float_raise(float_flag_invalid
, &env
->fp_status
);
617 RddV
= float64_to_uint64(RssV
, &env
->fp_status
);
623 int64_t HELPER(conv_df2d
)(CPUHexagonState
*env
, float64 RssV
)
626 arch_fpop_start(env
);
627 /* Hexagon returns -1 for NaN */
628 if (float64_is_any_nan(RssV
)) {
629 float_raise(float_flag_invalid
, &env
->fp_status
);
632 RddV
= float64_to_int64(RssV
, &env
->fp_status
);
638 uint32_t HELPER(conv_sf2uw_chop
)(CPUHexagonState
*env
, float32 RsV
)
641 arch_fpop_start(env
);
642 /* Hexagon checks the sign before rounding */
643 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
644 float_raise(float_flag_invalid
, &env
->fp_status
);
647 RdV
= float32_to_uint32_round_to_zero(RsV
, &env
->fp_status
);
653 int32_t HELPER(conv_sf2w_chop
)(CPUHexagonState
*env
, float32 RsV
)
656 arch_fpop_start(env
);
657 /* Hexagon returns -1 for NaN */
658 if (float32_is_any_nan(RsV
)) {
659 float_raise(float_flag_invalid
, &env
->fp_status
);
662 RdV
= float32_to_int32_round_to_zero(RsV
, &env
->fp_status
);
668 uint64_t HELPER(conv_sf2ud_chop
)(CPUHexagonState
*env
, float32 RsV
)
671 arch_fpop_start(env
);
672 /* Hexagon checks the sign before rounding */
673 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
674 float_raise(float_flag_invalid
, &env
->fp_status
);
677 RddV
= float32_to_uint64_round_to_zero(RsV
, &env
->fp_status
);
683 int64_t HELPER(conv_sf2d_chop
)(CPUHexagonState
*env
, float32 RsV
)
686 arch_fpop_start(env
);
687 /* Hexagon returns -1 for NaN */
688 if (float32_is_any_nan(RsV
)) {
689 float_raise(float_flag_invalid
, &env
->fp_status
);
692 RddV
= float32_to_int64_round_to_zero(RsV
, &env
->fp_status
);
698 uint32_t HELPER(conv_df2uw_chop
)(CPUHexagonState
*env
, float64 RssV
)
701 arch_fpop_start(env
);
702 /* Hexagon checks the sign before rounding */
703 if (float64_is_neg(RssV
) && !float32_is_any_nan(RssV
)) {
704 float_raise(float_flag_invalid
, &env
->fp_status
);
707 RdV
= float64_to_uint32_round_to_zero(RssV
, &env
->fp_status
);
713 int32_t HELPER(conv_df2w_chop
)(CPUHexagonState
*env
, float64 RssV
)
716 arch_fpop_start(env
);
717 /* Hexagon returns -1 for NaN */
718 if (float64_is_any_nan(RssV
)) {
719 float_raise(float_flag_invalid
, &env
->fp_status
);
722 RdV
= float64_to_int32_round_to_zero(RssV
, &env
->fp_status
);
728 uint64_t HELPER(conv_df2ud_chop
)(CPUHexagonState
*env
, float64 RssV
)
731 arch_fpop_start(env
);
732 /* Hexagon checks the sign before rounding */
733 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
734 float_raise(float_flag_invalid
, &env
->fp_status
);
737 RddV
= float64_to_uint64_round_to_zero(RssV
, &env
->fp_status
);
743 int64_t HELPER(conv_df2d_chop
)(CPUHexagonState
*env
, float64 RssV
)
746 arch_fpop_start(env
);
747 /* Hexagon returns -1 for NaN */
748 if (float64_is_any_nan(RssV
)) {
749 float_raise(float_flag_invalid
, &env
->fp_status
);
752 RddV
= float64_to_int64_round_to_zero(RssV
, &env
->fp_status
);
758 float32
HELPER(sfadd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
761 arch_fpop_start(env
);
762 RdV
= float32_add(RsV
, RtV
, &env
->fp_status
);
767 float32
HELPER(sfsub
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
770 arch_fpop_start(env
);
771 RdV
= float32_sub(RsV
, RtV
, &env
->fp_status
);
776 int32_t HELPER(sfcmpeq
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
779 arch_fpop_start(env
);
780 PdV
= f8BITSOF(float32_eq_quiet(RsV
, RtV
, &env
->fp_status
));
785 int32_t HELPER(sfcmpgt
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
789 arch_fpop_start(env
);
790 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
791 PdV
= f8BITSOF(cmp
== float_relation_greater
);
796 int32_t HELPER(sfcmpge
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
800 arch_fpop_start(env
);
801 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
802 PdV
= f8BITSOF(cmp
== float_relation_greater
||
803 cmp
== float_relation_equal
);
808 int32_t HELPER(sfcmpuo
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
811 arch_fpop_start(env
);
812 PdV
= f8BITSOF(float32_is_any_nan(RsV
) ||
813 float32_is_any_nan(RtV
));
818 float32
HELPER(sfmax
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
821 arch_fpop_start(env
);
822 RdV
= float32_maxnum(RsV
, RtV
, &env
->fp_status
);
827 float32
HELPER(sfmin
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
830 arch_fpop_start(env
);
831 RdV
= float32_minnum(RsV
, RtV
, &env
->fp_status
);
836 int32_t HELPER(sfclass
)(CPUHexagonState
*env
, float32 RsV
, int32_t uiV
)
839 arch_fpop_start(env
);
840 if (fGETBIT(0, uiV
) && float32_is_zero(RsV
)) {
843 if (fGETBIT(1, uiV
) && float32_is_normal(RsV
)) {
846 if (fGETBIT(2, uiV
) && float32_is_denormal(RsV
)) {
849 if (fGETBIT(3, uiV
) && float32_is_infinity(RsV
)) {
852 if (fGETBIT(4, uiV
) && float32_is_any_nan(RsV
)) {
855 set_float_exception_flags(0, &env
->fp_status
);
860 float32
HELPER(sffixupn
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
864 arch_fpop_start(env
);
865 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
871 float32
HELPER(sffixupd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
875 arch_fpop_start(env
);
876 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
882 float32
HELPER(sffixupr
)(CPUHexagonState
*env
, float32 RsV
)
886 arch_fpop_start(env
);
887 arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
);
893 float64
HELPER(dfadd
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
896 arch_fpop_start(env
);
897 RddV
= float64_add(RssV
, RttV
, &env
->fp_status
);
902 float64
HELPER(dfsub
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
905 arch_fpop_start(env
);
906 RddV
= float64_sub(RssV
, RttV
, &env
->fp_status
);
911 float64
HELPER(dfmax
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
914 arch_fpop_start(env
);
915 RddV
= float64_maxnum(RssV
, RttV
, &env
->fp_status
);
916 if (float64_is_any_nan(RssV
) || float64_is_any_nan(RttV
)) {
917 float_raise(float_flag_invalid
, &env
->fp_status
);
923 float64
HELPER(dfmin
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
926 arch_fpop_start(env
);
927 RddV
= float64_minnum(RssV
, RttV
, &env
->fp_status
);
928 if (float64_is_any_nan(RssV
) || float64_is_any_nan(RttV
)) {
929 float_raise(float_flag_invalid
, &env
->fp_status
);
935 int32_t HELPER(dfcmpeq
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
938 arch_fpop_start(env
);
939 PdV
= f8BITSOF(float64_eq_quiet(RssV
, RttV
, &env
->fp_status
));
944 int32_t HELPER(dfcmpgt
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
948 arch_fpop_start(env
);
949 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
950 PdV
= f8BITSOF(cmp
== float_relation_greater
);
955 int32_t HELPER(dfcmpge
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
959 arch_fpop_start(env
);
960 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
961 PdV
= f8BITSOF(cmp
== float_relation_greater
||
962 cmp
== float_relation_equal
);
967 int32_t HELPER(dfcmpuo
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
970 arch_fpop_start(env
);
971 PdV
= f8BITSOF(float64_is_any_nan(RssV
) ||
972 float64_is_any_nan(RttV
));
977 int32_t HELPER(dfclass
)(CPUHexagonState
*env
, float64 RssV
, int32_t uiV
)
980 arch_fpop_start(env
);
981 if (fGETBIT(0, uiV
) && float64_is_zero(RssV
)) {
984 if (fGETBIT(1, uiV
) && float64_is_normal(RssV
)) {
987 if (fGETBIT(2, uiV
) && float64_is_denormal(RssV
)) {
990 if (fGETBIT(3, uiV
) && float64_is_infinity(RssV
)) {
993 if (fGETBIT(4, uiV
) && float64_is_any_nan(RssV
)) {
996 set_float_exception_flags(0, &env
->fp_status
);
1001 float32
HELPER(sfmpy
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
1004 arch_fpop_start(env
);
1005 RdV
= internal_mpyf(RsV
, RtV
, &env
->fp_status
);
1010 float32
HELPER(sffma
)(CPUHexagonState
*env
, float32 RxV
,
1011 float32 RsV
, float32 RtV
)
1013 arch_fpop_start(env
);
1014 RxV
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1019 static bool is_zero_prod(float32 a
, float32 b
)
1021 return ((float32_is_zero(a
) && is_finite(b
)) ||
1022 (float32_is_zero(b
) && is_finite(a
)));
1025 static float32
check_nan(float32 dst
, float32 x
, float_status
*fp_status
)
1028 if (float32_is_any_nan(x
)) {
1029 if (extract32(x
, 22, 1) == 0) {
1030 float_raise(float_flag_invalid
, fp_status
);
1032 ret
= make_float32(0xffffffff); /* nan */
1037 float32
HELPER(sffma_sc
)(CPUHexagonState
*env
, float32 RxV
,
1038 float32 RsV
, float32 RtV
, float32 PuV
)
1041 arch_fpop_start(env
);
1042 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1043 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1044 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1045 tmp
= internal_fmafx(RsV
, RtV
, RxV
, fSXTN(8, 64, PuV
), &env
->fp_status
);
1046 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1053 float32
HELPER(sffms
)(CPUHexagonState
*env
, float32 RxV
,
1054 float32 RsV
, float32 RtV
)
1057 arch_fpop_start(env
);
1058 neg_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1059 RxV
= internal_fmafx(neg_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1064 static bool is_inf_prod(int32_t a
, int32_t b
)
1066 return (float32_is_infinity(a
) && float32_is_infinity(b
)) ||
1067 (float32_is_infinity(a
) && is_finite(b
) && !float32_is_zero(b
)) ||
1068 (float32_is_infinity(b
) && is_finite(a
) && !float32_is_zero(a
));
1071 float32
HELPER(sffma_lib
)(CPUHexagonState
*env
, float32 RxV
,
1072 float32 RsV
, float32 RtV
)
1078 arch_fpop_start(env
);
1079 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1080 infminusinf
= float32_is_infinity(RxV
) &&
1081 is_inf_prod(RsV
, RtV
) &&
1082 (fGETBIT(31, RsV
^ RxV
^ RtV
) != 0);
1083 infinp
= float32_is_infinity(RxV
) ||
1084 float32_is_infinity(RtV
) ||
1085 float32_is_infinity(RsV
);
1086 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1087 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1088 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1089 tmp
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1090 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1093 set_float_exception_flags(0, &env
->fp_status
);
1094 if (float32_is_infinity(RxV
) && !infinp
) {
1104 float32
HELPER(sffms_lib
)(CPUHexagonState
*env
, float32 RxV
,
1105 float32 RsV
, float32 RtV
)
1111 arch_fpop_start(env
);
1112 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1113 infminusinf
= float32_is_infinity(RxV
) &&
1114 is_inf_prod(RsV
, RtV
) &&
1115 (fGETBIT(31, RsV
^ RxV
^ RtV
) == 0);
1116 infinp
= float32_is_infinity(RxV
) ||
1117 float32_is_infinity(RtV
) ||
1118 float32_is_infinity(RsV
);
1119 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1120 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1121 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1122 float32 minus_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1123 tmp
= internal_fmafx(minus_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1124 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1127 set_float_exception_flags(0, &env
->fp_status
);
1128 if (float32_is_infinity(RxV
) && !infinp
) {
1138 float64
HELPER(dfmpyfix
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1141 arch_fpop_start(env
);
1142 if (float64_is_denormal(RssV
) &&
1143 (float64_getexp(RttV
) >= 512) &&
1144 float64_is_normal(RttV
)) {
1145 RddV
= float64_mul(RssV
, make_float64(0x4330000000000000),
1147 } else if (float64_is_denormal(RttV
) &&
1148 (float64_getexp(RssV
) >= 512) &&
1149 float64_is_normal(RssV
)) {
1150 RddV
= float64_mul(RssV
, make_float64(0x3cb0000000000000),
1159 float64
HELPER(dfmpyhh
)(CPUHexagonState
*env
, float64 RxxV
,
1160 float64 RssV
, float64 RttV
)
1162 arch_fpop_start(env
);
1163 RxxV
= internal_mpyhh(RssV
, RttV
, RxxV
, &env
->fp_status
);
1168 static void cancel_slot(CPUHexagonState
*env
, uint32_t slot
)
1170 HEX_DEBUG_LOG("Slot %d cancelled\n", slot
);
1171 env
->slot_cancelled
|= (1 << slot
);
1174 /* These macros can be referenced in the generated helper functions */
1175 #define warn(...) /* Nothing */
1176 #define fatal(...) g_assert_not_reached();
1178 #define BOGUS_HELPER(tag) \
1179 printf("ERROR: bogus helper: " #tag "\n")
1181 #include "helper_funcs_generated.c.inc"