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"
30 #include "mmvec/mmvec.h"
31 #include "mmvec/macros.h"
34 #define SF_MANTBITS 23
36 /* Exceptions processing helpers */
37 static void QEMU_NORETURN
do_raise_exception_err(CPUHexagonState
*env
,
41 CPUState
*cs
= env_cpu(env
);
42 qemu_log_mask(CPU_LOG_INT
, "%s: %d\n", __func__
, exception
);
43 cs
->exception_index
= exception
;
44 cpu_loop_exit_restore(cs
, pc
);
47 void QEMU_NORETURN
HELPER(raise_exception
)(CPUHexagonState
*env
, uint32_t excp
)
49 do_raise_exception_err(env
, excp
, 0);
52 static void log_reg_write(CPUHexagonState
*env
, int rnum
,
53 target_ulong val
, uint32_t slot
)
55 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")",
57 if (val
== env
->gpr
[rnum
]) {
58 HEX_DEBUG_LOG(" NO CHANGE");
62 env
->new_value
[rnum
] = val
;
64 /* Do this so HELPER(debug_commit_end) will know */
65 env
->reg_written
[rnum
] = 1;
69 static void log_pred_write(CPUHexagonState
*env
, int pnum
, target_ulong val
)
71 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
72 " (0x" TARGET_FMT_lx
")\n",
75 /* Multiple writes to the same preg are and'ed together */
76 if (env
->pred_written
& (1 << pnum
)) {
77 env
->new_pred_value
[pnum
] &= val
& 0xff;
79 env
->new_pred_value
[pnum
] = val
& 0xff;
80 env
->pred_written
|= 1 << pnum
;
84 static void log_store32(CPUHexagonState
*env
, target_ulong addr
,
85 target_ulong val
, int width
, int slot
)
87 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
88 ", %" PRId32
" [0x08%" PRIx32
"])\n",
89 width
, addr
, val
, val
);
90 env
->mem_log_stores
[slot
].va
= addr
;
91 env
->mem_log_stores
[slot
].width
= width
;
92 env
->mem_log_stores
[slot
].data32
= val
;
95 static void log_store64(CPUHexagonState
*env
, target_ulong addr
,
96 int64_t val
, int width
, int slot
)
98 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
99 ", %" PRId64
" [0x016%" PRIx64
"])\n",
100 width
, addr
, val
, val
);
101 env
->mem_log_stores
[slot
].va
= addr
;
102 env
->mem_log_stores
[slot
].width
= width
;
103 env
->mem_log_stores
[slot
].data64
= val
;
106 static void write_new_pc(CPUHexagonState
*env
, target_ulong addr
)
108 HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx
")\n", addr
);
111 * If more than one branch is taken in a packet, only the first one
114 if (env
->branch_taken
) {
115 HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
116 "ignoring the second one\n");
118 fCHECK_PCALIGN(addr
);
119 env
->branch_taken
= 1;
124 /* Handy place to set a breakpoint */
125 void HELPER(debug_start_packet
)(CPUHexagonState
*env
)
127 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx
"\n",
128 env
->gpr
[HEX_REG_PC
]);
130 for (int i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
131 env
->reg_written
[i
] = 0;
135 /* Checks for bookkeeping errors between disassembly context and runtime */
136 void HELPER(debug_check_store_width
)(CPUHexagonState
*env
, int slot
, int check
)
138 if (env
->mem_log_stores
[slot
].width
!= check
) {
139 HEX_DEBUG_LOG("ERROR: %d != %d\n",
140 env
->mem_log_stores
[slot
].width
, check
);
141 g_assert_not_reached();
145 void HELPER(commit_store
)(CPUHexagonState
*env
, int slot_num
)
147 uintptr_t ra
= GETPC();
148 uint8_t width
= env
->mem_log_stores
[slot_num
].width
;
149 target_ulong va
= env
->mem_log_stores
[slot_num
].va
;
153 cpu_stb_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
156 cpu_stw_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
159 cpu_stl_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data32
, ra
);
162 cpu_stq_data_ra(env
, va
, env
->mem_log_stores
[slot_num
].data64
, ra
);
165 g_assert_not_reached();
169 void HELPER(gather_store
)(CPUHexagonState
*env
, uint32_t addr
, int slot
)
171 mem_gather_store(env
, addr
, slot
);
174 void HELPER(commit_hvx_stores
)(CPUHexagonState
*env
)
176 uintptr_t ra
= GETPC();
179 /* Normal (possibly masked) vector store */
180 for (i
= 0; i
< VSTORES_MAX
; i
++) {
181 if (env
->vstore_pending
[i
]) {
182 env
->vstore_pending
[i
] = 0;
183 target_ulong va
= env
->vstore
[i
].va
;
184 int size
= env
->vstore
[i
].size
;
185 for (int j
= 0; j
< size
; j
++) {
186 if (test_bit(j
, env
->vstore
[i
].mask
)) {
187 cpu_stb_data_ra(env
, va
+ j
, env
->vstore
[i
].data
.ub
[j
], ra
);
194 if (env
->vtcm_pending
) {
195 env
->vtcm_pending
= false;
196 if (env
->vtcm_log
.op
) {
197 /* Need to perform the scatter read/modify/write at commit time */
198 if (env
->vtcm_log
.op_size
== 2) {
199 SCATTER_OP_WRITE_TO_MEM(uint16_t);
200 } else if (env
->vtcm_log
.op_size
== 4) {
201 /* Word Scatter += */
202 SCATTER_OP_WRITE_TO_MEM(uint32_t);
204 g_assert_not_reached();
207 for (i
= 0; i
< sizeof(MMVector
); i
++) {
208 if (test_bit(i
, env
->vtcm_log
.mask
)) {
209 cpu_stb_data_ra(env
, env
->vtcm_log
.va
[i
],
210 env
->vtcm_log
.data
.ub
[i
], ra
);
211 clear_bit(i
, env
->vtcm_log
.mask
);
212 env
->vtcm_log
.data
.ub
[i
] = 0;
220 static void print_store(CPUHexagonState
*env
, int slot
)
222 if (!(env
->slot_cancelled
& (1 << slot
))) {
223 uint8_t width
= env
->mem_log_stores
[slot
].width
;
225 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xff;
226 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx
"] = %" PRId32
227 " (0x%02" PRIx32
")\n",
228 env
->mem_log_stores
[slot
].va
, data
, data
);
229 } else if (width
== 2) {
230 uint32_t data
= env
->mem_log_stores
[slot
].data32
& 0xffff;
231 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx
"] = %" PRId32
232 " (0x%04" PRIx32
")\n",
233 env
->mem_log_stores
[slot
].va
, data
, data
);
234 } else if (width
== 4) {
235 uint32_t data
= env
->mem_log_stores
[slot
].data32
;
236 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx
"] = %" PRId32
237 " (0x%08" PRIx32
")\n",
238 env
->mem_log_stores
[slot
].va
, data
, data
);
239 } else if (width
== 8) {
240 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx
"] = %" PRId64
241 " (0x%016" PRIx64
")\n",
242 env
->mem_log_stores
[slot
].va
,
243 env
->mem_log_stores
[slot
].data64
,
244 env
->mem_log_stores
[slot
].data64
);
246 HEX_DEBUG_LOG("\tBad store width %d\n", width
);
247 g_assert_not_reached();
252 /* This function is a handy place to set a breakpoint */
253 void HELPER(debug_commit_end
)(CPUHexagonState
*env
, int has_st0
, int has_st1
)
255 bool reg_printed
= false;
256 bool pred_printed
= false;
259 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx
"\n",
261 HEX_DEBUG_LOG("slot_cancelled = %d\n", env
->slot_cancelled
);
263 for (i
= 0; i
< TOTAL_PER_THREAD_REGS
; i
++) {
264 if (env
->reg_written
[i
]) {
266 HEX_DEBUG_LOG("Regs written\n");
269 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld
" (0x" TARGET_FMT_lx
")\n",
270 i
, env
->new_value
[i
], env
->new_value
[i
]);
274 for (i
= 0; i
< NUM_PREGS
; i
++) {
275 if (env
->pred_written
& (1 << i
)) {
277 HEX_DEBUG_LOG("Predicates written\n");
280 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx
"\n",
281 i
, env
->new_pred_value
[i
]);
285 if (has_st0
|| has_st1
) {
286 HEX_DEBUG_LOG("Stores\n");
295 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx
"\n", env
->next_PC
);
296 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
297 ", insn = " TARGET_FMT_lx
298 ", hvx = " TARGET_FMT_lx
"\n",
299 env
->gpr
[HEX_REG_QEMU_PKT_CNT
],
300 env
->gpr
[HEX_REG_QEMU_INSN_CNT
],
301 env
->gpr
[HEX_REG_QEMU_HVX_CNT
]);
305 int32_t HELPER(fcircadd
)(int32_t RxV
, int32_t offset
, int32_t M
, int32_t CS
)
307 int32_t K_const
= sextract32(M
, 24, 4);
308 int32_t length
= sextract32(M
, 0, 17);
309 uint32_t new_ptr
= RxV
+ offset
;
313 if (K_const
== 0 && length
>= 4) {
315 end_addr
= start_addr
+ length
;
318 * Versions v3 and earlier used the K value to specify a power-of-2 size
319 * 2^(K+2) that is greater than the buffer length
321 int32_t mask
= (1 << (K_const
+ 2)) - 1;
322 start_addr
= RxV
& (~mask
);
323 end_addr
= start_addr
| length
;
326 if (new_ptr
>= end_addr
) {
328 } else if (new_ptr
< start_addr
) {
335 uint32_t HELPER(fbrev
)(uint32_t addr
)
338 * Bit reverse the low 16 bits of the address
340 return deposit32(addr
, 0, 16, revbit16(addr
));
343 static float32
build_float32(uint8_t sign
, uint32_t exp
, uint32_t mant
)
347 ((exp
& 0xff) << SF_MANTBITS
) |
348 (mant
& ((1 << SF_MANTBITS
) - 1)));
352 * sfrecipa, sfinvsqrta have two 32-bit results
353 * r0,p0=sfrecipa(r1,r2)
354 * r0,p0=sfinvsqrta(r1)
356 * Since helpers can only return a single value, we pack the two results
357 * into a 64-bit value.
359 uint64_t HELPER(sfrecipa
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
368 arch_fpop_start(env
);
369 if (arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
)) {
371 idx
= (RtV
>> 16) & 0x7f;
372 mant
= (recip_lookup_table
[idx
] << 15) | 1;
373 exp
= SF_BIAS
- (float32_getexp(RtV
) - SF_BIAS
) - 1;
374 RdV
= build_float32(extract32(RtV
, 31, 1), exp
, mant
);
377 return ((uint64_t)RdV
<< 32) | PeV
;
380 uint64_t HELPER(sfinvsqrta
)(CPUHexagonState
*env
, float32 RsV
)
389 arch_fpop_start(env
);
390 if (arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
)) {
392 idx
= (RsV
>> 17) & 0x7f;
393 mant
= (invsqrt_lookup_table
[idx
] << 15);
394 exp
= SF_BIAS
- ((float32_getexp(RsV
) - SF_BIAS
) >> 1) - 1;
395 RdV
= build_float32(extract32(RsV
, 31, 1), exp
, mant
);
398 return ((uint64_t)RdV
<< 32) | PeV
;
401 int64_t HELPER(vacsh_val
)(CPUHexagonState
*env
,
402 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
404 for (int i
= 0; i
< 4; i
++) {
405 int xv
= sextract64(RxxV
, i
* 16, 16);
406 int sv
= sextract64(RssV
, i
* 16, 16);
407 int tv
= sextract64(RttV
, i
* 16, 16);
411 max
= xv
> sv
? xv
: sv
;
412 /* Note that fSATH can set the OVF bit in usr */
413 RxxV
= deposit64(RxxV
, i
* 16, 16, fSATH(max
));
418 int32_t HELPER(vacsh_pred
)(CPUHexagonState
*env
,
419 int64_t RxxV
, int64_t RssV
, int64_t RttV
)
422 for (int i
= 0; i
< 4; i
++) {
423 int xv
= sextract64(RxxV
, i
* 16, 16);
424 int sv
= sextract64(RssV
, i
* 16, 16);
425 int tv
= sextract64(RttV
, i
* 16, 16);
428 PeV
= deposit32(PeV
, i
* 2, 1, (xv
> sv
));
429 PeV
= deposit32(PeV
, i
* 2 + 1, 1, (xv
> sv
));
434 static void probe_store(CPUHexagonState
*env
, int slot
, int mmu_idx
)
436 if (!(env
->slot_cancelled
& (1 << slot
))) {
437 size1u_t width
= env
->mem_log_stores
[slot
].width
;
438 target_ulong va
= env
->mem_log_stores
[slot
].va
;
439 uintptr_t ra
= GETPC();
440 probe_write(env
, va
, width
, mmu_idx
, ra
);
444 /* Called during packet commit when there are two scalar stores */
445 void HELPER(probe_pkt_scalar_store_s0
)(CPUHexagonState
*env
, int mmu_idx
)
447 probe_store(env
, 0, mmu_idx
);
450 void HELPER(probe_hvx_stores
)(CPUHexagonState
*env
, int mmu_idx
)
452 uintptr_t retaddr
= GETPC();
455 /* Normal (possibly masked) vector store */
456 for (i
= 0; i
< VSTORES_MAX
; i
++) {
457 if (env
->vstore_pending
[i
]) {
458 target_ulong va
= env
->vstore
[i
].va
;
459 int size
= env
->vstore
[i
].size
;
460 for (int j
= 0; j
< size
; j
++) {
461 if (test_bit(j
, env
->vstore
[i
].mask
)) {
462 probe_write(env
, va
+ j
, 1, mmu_idx
, retaddr
);
469 if (env
->vtcm_pending
) {
470 if (env
->vtcm_log
.op
) {
471 /* Need to perform the scatter read/modify/write at commit time */
472 if (env
->vtcm_log
.op_size
== 2) {
473 SCATTER_OP_PROBE_MEM(size2u_t
, mmu_idx
, retaddr
);
474 } else if (env
->vtcm_log
.op_size
== 4) {
475 /* Word Scatter += */
476 SCATTER_OP_PROBE_MEM(size4u_t
, mmu_idx
, retaddr
);
478 g_assert_not_reached();
481 for (int i
= 0; i
< sizeof(MMVector
); i
++) {
482 if (test_bit(i
, env
->vtcm_log
.mask
)) {
483 probe_write(env
, env
->vtcm_log
.va
[i
], 1, mmu_idx
, retaddr
);
491 void HELPER(probe_pkt_scalar_hvx_stores
)(CPUHexagonState
*env
, int mask
,
494 bool has_st0
= (mask
>> 0) & 1;
495 bool has_st1
= (mask
>> 1) & 1;
496 bool has_hvx_stores
= (mask
>> 2) & 1;
499 probe_store(env
, 0, mmu_idx
);
502 probe_store(env
, 1, mmu_idx
);
504 if (has_hvx_stores
) {
505 HELPER(probe_hvx_stores
)(env
, mmu_idx
);
511 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
513 * If the load is in slot 0 and there is a store in slot1 (that
514 * wasn't cancelled), we have to do the store first.
516 static void check_noshuf(CPUHexagonState
*env
, uint32_t slot
)
518 if (slot
== 0 && env
->pkt_has_store_s1
&&
519 ((env
->slot_cancelled
& (1 << 1)) == 0)) {
520 HELPER(commit_store
)(env
, 1);
524 static uint8_t mem_load1(CPUHexagonState
*env
, uint32_t slot
,
527 uintptr_t ra
= GETPC();
528 check_noshuf(env
, slot
);
529 return cpu_ldub_data_ra(env
, vaddr
, ra
);
532 static uint16_t mem_load2(CPUHexagonState
*env
, uint32_t slot
,
535 uintptr_t ra
= GETPC();
536 check_noshuf(env
, slot
);
537 return cpu_lduw_data_ra(env
, vaddr
, ra
);
540 static uint32_t mem_load4(CPUHexagonState
*env
, uint32_t slot
,
543 uintptr_t ra
= GETPC();
544 check_noshuf(env
, slot
);
545 return cpu_ldl_data_ra(env
, vaddr
, ra
);
548 static uint64_t mem_load8(CPUHexagonState
*env
, uint32_t slot
,
551 uintptr_t ra
= GETPC();
552 check_noshuf(env
, slot
);
553 return cpu_ldq_data_ra(env
, vaddr
, ra
);
557 float64
HELPER(conv_sf2df
)(CPUHexagonState
*env
, float32 RsV
)
560 arch_fpop_start(env
);
561 out_f64
= float32_to_float64(RsV
, &env
->fp_status
);
566 float32
HELPER(conv_df2sf
)(CPUHexagonState
*env
, float64 RssV
)
569 arch_fpop_start(env
);
570 out_f32
= float64_to_float32(RssV
, &env
->fp_status
);
575 float32
HELPER(conv_uw2sf
)(CPUHexagonState
*env
, int32_t RsV
)
578 arch_fpop_start(env
);
579 RdV
= uint32_to_float32(RsV
, &env
->fp_status
);
584 float64
HELPER(conv_uw2df
)(CPUHexagonState
*env
, int32_t RsV
)
587 arch_fpop_start(env
);
588 RddV
= uint32_to_float64(RsV
, &env
->fp_status
);
593 float32
HELPER(conv_w2sf
)(CPUHexagonState
*env
, int32_t RsV
)
596 arch_fpop_start(env
);
597 RdV
= int32_to_float32(RsV
, &env
->fp_status
);
602 float64
HELPER(conv_w2df
)(CPUHexagonState
*env
, int32_t RsV
)
605 arch_fpop_start(env
);
606 RddV
= int32_to_float64(RsV
, &env
->fp_status
);
611 float32
HELPER(conv_ud2sf
)(CPUHexagonState
*env
, int64_t RssV
)
614 arch_fpop_start(env
);
615 RdV
= uint64_to_float32(RssV
, &env
->fp_status
);
620 float64
HELPER(conv_ud2df
)(CPUHexagonState
*env
, int64_t RssV
)
623 arch_fpop_start(env
);
624 RddV
= uint64_to_float64(RssV
, &env
->fp_status
);
629 float32
HELPER(conv_d2sf
)(CPUHexagonState
*env
, int64_t RssV
)
632 arch_fpop_start(env
);
633 RdV
= int64_to_float32(RssV
, &env
->fp_status
);
638 float64
HELPER(conv_d2df
)(CPUHexagonState
*env
, int64_t RssV
)
641 arch_fpop_start(env
);
642 RddV
= int64_to_float64(RssV
, &env
->fp_status
);
647 uint32_t HELPER(conv_sf2uw
)(CPUHexagonState
*env
, float32 RsV
)
650 arch_fpop_start(env
);
651 /* Hexagon checks the sign before rounding */
652 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
653 float_raise(float_flag_invalid
, &env
->fp_status
);
656 RdV
= float32_to_uint32(RsV
, &env
->fp_status
);
662 int32_t HELPER(conv_sf2w
)(CPUHexagonState
*env
, float32 RsV
)
665 arch_fpop_start(env
);
666 /* Hexagon returns -1 for NaN */
667 if (float32_is_any_nan(RsV
)) {
668 float_raise(float_flag_invalid
, &env
->fp_status
);
671 RdV
= float32_to_int32(RsV
, &env
->fp_status
);
677 uint64_t HELPER(conv_sf2ud
)(CPUHexagonState
*env
, float32 RsV
)
680 arch_fpop_start(env
);
681 /* Hexagon checks the sign before rounding */
682 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
683 float_raise(float_flag_invalid
, &env
->fp_status
);
686 RddV
= float32_to_uint64(RsV
, &env
->fp_status
);
692 int64_t HELPER(conv_sf2d
)(CPUHexagonState
*env
, float32 RsV
)
695 arch_fpop_start(env
);
696 /* Hexagon returns -1 for NaN */
697 if (float32_is_any_nan(RsV
)) {
698 float_raise(float_flag_invalid
, &env
->fp_status
);
701 RddV
= float32_to_int64(RsV
, &env
->fp_status
);
707 uint32_t HELPER(conv_df2uw
)(CPUHexagonState
*env
, float64 RssV
)
710 arch_fpop_start(env
);
711 /* Hexagon checks the sign before rounding */
712 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
713 float_raise(float_flag_invalid
, &env
->fp_status
);
716 RdV
= float64_to_uint32(RssV
, &env
->fp_status
);
722 int32_t HELPER(conv_df2w
)(CPUHexagonState
*env
, float64 RssV
)
725 arch_fpop_start(env
);
726 /* Hexagon returns -1 for NaN */
727 if (float64_is_any_nan(RssV
)) {
728 float_raise(float_flag_invalid
, &env
->fp_status
);
731 RdV
= float64_to_int32(RssV
, &env
->fp_status
);
737 uint64_t HELPER(conv_df2ud
)(CPUHexagonState
*env
, float64 RssV
)
740 arch_fpop_start(env
);
741 /* Hexagon checks the sign before rounding */
742 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
743 float_raise(float_flag_invalid
, &env
->fp_status
);
746 RddV
= float64_to_uint64(RssV
, &env
->fp_status
);
752 int64_t HELPER(conv_df2d
)(CPUHexagonState
*env
, float64 RssV
)
755 arch_fpop_start(env
);
756 /* Hexagon returns -1 for NaN */
757 if (float64_is_any_nan(RssV
)) {
758 float_raise(float_flag_invalid
, &env
->fp_status
);
761 RddV
= float64_to_int64(RssV
, &env
->fp_status
);
767 uint32_t HELPER(conv_sf2uw_chop
)(CPUHexagonState
*env
, float32 RsV
)
770 arch_fpop_start(env
);
771 /* Hexagon checks the sign before rounding */
772 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
773 float_raise(float_flag_invalid
, &env
->fp_status
);
776 RdV
= float32_to_uint32_round_to_zero(RsV
, &env
->fp_status
);
782 int32_t HELPER(conv_sf2w_chop
)(CPUHexagonState
*env
, float32 RsV
)
785 arch_fpop_start(env
);
786 /* Hexagon returns -1 for NaN */
787 if (float32_is_any_nan(RsV
)) {
788 float_raise(float_flag_invalid
, &env
->fp_status
);
791 RdV
= float32_to_int32_round_to_zero(RsV
, &env
->fp_status
);
797 uint64_t HELPER(conv_sf2ud_chop
)(CPUHexagonState
*env
, float32 RsV
)
800 arch_fpop_start(env
);
801 /* Hexagon checks the sign before rounding */
802 if (float32_is_neg(RsV
) && !float32_is_any_nan(RsV
)) {
803 float_raise(float_flag_invalid
, &env
->fp_status
);
806 RddV
= float32_to_uint64_round_to_zero(RsV
, &env
->fp_status
);
812 int64_t HELPER(conv_sf2d_chop
)(CPUHexagonState
*env
, float32 RsV
)
815 arch_fpop_start(env
);
816 /* Hexagon returns -1 for NaN */
817 if (float32_is_any_nan(RsV
)) {
818 float_raise(float_flag_invalid
, &env
->fp_status
);
821 RddV
= float32_to_int64_round_to_zero(RsV
, &env
->fp_status
);
827 uint32_t HELPER(conv_df2uw_chop
)(CPUHexagonState
*env
, float64 RssV
)
830 arch_fpop_start(env
);
831 /* Hexagon checks the sign before rounding */
832 if (float64_is_neg(RssV
) && !float32_is_any_nan(RssV
)) {
833 float_raise(float_flag_invalid
, &env
->fp_status
);
836 RdV
= float64_to_uint32_round_to_zero(RssV
, &env
->fp_status
);
842 int32_t HELPER(conv_df2w_chop
)(CPUHexagonState
*env
, float64 RssV
)
845 arch_fpop_start(env
);
846 /* Hexagon returns -1 for NaN */
847 if (float64_is_any_nan(RssV
)) {
848 float_raise(float_flag_invalid
, &env
->fp_status
);
851 RdV
= float64_to_int32_round_to_zero(RssV
, &env
->fp_status
);
857 uint64_t HELPER(conv_df2ud_chop
)(CPUHexagonState
*env
, float64 RssV
)
860 arch_fpop_start(env
);
861 /* Hexagon checks the sign before rounding */
862 if (float64_is_neg(RssV
) && !float64_is_any_nan(RssV
)) {
863 float_raise(float_flag_invalid
, &env
->fp_status
);
866 RddV
= float64_to_uint64_round_to_zero(RssV
, &env
->fp_status
);
872 int64_t HELPER(conv_df2d_chop
)(CPUHexagonState
*env
, float64 RssV
)
875 arch_fpop_start(env
);
876 /* Hexagon returns -1 for NaN */
877 if (float64_is_any_nan(RssV
)) {
878 float_raise(float_flag_invalid
, &env
->fp_status
);
881 RddV
= float64_to_int64_round_to_zero(RssV
, &env
->fp_status
);
887 float32
HELPER(sfadd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
890 arch_fpop_start(env
);
891 RdV
= float32_add(RsV
, RtV
, &env
->fp_status
);
896 float32
HELPER(sfsub
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
899 arch_fpop_start(env
);
900 RdV
= float32_sub(RsV
, RtV
, &env
->fp_status
);
905 int32_t HELPER(sfcmpeq
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
908 arch_fpop_start(env
);
909 PdV
= f8BITSOF(float32_eq_quiet(RsV
, RtV
, &env
->fp_status
));
914 int32_t HELPER(sfcmpgt
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
918 arch_fpop_start(env
);
919 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
920 PdV
= f8BITSOF(cmp
== float_relation_greater
);
925 int32_t HELPER(sfcmpge
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
929 arch_fpop_start(env
);
930 cmp
= float32_compare_quiet(RsV
, RtV
, &env
->fp_status
);
931 PdV
= f8BITSOF(cmp
== float_relation_greater
||
932 cmp
== float_relation_equal
);
937 int32_t HELPER(sfcmpuo
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
940 arch_fpop_start(env
);
941 PdV
= f8BITSOF(float32_is_any_nan(RsV
) ||
942 float32_is_any_nan(RtV
));
947 float32
HELPER(sfmax
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
950 arch_fpop_start(env
);
951 RdV
= float32_maxnum(RsV
, RtV
, &env
->fp_status
);
956 float32
HELPER(sfmin
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
959 arch_fpop_start(env
);
960 RdV
= float32_minnum(RsV
, RtV
, &env
->fp_status
);
965 int32_t HELPER(sfclass
)(CPUHexagonState
*env
, float32 RsV
, int32_t uiV
)
968 arch_fpop_start(env
);
969 if (fGETBIT(0, uiV
) && float32_is_zero(RsV
)) {
972 if (fGETBIT(1, uiV
) && float32_is_normal(RsV
)) {
975 if (fGETBIT(2, uiV
) && float32_is_denormal(RsV
)) {
978 if (fGETBIT(3, uiV
) && float32_is_infinity(RsV
)) {
981 if (fGETBIT(4, uiV
) && float32_is_any_nan(RsV
)) {
984 set_float_exception_flags(0, &env
->fp_status
);
989 float32
HELPER(sffixupn
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
993 arch_fpop_start(env
);
994 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
1000 float32
HELPER(sffixupd
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
1004 arch_fpop_start(env
);
1005 arch_sf_recip_common(&RsV
, &RtV
, &RdV
, &adjust
, &env
->fp_status
);
1011 float32
HELPER(sffixupr
)(CPUHexagonState
*env
, float32 RsV
)
1015 arch_fpop_start(env
);
1016 arch_sf_invsqrt_common(&RsV
, &RdV
, &adjust
, &env
->fp_status
);
1022 float64
HELPER(dfadd
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1025 arch_fpop_start(env
);
1026 RddV
= float64_add(RssV
, RttV
, &env
->fp_status
);
1031 float64
HELPER(dfsub
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1034 arch_fpop_start(env
);
1035 RddV
= float64_sub(RssV
, RttV
, &env
->fp_status
);
1040 float64
HELPER(dfmax
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1043 arch_fpop_start(env
);
1044 RddV
= float64_maxnum(RssV
, RttV
, &env
->fp_status
);
1045 if (float64_is_any_nan(RssV
) || float64_is_any_nan(RttV
)) {
1046 float_raise(float_flag_invalid
, &env
->fp_status
);
1052 float64
HELPER(dfmin
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1055 arch_fpop_start(env
);
1056 RddV
= float64_minnum(RssV
, RttV
, &env
->fp_status
);
1057 if (float64_is_any_nan(RssV
) || float64_is_any_nan(RttV
)) {
1058 float_raise(float_flag_invalid
, &env
->fp_status
);
1064 int32_t HELPER(dfcmpeq
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1067 arch_fpop_start(env
);
1068 PdV
= f8BITSOF(float64_eq_quiet(RssV
, RttV
, &env
->fp_status
));
1073 int32_t HELPER(dfcmpgt
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1077 arch_fpop_start(env
);
1078 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
1079 PdV
= f8BITSOF(cmp
== float_relation_greater
);
1084 int32_t HELPER(dfcmpge
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1088 arch_fpop_start(env
);
1089 cmp
= float64_compare_quiet(RssV
, RttV
, &env
->fp_status
);
1090 PdV
= f8BITSOF(cmp
== float_relation_greater
||
1091 cmp
== float_relation_equal
);
1096 int32_t HELPER(dfcmpuo
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1099 arch_fpop_start(env
);
1100 PdV
= f8BITSOF(float64_is_any_nan(RssV
) ||
1101 float64_is_any_nan(RttV
));
1106 int32_t HELPER(dfclass
)(CPUHexagonState
*env
, float64 RssV
, int32_t uiV
)
1109 arch_fpop_start(env
);
1110 if (fGETBIT(0, uiV
) && float64_is_zero(RssV
)) {
1113 if (fGETBIT(1, uiV
) && float64_is_normal(RssV
)) {
1116 if (fGETBIT(2, uiV
) && float64_is_denormal(RssV
)) {
1119 if (fGETBIT(3, uiV
) && float64_is_infinity(RssV
)) {
1122 if (fGETBIT(4, uiV
) && float64_is_any_nan(RssV
)) {
1125 set_float_exception_flags(0, &env
->fp_status
);
1130 float32
HELPER(sfmpy
)(CPUHexagonState
*env
, float32 RsV
, float32 RtV
)
1133 arch_fpop_start(env
);
1134 RdV
= internal_mpyf(RsV
, RtV
, &env
->fp_status
);
1139 float32
HELPER(sffma
)(CPUHexagonState
*env
, float32 RxV
,
1140 float32 RsV
, float32 RtV
)
1142 arch_fpop_start(env
);
1143 RxV
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1148 static bool is_zero_prod(float32 a
, float32 b
)
1150 return ((float32_is_zero(a
) && is_finite(b
)) ||
1151 (float32_is_zero(b
) && is_finite(a
)));
1154 static float32
check_nan(float32 dst
, float32 x
, float_status
*fp_status
)
1157 if (float32_is_any_nan(x
)) {
1158 if (extract32(x
, 22, 1) == 0) {
1159 float_raise(float_flag_invalid
, fp_status
);
1161 ret
= make_float32(0xffffffff); /* nan */
1166 float32
HELPER(sffma_sc
)(CPUHexagonState
*env
, float32 RxV
,
1167 float32 RsV
, float32 RtV
, float32 PuV
)
1170 arch_fpop_start(env
);
1171 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1172 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1173 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1174 tmp
= internal_fmafx(RsV
, RtV
, RxV
, fSXTN(8, 64, PuV
), &env
->fp_status
);
1175 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1182 float32
HELPER(sffms
)(CPUHexagonState
*env
, float32 RxV
,
1183 float32 RsV
, float32 RtV
)
1186 arch_fpop_start(env
);
1187 neg_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1188 RxV
= internal_fmafx(neg_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1193 static bool is_inf_prod(int32_t a
, int32_t b
)
1195 return (float32_is_infinity(a
) && float32_is_infinity(b
)) ||
1196 (float32_is_infinity(a
) && is_finite(b
) && !float32_is_zero(b
)) ||
1197 (float32_is_infinity(b
) && is_finite(a
) && !float32_is_zero(a
));
1200 float32
HELPER(sffma_lib
)(CPUHexagonState
*env
, float32 RxV
,
1201 float32 RsV
, float32 RtV
)
1207 arch_fpop_start(env
);
1208 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1209 infminusinf
= float32_is_infinity(RxV
) &&
1210 is_inf_prod(RsV
, RtV
) &&
1211 (fGETBIT(31, RsV
^ RxV
^ RtV
) != 0);
1212 infinp
= float32_is_infinity(RxV
) ||
1213 float32_is_infinity(RtV
) ||
1214 float32_is_infinity(RsV
);
1215 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1216 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1217 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1218 tmp
= internal_fmafx(RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1219 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1222 set_float_exception_flags(0, &env
->fp_status
);
1223 if (float32_is_infinity(RxV
) && !infinp
) {
1233 float32
HELPER(sffms_lib
)(CPUHexagonState
*env
, float32 RxV
,
1234 float32 RsV
, float32 RtV
)
1240 arch_fpop_start(env
);
1241 set_float_rounding_mode(float_round_nearest_even
, &env
->fp_status
);
1242 infminusinf
= float32_is_infinity(RxV
) &&
1243 is_inf_prod(RsV
, RtV
) &&
1244 (fGETBIT(31, RsV
^ RxV
^ RtV
) == 0);
1245 infinp
= float32_is_infinity(RxV
) ||
1246 float32_is_infinity(RtV
) ||
1247 float32_is_infinity(RsV
);
1248 RxV
= check_nan(RxV
, RxV
, &env
->fp_status
);
1249 RxV
= check_nan(RxV
, RsV
, &env
->fp_status
);
1250 RxV
= check_nan(RxV
, RtV
, &env
->fp_status
);
1251 float32 minus_RsV
= float32_sub(float32_zero
, RsV
, &env
->fp_status
);
1252 tmp
= internal_fmafx(minus_RsV
, RtV
, RxV
, 0, &env
->fp_status
);
1253 if (!(float32_is_zero(RxV
) && is_zero_prod(RsV
, RtV
))) {
1256 set_float_exception_flags(0, &env
->fp_status
);
1257 if (float32_is_infinity(RxV
) && !infinp
) {
1267 float64
HELPER(dfmpyfix
)(CPUHexagonState
*env
, float64 RssV
, float64 RttV
)
1270 arch_fpop_start(env
);
1271 if (float64_is_denormal(RssV
) &&
1272 (float64_getexp(RttV
) >= 512) &&
1273 float64_is_normal(RttV
)) {
1274 RddV
= float64_mul(RssV
, make_float64(0x4330000000000000),
1276 } else if (float64_is_denormal(RttV
) &&
1277 (float64_getexp(RssV
) >= 512) &&
1278 float64_is_normal(RssV
)) {
1279 RddV
= float64_mul(RssV
, make_float64(0x3cb0000000000000),
1288 float64
HELPER(dfmpyhh
)(CPUHexagonState
*env
, float64 RxxV
,
1289 float64 RssV
, float64 RttV
)
1291 arch_fpop_start(env
);
1292 RxxV
= internal_mpyhh(RssV
, RttV
, RxxV
, &env
->fp_status
);
1297 /* Histogram instructions */
1299 void HELPER(vhist
)(CPUHexagonState
*env
)
1301 MMVector
*input
= &env
->tmp_VRegs
[0];
1303 for (int lane
= 0; lane
< 8; lane
++) {
1304 for (int i
= 0; i
< sizeof(MMVector
) / 8; ++i
) {
1305 unsigned char value
= input
->ub
[(sizeof(MMVector
) / 8) * lane
+ i
];
1306 unsigned char regno
= value
>> 3;
1307 unsigned char element
= value
& 7;
1309 env
->VRegs
[regno
].uh
[(sizeof(MMVector
) / 16) * lane
+ element
]++;
1314 void HELPER(vhistq
)(CPUHexagonState
*env
)
1316 MMVector
*input
= &env
->tmp_VRegs
[0];
1318 for (int lane
= 0; lane
< 8; lane
++) {
1319 for (int i
= 0; i
< sizeof(MMVector
) / 8; ++i
) {
1320 unsigned char value
= input
->ub
[(sizeof(MMVector
) / 8) * lane
+ i
];
1321 unsigned char regno
= value
>> 3;
1322 unsigned char element
= value
& 7;
1324 if (fGETQBIT(env
->qtmp
, sizeof(MMVector
) / 8 * lane
+ i
)) {
1325 env
->VRegs
[regno
].uh
[
1326 (sizeof(MMVector
) / 16) * lane
+ element
]++;
1332 void HELPER(vwhist256
)(CPUHexagonState
*env
)
1334 MMVector
*input
= &env
->tmp_VRegs
[0];
1336 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1337 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1338 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1339 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1340 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1342 env
->VRegs
[vindex
].uh
[elindex
] =
1343 env
->VRegs
[vindex
].uh
[elindex
] + weight
;
1347 void HELPER(vwhist256q
)(CPUHexagonState
*env
)
1349 MMVector
*input
= &env
->tmp_VRegs
[0];
1351 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1352 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1353 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1354 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1355 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1357 if (fGETQBIT(env
->qtmp
, 2 * i
)) {
1358 env
->VRegs
[vindex
].uh
[elindex
] =
1359 env
->VRegs
[vindex
].uh
[elindex
] + weight
;
1364 void HELPER(vwhist256_sat
)(CPUHexagonState
*env
)
1366 MMVector
*input
= &env
->tmp_VRegs
[0];
1368 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1369 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1370 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1371 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1372 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1374 env
->VRegs
[vindex
].uh
[elindex
] =
1375 fVSATUH(env
->VRegs
[vindex
].uh
[elindex
] + weight
);
1379 void HELPER(vwhist256q_sat
)(CPUHexagonState
*env
)
1381 MMVector
*input
= &env
->tmp_VRegs
[0];
1383 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1384 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1385 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1386 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1387 unsigned int elindex
= ((i
>> 0) & (~7)) | ((bucket
>> 0) & 7);
1389 if (fGETQBIT(env
->qtmp
, 2 * i
)) {
1390 env
->VRegs
[vindex
].uh
[elindex
] =
1391 fVSATUH(env
->VRegs
[vindex
].uh
[elindex
] + weight
);
1396 void HELPER(vwhist128
)(CPUHexagonState
*env
)
1398 MMVector
*input
= &env
->tmp_VRegs
[0];
1400 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1401 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1402 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1403 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1404 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1406 env
->VRegs
[vindex
].uw
[elindex
] =
1407 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1411 void HELPER(vwhist128q
)(CPUHexagonState
*env
)
1413 MMVector
*input
= &env
->tmp_VRegs
[0];
1415 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1416 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1417 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1418 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1419 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1421 if (fGETQBIT(env
->qtmp
, 2 * i
)) {
1422 env
->VRegs
[vindex
].uw
[elindex
] =
1423 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1428 void HELPER(vwhist128m
)(CPUHexagonState
*env
, int32_t uiV
)
1430 MMVector
*input
= &env
->tmp_VRegs
[0];
1432 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1433 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1434 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1435 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1436 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1438 if ((bucket
& 1) == uiV
) {
1439 env
->VRegs
[vindex
].uw
[elindex
] =
1440 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1445 void HELPER(vwhist128qm
)(CPUHexagonState
*env
, int32_t uiV
)
1447 MMVector
*input
= &env
->tmp_VRegs
[0];
1449 for (int i
= 0; i
< (sizeof(MMVector
) / 2); i
++) {
1450 unsigned int bucket
= fGETUBYTE(0, input
->h
[i
]);
1451 unsigned int weight
= fGETUBYTE(1, input
->h
[i
]);
1452 unsigned int vindex
= (bucket
>> 3) & 0x1F;
1453 unsigned int elindex
= ((i
>> 1) & (~3)) | ((bucket
>> 1) & 3);
1455 if (((bucket
& 1) == uiV
) && fGETQBIT(env
->qtmp
, 2 * i
)) {
1456 env
->VRegs
[vindex
].uw
[elindex
] =
1457 env
->VRegs
[vindex
].uw
[elindex
] + weight
;
1462 static void cancel_slot(CPUHexagonState
*env
, uint32_t slot
)
1464 HEX_DEBUG_LOG("Slot %d cancelled\n", slot
);
1465 env
->slot_cancelled
|= (1 << slot
);
1468 /* These macros can be referenced in the generated helper functions */
1469 #define warn(...) /* Nothing */
1470 #define fatal(...) g_assert_not_reached();
1472 #define BOGUS_HELPER(tag) \
1473 printf("ERROR: bogus helper: " #tag "\n")
1475 #include "helper_funcs_generated.c.inc"