]> git.proxmox.com Git - mirror_qemu.git/blame - target/hexagon/op_helper.c
Merge tag 'pull-hex-20231018' of https://github.com/quic/qemu into staging
[mirror_qemu.git] / target / hexagon / op_helper.c
CommitLineData
b5ed786f 1/*
dae386b8 2 * Copyright(c) 2019-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
b5ed786f
TS
3 *
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.
8 *
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.
13 *
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/>.
16 */
17
18#include "qemu/osdep.h"
25fc9b79
PM
19#include "qemu/log.h"
20#include "exec/exec-all.h"
4699a927 21#include "exec/cpu_ldst.h"
b5ed786f
TS
22#include "exec/helper-proto.h"
23#include "fpu/softfloat.h"
24#include "cpu.h"
25#include "internal.h"
26#include "macros.h"
27#include "arch.h"
28#include "hex_arch_types.h"
29#include "fma_emu.h"
33e9ed11
TS
30#include "mmvec/mmvec.h"
31#include "mmvec/macros.h"
7e8b3b39 32#include "op_helper.h"
7b84fd04 33#include "translate.h"
b5ed786f
TS
34
35#define SF_BIAS 127
36#define SF_MANTBITS 23
37
38/* Exceptions processing helpers */
8905770b
MAL
39static G_NORETURN
40void do_raise_exception_err(CPUHexagonState *env,
41 uint32_t exception,
42 uintptr_t pc)
b5ed786f 43{
7d9ab202 44 CPUState *cs = env_cpu(env);
b5ed786f
TS
45 qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
46 cs->exception_index = exception;
47 cpu_loop_exit_restore(cs, pc);
48}
49
8905770b 50G_NORETURN void HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
b5ed786f
TS
51{
52 do_raise_exception_err(env, excp, 0);
53}
54
7e8b3b39
PM
55void log_store32(CPUHexagonState *env, target_ulong addr,
56 target_ulong val, int width, int slot)
b5ed786f
TS
57{
58 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
59 ", %" PRId32 " [0x08%" PRIx32 "])\n",
60 width, addr, val, val);
61 env->mem_log_stores[slot].va = addr;
62 env->mem_log_stores[slot].width = width;
63 env->mem_log_stores[slot].data32 = val;
64}
65
7e8b3b39
PM
66void log_store64(CPUHexagonState *env, target_ulong addr,
67 int64_t val, int width, int slot)
b5ed786f
TS
68{
69 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
70 ", %" PRId64 " [0x016%" PRIx64 "])\n",
71 width, addr, val, val);
72 env->mem_log_stores[slot].va = addr;
73 env->mem_log_stores[slot].width = width;
74 env->mem_log_stores[slot].data64 = val;
75}
76
b5ed786f
TS
77/* Handy place to set a breakpoint */
78void HELPER(debug_start_packet)(CPUHexagonState *env)
79{
80 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
81 env->gpr[HEX_REG_PC]);
82
83 for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
84 env->reg_written[i] = 0;
85 }
86}
b5ed786f 87
b5ed786f
TS
88/* Checks for bookkeeping errors between disassembly context and runtime */
89void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
90{
91 if (env->mem_log_stores[slot].width != check) {
92 HEX_DEBUG_LOG("ERROR: %d != %d\n",
93 env->mem_log_stores[slot].width, check);
94 g_assert_not_reached();
95 }
96}
b5ed786f 97
3bd83593 98static void commit_store(CPUHexagonState *env, int slot_num, uintptr_t ra)
b5ed786f 99{
4699a927
TS
100 uint8_t width = env->mem_log_stores[slot_num].width;
101 target_ulong va = env->mem_log_stores[slot_num].va;
102
103 switch (width) {
b5ed786f 104 case 1:
4699a927 105 cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
b5ed786f
TS
106 break;
107 case 2:
4699a927 108 cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
b5ed786f
TS
109 break;
110 case 4:
4699a927 111 cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
b5ed786f
TS
112 break;
113 case 8:
4699a927 114 cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra);
b5ed786f
TS
115 break;
116 default:
117 g_assert_not_reached();
118 }
119}
120
3bd83593
MTB
121void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
122{
123 uintptr_t ra = GETPC();
124 commit_store(env, slot_num, ra);
125}
126
33e9ed11
TS
127void HELPER(gather_store)(CPUHexagonState *env, uint32_t addr, int slot)
128{
129 mem_gather_store(env, addr, slot);
130}
131
132void HELPER(commit_hvx_stores)(CPUHexagonState *env)
133{
134 uintptr_t ra = GETPC();
33e9ed11
TS
135
136 /* Normal (possibly masked) vector store */
20c34a92 137 for (int i = 0; i < VSTORES_MAX; i++) {
33e9ed11
TS
138 if (env->vstore_pending[i]) {
139 env->vstore_pending[i] = 0;
140 target_ulong va = env->vstore[i].va;
141 int size = env->vstore[i].size;
142 for (int j = 0; j < size; j++) {
143 if (test_bit(j, env->vstore[i].mask)) {
144 cpu_stb_data_ra(env, va + j, env->vstore[i].data.ub[j], ra);
145 }
146 }
147 }
148 }
149
150 /* Scatter store */
151 if (env->vtcm_pending) {
152 env->vtcm_pending = false;
153 if (env->vtcm_log.op) {
154 /* Need to perform the scatter read/modify/write at commit time */
155 if (env->vtcm_log.op_size == 2) {
156 SCATTER_OP_WRITE_TO_MEM(uint16_t);
157 } else if (env->vtcm_log.op_size == 4) {
158 /* Word Scatter += */
159 SCATTER_OP_WRITE_TO_MEM(uint32_t);
160 } else {
161 g_assert_not_reached();
162 }
163 } else {
20c34a92 164 for (int i = 0; i < sizeof(MMVector); i++) {
33e9ed11
TS
165 if (test_bit(i, env->vtcm_log.mask)) {
166 cpu_stb_data_ra(env, env->vtcm_log.va[i],
167 env->vtcm_log.data.ub[i], ra);
168 clear_bit(i, env->vtcm_log.mask);
169 env->vtcm_log.data.ub[i] = 0;
170 }
171
172 }
173 }
174 }
175}
176
b5ed786f
TS
177static void print_store(CPUHexagonState *env, int slot)
178{
179 if (!(env->slot_cancelled & (1 << slot))) {
180 uint8_t width = env->mem_log_stores[slot].width;
181 if (width == 1) {
182 uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
183 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
184 " (0x%02" PRIx32 ")\n",
185 env->mem_log_stores[slot].va, data, data);
186 } else if (width == 2) {
187 uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
188 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
189 " (0x%04" PRIx32 ")\n",
190 env->mem_log_stores[slot].va, data, data);
191 } else if (width == 4) {
192 uint32_t data = env->mem_log_stores[slot].data32;
193 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
194 " (0x%08" PRIx32 ")\n",
195 env->mem_log_stores[slot].va, data, data);
196 } else if (width == 8) {
197 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
198 " (0x%016" PRIx64 ")\n",
199 env->mem_log_stores[slot].va,
200 env->mem_log_stores[slot].data64,
201 env->mem_log_stores[slot].data64);
202 } else {
203 HEX_DEBUG_LOG("\tBad store width %d\n", width);
204 g_assert_not_reached();
205 }
206 }
207}
208
209/* This function is a handy place to set a breakpoint */
0fc56c43 210void HELPER(debug_commit_end)(CPUHexagonState *env, uint32_t this_PC,
842b206f 211 int pred_written, int has_st0, int has_st1)
b5ed786f
TS
212{
213 bool reg_printed = false;
214 bool pred_printed = false;
215 int i;
216
0fc56c43 217 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n", this_PC);
b5ed786f
TS
218 HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
219
220 for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
221 if (env->reg_written[i]) {
222 if (!reg_printed) {
223 HEX_DEBUG_LOG("Regs written\n");
224 reg_printed = true;
225 }
226 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
d54c5615 227 i, env->gpr[i], env->gpr[i]);
b5ed786f
TS
228 }
229 }
230
231 for (i = 0; i < NUM_PREGS; i++) {
842b206f 232 if (pred_written & (1 << i)) {
b5ed786f
TS
233 if (!pred_printed) {
234 HEX_DEBUG_LOG("Predicates written\n");
235 pred_printed = true;
236 }
237 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
e22edc7c 238 i, env->pred[i]);
b5ed786f
TS
239 }
240 }
241
242 if (has_st0 || has_st1) {
243 HEX_DEBUG_LOG("Stores\n");
244 if (has_st0) {
245 print_store(env, 0);
246 }
247 if (has_st1) {
248 print_store(env, 1);
249 }
250 }
251
613653e5 252 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->gpr[HEX_REG_PC]);
b5ed786f
TS
253 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
254 ", insn = " TARGET_FMT_lx
33e9ed11 255 ", hvx = " TARGET_FMT_lx "\n",
b5ed786f 256 env->gpr[HEX_REG_QEMU_PKT_CNT],
33e9ed11
TS
257 env->gpr[HEX_REG_QEMU_INSN_CNT],
258 env->gpr[HEX_REG_QEMU_HVX_CNT]);
b5ed786f
TS
259
260}
b5ed786f 261
b5ed786f
TS
262int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
263{
58ff2981
ML
264 uint32_t K_const = extract32(M, 24, 4);
265 uint32_t length = extract32(M, 0, 17);
b5ed786f 266 uint32_t new_ptr = RxV + offset;
46ef47e2
TS
267 uint32_t start_addr;
268 uint32_t end_addr;
b5ed786f
TS
269
270 if (K_const == 0 && length >= 4) {
46ef47e2
TS
271 start_addr = CS;
272 end_addr = start_addr + length;
273 } else {
274 /*
275 * Versions v3 and earlier used the K value to specify a power-of-2 size
276 * 2^(K+2) that is greater than the buffer length
277 */
278 int32_t mask = (1 << (K_const + 2)) - 1;
279 start_addr = RxV & (~mask);
280 end_addr = start_addr | length;
b5ed786f
TS
281 }
282
283 if (new_ptr >= end_addr) {
284 new_ptr -= length;
285 } else if (new_ptr < start_addr) {
286 new_ptr += length;
287 }
288
289 return new_ptr;
290}
291
af7f1821
TS
292uint32_t HELPER(fbrev)(uint32_t addr)
293{
294 /*
295 * Bit reverse the low 16 bits of the address
296 */
297 return deposit32(addr, 0, 16, revbit16(addr));
298}
299
d934c16d
TS
300static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
301{
302 return make_float32(
303 ((sign & 1) << 31) |
304 ((exp & 0xff) << SF_MANTBITS) |
305 (mant & ((1 << SF_MANTBITS) - 1)));
306}
307
308/*
309 * sfrecipa, sfinvsqrta have two 32-bit results
310 * r0,p0=sfrecipa(r1,r2)
311 * r0,p0=sfinvsqrta(r1)
312 *
313 * Since helpers can only return a single value, we pack the two results
314 * into a 64-bit value.
315 */
316uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
317{
318 int32_t PeV = 0;
319 float32 RdV;
320 int idx;
321 int adjust;
322 int mant;
323 int exp;
324
325 arch_fpop_start(env);
326 if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
327 PeV = adjust;
328 idx = (RtV >> 16) & 0x7f;
329 mant = (recip_lookup_table[idx] << 15) | 1;
330 exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
331 RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
332 }
333 arch_fpop_end(env);
334 return ((uint64_t)RdV << 32) | PeV;
335}
336
dd8705bd
TS
337uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
338{
339 int PeV = 0;
340 float32 RdV;
341 int idx;
342 int adjust;
343 int mant;
344 int exp;
345
346 arch_fpop_start(env);
347 if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
348 PeV = adjust;
349 idx = (RsV >> 17) & 0x7f;
350 mant = (invsqrt_lookup_table[idx] << 15);
351 exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
352 RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
353 }
354 arch_fpop_end(env);
355 return ((uint64_t)RdV << 32) | PeV;
356}
357
da74cd2d 358int64_t HELPER(vacsh_val)(CPUHexagonState *env,
d54c5615
TS
359 int64_t RxxV, int64_t RssV, int64_t RttV,
360 uint32_t pkt_need_commit)
da74cd2d
TS
361{
362 for (int i = 0; i < 4; i++) {
363 int xv = sextract64(RxxV, i * 16, 16);
364 int sv = sextract64(RssV, i * 16, 16);
365 int tv = sextract64(RttV, i * 16, 16);
366 int max;
367 xv = xv + tv;
368 sv = sv - tv;
369 max = xv > sv ? xv : sv;
370 /* Note that fSATH can set the OVF bit in usr */
371 RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
372 }
373 return RxxV;
374}
375
376int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
377 int64_t RxxV, int64_t RssV, int64_t RttV)
378{
379 int32_t PeV = 0;
380 for (int i = 0; i < 4; i++) {
381 int xv = sextract64(RxxV, i * 16, 16);
382 int sv = sextract64(RssV, i * 16, 16);
383 int tv = sextract64(RttV, i * 16, 16);
384 xv = xv + tv;
385 sv = sv - tv;
386 PeV = deposit32(PeV, i * 2, 1, (xv > sv));
387 PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
388 }
389 return PeV;
390}
391
d24f0b2b
TS
392int64_t HELPER(cabacdecbin_val)(int64_t RssV, int64_t RttV)
393{
394 int64_t RddV = 0;
395 size4u_t state;
396 size4u_t valMPS;
397 size4u_t bitpos;
398 size4u_t range;
399 size4u_t offset;
400 size4u_t rLPS;
401 size4u_t rMPS;
402
403 state = fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0);
404 valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8);
405 bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0);
406 range = fGETWORD(0, RssV);
407 offset = fGETWORD(1, RssV);
408
409 /* calculate rLPS */
410 range <<= bitpos;
411 offset <<= bitpos;
412 rLPS = rLPS_table_64x4[state][(range >> 29) & 3];
413 rLPS = rLPS << 23; /* left aligned */
414
415 /* calculate rMPS */
416 rMPS = (range & 0xff800000) - rLPS;
417
418 /* most probable region */
419 if (offset < rMPS) {
420 RddV = AC_next_state_MPS_64[state];
421 fINSERT_RANGE(RddV, 8, 8, valMPS);
422 fINSERT_RANGE(RddV, 31, 23, (rMPS >> 23));
423 fSETWORD(1, RddV, offset);
424 }
425 /* least probable region */
426 else {
427 RddV = AC_next_state_LPS_64[state];
428 fINSERT_RANGE(RddV, 8, 8, ((!state) ? (1 - valMPS) : (valMPS)));
429 fINSERT_RANGE(RddV, 31, 23, (rLPS >> 23));
430 fSETWORD(1, RddV, (offset - rMPS));
431 }
432 return RddV;
433}
434
435int32_t HELPER(cabacdecbin_pred)(int64_t RssV, int64_t RttV)
436{
437 int32_t p0 = 0;
438 size4u_t state;
439 size4u_t valMPS;
440 size4u_t bitpos;
441 size4u_t range;
442 size4u_t offset;
443 size4u_t rLPS;
444 size4u_t rMPS;
445
446 state = fEXTRACTU_RANGE(fGETWORD(1, RttV), 5, 0);
447 valMPS = fEXTRACTU_RANGE(fGETWORD(1, RttV), 8, 8);
448 bitpos = fEXTRACTU_RANGE(fGETWORD(0, RttV), 4, 0);
449 range = fGETWORD(0, RssV);
450 offset = fGETWORD(1, RssV);
451
452 /* calculate rLPS */
453 range <<= bitpos;
454 offset <<= bitpos;
455 rLPS = rLPS_table_64x4[state][(range >> 29) & 3];
456 rLPS = rLPS << 23; /* left aligned */
457
458 /* calculate rMPS */
459 rMPS = (range & 0xff800000) - rLPS;
460
461 /* most probable region */
462 if (offset < rMPS) {
463 p0 = valMPS;
464
465 }
466 /* least probable region */
467 else {
468 p0 = valMPS ^ 1;
469 }
470 return p0;
471}
472
7b84fd04 473static void probe_store(CPUHexagonState *env, int slot, int mmu_idx,
3bd83593 474 bool is_predicated, uintptr_t retaddr)
c23b5764 475{
7b84fd04 476 if (!is_predicated || !(env->slot_cancelled & (1 << slot))) {
c23b5764
TS
477 size1u_t width = env->mem_log_stores[slot].width;
478 target_ulong va = env->mem_log_stores[slot].va;
3bd83593 479 probe_write(env, va, width, mmu_idx, retaddr);
c23b5764
TS
480 }
481}
482
15fc6bad
TS
483/*
484 * Called from a mem_noshuf packet to make sure the load doesn't
485 * raise an exception
486 */
487void HELPER(probe_noshuf_load)(CPUHexagonState *env, target_ulong va,
488 int size, int mmu_idx)
489{
490 uintptr_t retaddr = GETPC();
491 probe_read(env, va, size, mmu_idx, retaddr);
492}
493
c23b5764 494/* Called during packet commit when there are two scalar stores */
7b84fd04 495void HELPER(probe_pkt_scalar_store_s0)(CPUHexagonState *env, int args)
c23b5764 496{
7b84fd04
TS
497 int mmu_idx = FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, MMU_IDX);
498 bool is_predicated =
499 FIELD_EX32(args, PROBE_PKT_SCALAR_STORE_S0, IS_PREDICATED);
3bd83593
MTB
500 uintptr_t ra = GETPC();
501 probe_store(env, 0, mmu_idx, is_predicated, ra);
c23b5764
TS
502}
503
3bd83593
MTB
504static void probe_hvx_stores(CPUHexagonState *env, int mmu_idx,
505 uintptr_t retaddr)
33e9ed11 506{
33e9ed11 507 /* Normal (possibly masked) vector store */
20c34a92 508 for (int i = 0; i < VSTORES_MAX; i++) {
33e9ed11
TS
509 if (env->vstore_pending[i]) {
510 target_ulong va = env->vstore[i].va;
511 int size = env->vstore[i].size;
512 for (int j = 0; j < size; j++) {
513 if (test_bit(j, env->vstore[i].mask)) {
514 probe_write(env, va + j, 1, mmu_idx, retaddr);
515 }
516 }
517 }
518 }
519
520 /* Scatter store */
521 if (env->vtcm_pending) {
522 if (env->vtcm_log.op) {
523 /* Need to perform the scatter read/modify/write at commit time */
524 if (env->vtcm_log.op_size == 2) {
525 SCATTER_OP_PROBE_MEM(size2u_t, mmu_idx, retaddr);
526 } else if (env->vtcm_log.op_size == 4) {
527 /* Word Scatter += */
528 SCATTER_OP_PROBE_MEM(size4u_t, mmu_idx, retaddr);
529 } else {
530 g_assert_not_reached();
531 }
532 } else {
533 for (int i = 0; i < sizeof(MMVector); i++) {
534 if (test_bit(i, env->vtcm_log.mask)) {
535 probe_write(env, env->vtcm_log.va[i], 1, mmu_idx, retaddr);
536 }
537
538 }
539 }
540 }
541}
542
3bd83593
MTB
543void HELPER(probe_hvx_stores)(CPUHexagonState *env, int mmu_idx)
544{
545 uintptr_t retaddr = GETPC();
546 probe_hvx_stores(env, mmu_idx, retaddr);
547}
548
2bda44e8 549void HELPER(probe_pkt_scalar_hvx_stores)(CPUHexagonState *env, int mask)
33e9ed11 550{
7b84fd04
TS
551 bool has_st0 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST0);
552 bool has_st1 = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_ST1);
553 bool has_hvx_stores =
554 FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, HAS_HVX_STORES);
555 bool s0_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S0_IS_PRED);
556 bool s1_is_pred = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, S1_IS_PRED);
2bda44e8 557 int mmu_idx = FIELD_EX32(mask, PROBE_PKT_SCALAR_HVX_STORES, MMU_IDX);
3bd83593 558 uintptr_t ra = GETPC();
33e9ed11
TS
559
560 if (has_st0) {
3bd83593 561 probe_store(env, 0, mmu_idx, s0_is_pred, ra);
33e9ed11
TS
562 }
563 if (has_st1) {
3bd83593 564 probe_store(env, 1, mmu_idx, s1_is_pred, ra);
33e9ed11
TS
565 }
566 if (has_hvx_stores) {
3bd83593 567 probe_hvx_stores(env, mmu_idx, ra);
33e9ed11
TS
568 }
569}
570
3bd83593 571#ifndef CONFIG_HEXAGON_IDEF_PARSER
b5ed786f
TS
572/*
573 * mem_noshuf
574 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
575 *
576 * If the load is in slot 0 and there is a store in slot1 (that
577 * wasn't cancelled), we have to do the store first.
578 */
e5d0d78d 579static void check_noshuf(CPUHexagonState *env, bool pkt_has_store_s1,
3bd83593
MTB
580 uint32_t slot, target_ulong vaddr, int size,
581 uintptr_t ra)
b5ed786f 582{
e5d0d78d 583 if (slot == 0 && pkt_has_store_s1 &&
b5ed786f 584 ((env->slot_cancelled & (1 << 1)) == 0)) {
3bd83593
MTB
585 probe_read(env, vaddr, size, MMU_USER_IDX, ra);
586 commit_store(env, 1, ra);
b5ed786f
TS
587 }
588}
3bd83593 589#endif
b5ed786f
TS
590
591/* Floating point */
592float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
593{
594 float64 out_f64;
595 arch_fpop_start(env);
596 out_f64 = float32_to_float64(RsV, &env->fp_status);
b5ed786f
TS
597 arch_fpop_end(env);
598 return out_f64;
599}
600
601float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
602{
603 float32 out_f32;
604 arch_fpop_start(env);
605 out_f32 = float64_to_float32(RssV, &env->fp_status);
b5ed786f
TS
606 arch_fpop_end(env);
607 return out_f32;
608}
609
610float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
611{
612 float32 RdV;
613 arch_fpop_start(env);
614 RdV = uint32_to_float32(RsV, &env->fp_status);
b5ed786f
TS
615 arch_fpop_end(env);
616 return RdV;
617}
618
619float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
620{
621 float64 RddV;
622 arch_fpop_start(env);
623 RddV = uint32_to_float64(RsV, &env->fp_status);
b5ed786f
TS
624 arch_fpop_end(env);
625 return RddV;
626}
627
628float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
629{
630 float32 RdV;
631 arch_fpop_start(env);
632 RdV = int32_to_float32(RsV, &env->fp_status);
b5ed786f
TS
633 arch_fpop_end(env);
634 return RdV;
635}
636
637float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
638{
639 float64 RddV;
640 arch_fpop_start(env);
641 RddV = int32_to_float64(RsV, &env->fp_status);
b5ed786f
TS
642 arch_fpop_end(env);
643 return RddV;
644}
645
646float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
647{
648 float32 RdV;
649 arch_fpop_start(env);
650 RdV = uint64_to_float32(RssV, &env->fp_status);
b5ed786f
TS
651 arch_fpop_end(env);
652 return RdV;
653}
654
655float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
656{
657 float64 RddV;
658 arch_fpop_start(env);
659 RddV = uint64_to_float64(RssV, &env->fp_status);
b5ed786f
TS
660 arch_fpop_end(env);
661 return RddV;
662}
663
664float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
665{
666 float32 RdV;
667 arch_fpop_start(env);
668 RdV = int64_to_float32(RssV, &env->fp_status);
b5ed786f
TS
669 arch_fpop_end(env);
670 return RdV;
671}
672
673float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
674{
675 float64 RddV;
676 arch_fpop_start(env);
677 RddV = int64_to_float64(RssV, &env->fp_status);
b5ed786f
TS
678 arch_fpop_end(env);
679 return RddV;
680}
681
b3f37abd 682uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
b5ed786f 683{
b3f37abd 684 uint32_t RdV;
b5ed786f 685 arch_fpop_start(env);
b3f37abd
TS
686 /* Hexagon checks the sign before rounding */
687 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
688 float_raise(float_flag_invalid, &env->fp_status);
689 RdV = 0;
690 } else {
691 RdV = float32_to_uint32(RsV, &env->fp_status);
692 }
b5ed786f
TS
693 arch_fpop_end(env);
694 return RdV;
695}
696
697int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
698{
699 int32_t RdV;
700 arch_fpop_start(env);
b3f37abd
TS
701 /* Hexagon returns -1 for NaN */
702 if (float32_is_any_nan(RsV)) {
703 float_raise(float_flag_invalid, &env->fp_status);
704 RdV = -1;
705 } else {
706 RdV = float32_to_int32(RsV, &env->fp_status);
707 }
b5ed786f
TS
708 arch_fpop_end(env);
709 return RdV;
710}
711
b3f37abd 712uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
b5ed786f 713{
b3f37abd 714 uint64_t RddV;
b5ed786f 715 arch_fpop_start(env);
b3f37abd
TS
716 /* Hexagon checks the sign before rounding */
717 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
718 float_raise(float_flag_invalid, &env->fp_status);
719 RddV = 0;
720 } else {
721 RddV = float32_to_uint64(RsV, &env->fp_status);
722 }
b5ed786f
TS
723 arch_fpop_end(env);
724 return RddV;
725}
726
727int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
728{
729 int64_t RddV;
730 arch_fpop_start(env);
b3f37abd
TS
731 /* Hexagon returns -1 for NaN */
732 if (float32_is_any_nan(RsV)) {
733 float_raise(float_flag_invalid, &env->fp_status);
734 RddV = -1;
735 } else {
736 RddV = float32_to_int64(RsV, &env->fp_status);
737 }
b5ed786f
TS
738 arch_fpop_end(env);
739 return RddV;
740}
741
b3f37abd 742uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
b5ed786f 743{
b3f37abd 744 uint32_t RdV;
b5ed786f 745 arch_fpop_start(env);
b3f37abd
TS
746 /* Hexagon checks the sign before rounding */
747 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
748 float_raise(float_flag_invalid, &env->fp_status);
749 RdV = 0;
750 } else {
751 RdV = float64_to_uint32(RssV, &env->fp_status);
752 }
b5ed786f
TS
753 arch_fpop_end(env);
754 return RdV;
755}
756
757int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
758{
759 int32_t RdV;
760 arch_fpop_start(env);
b3f37abd
TS
761 /* Hexagon returns -1 for NaN */
762 if (float64_is_any_nan(RssV)) {
763 float_raise(float_flag_invalid, &env->fp_status);
764 RdV = -1;
765 } else {
766 RdV = float64_to_int32(RssV, &env->fp_status);
767 }
b5ed786f
TS
768 arch_fpop_end(env);
769 return RdV;
770}
771
b3f37abd 772uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
b5ed786f 773{
b3f37abd 774 uint64_t RddV;
b5ed786f 775 arch_fpop_start(env);
b3f37abd
TS
776 /* Hexagon checks the sign before rounding */
777 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
778 float_raise(float_flag_invalid, &env->fp_status);
779 RddV = 0;
780 } else {
781 RddV = float64_to_uint64(RssV, &env->fp_status);
782 }
b5ed786f
TS
783 arch_fpop_end(env);
784 return RddV;
785}
786
787int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
788{
789 int64_t RddV;
790 arch_fpop_start(env);
b3f37abd
TS
791 /* Hexagon returns -1 for NaN */
792 if (float64_is_any_nan(RssV)) {
793 float_raise(float_flag_invalid, &env->fp_status);
794 RddV = -1;
795 } else {
796 RddV = float64_to_int64(RssV, &env->fp_status);
797 }
b5ed786f
TS
798 arch_fpop_end(env);
799 return RddV;
800}
801
b3f37abd 802uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
b5ed786f 803{
b3f37abd 804 uint32_t RdV;
b5ed786f 805 arch_fpop_start(env);
b3f37abd
TS
806 /* Hexagon checks the sign before rounding */
807 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
808 float_raise(float_flag_invalid, &env->fp_status);
809 RdV = 0;
810 } else {
811 RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
812 }
b5ed786f
TS
813 arch_fpop_end(env);
814 return RdV;
815}
816
817int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
818{
819 int32_t RdV;
820 arch_fpop_start(env);
b3f37abd
TS
821 /* Hexagon returns -1 for NaN */
822 if (float32_is_any_nan(RsV)) {
823 float_raise(float_flag_invalid, &env->fp_status);
824 RdV = -1;
825 } else {
826 RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
827 }
b5ed786f
TS
828 arch_fpop_end(env);
829 return RdV;
830}
831
b3f37abd 832uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
b5ed786f 833{
b3f37abd 834 uint64_t RddV;
b5ed786f 835 arch_fpop_start(env);
b3f37abd
TS
836 /* Hexagon checks the sign before rounding */
837 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
838 float_raise(float_flag_invalid, &env->fp_status);
839 RddV = 0;
840 } else {
841 RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
842 }
b5ed786f
TS
843 arch_fpop_end(env);
844 return RddV;
845}
846
847int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
848{
849 int64_t RddV;
850 arch_fpop_start(env);
b3f37abd
TS
851 /* Hexagon returns -1 for NaN */
852 if (float32_is_any_nan(RsV)) {
853 float_raise(float_flag_invalid, &env->fp_status);
854 RddV = -1;
855 } else {
856 RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
857 }
b5ed786f
TS
858 arch_fpop_end(env);
859 return RddV;
860}
861
b3f37abd 862uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
b5ed786f 863{
b3f37abd 864 uint32_t RdV;
b5ed786f 865 arch_fpop_start(env);
b3f37abd 866 /* Hexagon checks the sign before rounding */
3977ba30 867 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
b3f37abd
TS
868 float_raise(float_flag_invalid, &env->fp_status);
869 RdV = 0;
870 } else {
871 RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
872 }
b5ed786f
TS
873 arch_fpop_end(env);
874 return RdV;
875}
876
877int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
878{
879 int32_t RdV;
880 arch_fpop_start(env);
b3f37abd
TS
881 /* Hexagon returns -1 for NaN */
882 if (float64_is_any_nan(RssV)) {
883 float_raise(float_flag_invalid, &env->fp_status);
884 RdV = -1;
885 } else {
886 RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
887 }
b5ed786f
TS
888 arch_fpop_end(env);
889 return RdV;
890}
891
b3f37abd 892uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
b5ed786f 893{
b3f37abd 894 uint64_t RddV;
b5ed786f 895 arch_fpop_start(env);
b3f37abd
TS
896 /* Hexagon checks the sign before rounding */
897 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
898 float_raise(float_flag_invalid, &env->fp_status);
899 RddV = 0;
900 } else {
901 RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
902 }
b5ed786f
TS
903 arch_fpop_end(env);
904 return RddV;
905}
906
907int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
908{
909 int64_t RddV;
910 arch_fpop_start(env);
b3f37abd
TS
911 /* Hexagon returns -1 for NaN */
912 if (float64_is_any_nan(RssV)) {
913 float_raise(float_flag_invalid, &env->fp_status);
914 RddV = -1;
915 } else {
916 RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
917 }
b5ed786f
TS
918 arch_fpop_end(env);
919 return RddV;
920}
921
922float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
923{
924 float32 RdV;
925 arch_fpop_start(env);
926 RdV = float32_add(RsV, RtV, &env->fp_status);
b5ed786f
TS
927 arch_fpop_end(env);
928 return RdV;
929}
930
931float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
932{
933 float32 RdV;
934 arch_fpop_start(env);
935 RdV = float32_sub(RsV, RtV, &env->fp_status);
b5ed786f
TS
936 arch_fpop_end(env);
937 return RdV;
938}
939
940int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
941{
942 int32_t PdV;
943 arch_fpop_start(env);
944 PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
945 arch_fpop_end(env);
946 return PdV;
947}
948
949int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
950{
951 int cmp;
952 int32_t PdV;
953 arch_fpop_start(env);
954 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
955 PdV = f8BITSOF(cmp == float_relation_greater);
956 arch_fpop_end(env);
957 return PdV;
958}
959
960int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
961{
962 int cmp;
963 int32_t PdV;
964 arch_fpop_start(env);
965 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
966 PdV = f8BITSOF(cmp == float_relation_greater ||
967 cmp == float_relation_equal);
968 arch_fpop_end(env);
969 return PdV;
970}
971
972int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
973{
974 int32_t PdV;
975 arch_fpop_start(env);
9a659903 976 PdV = f8BITSOF(float32_unordered_quiet(RsV, RtV, &env->fp_status));
b5ed786f
TS
977 arch_fpop_end(env);
978 return PdV;
979}
980
981float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
982{
983 float32 RdV;
984 arch_fpop_start(env);
d76dd816 985 RdV = float32_maximum_number(RsV, RtV, &env->fp_status);
b5ed786f
TS
986 arch_fpop_end(env);
987 return RdV;
988}
989
990float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
991{
992 float32 RdV;
993 arch_fpop_start(env);
d76dd816 994 RdV = float32_minimum_number(RsV, RtV, &env->fp_status);
b5ed786f
TS
995 arch_fpop_end(env);
996 return RdV;
997}
998
999int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
1000{
1001 int32_t PdV = 0;
1002 arch_fpop_start(env);
1003 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
1004 PdV = 0xff;
1005 }
1006 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
1007 PdV = 0xff;
1008 }
1009 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
1010 PdV = 0xff;
1011 }
1012 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
1013 PdV = 0xff;
1014 }
1015 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
1016 PdV = 0xff;
1017 }
1018 set_float_exception_flags(0, &env->fp_status);
1019 arch_fpop_end(env);
1020 return PdV;
1021}
1022
1023float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
1024{
1025 float32 RdV = 0;
1026 int adjust;
1027 arch_fpop_start(env);
1028 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
1029 RdV = RsV;
1030 arch_fpop_end(env);
1031 return RdV;
1032}
1033
1034float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
1035{
1036 float32 RdV = 0;
1037 int adjust;
1038 arch_fpop_start(env);
1039 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
1040 RdV = RtV;
1041 arch_fpop_end(env);
1042 return RdV;
1043}
1044
1045float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
1046{
1047 float32 RdV = 0;
1048 int adjust;
1049 arch_fpop_start(env);
1050 arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
1051 RdV = RsV;
1052 arch_fpop_end(env);
1053 return RdV;
1054}
1055
1056float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
1057{
1058 float64 RddV;
1059 arch_fpop_start(env);
1060 RddV = float64_add(RssV, RttV, &env->fp_status);
b5ed786f
TS
1061 arch_fpop_end(env);
1062 return RddV;
1063}
1064
1065float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
1066{
1067 float64 RddV;
1068 arch_fpop_start(env);
1069 RddV = float64_sub(RssV, RttV, &env->fp_status);
b5ed786f
TS
1070 arch_fpop_end(env);
1071 return RddV;
1072}
1073
1074float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
1075{
1076 float64 RddV;
1077 arch_fpop_start(env);
d76dd816 1078 RddV = float64_maximum_number(RssV, RttV, &env->fp_status);
b5ed786f
TS
1079 arch_fpop_end(env);
1080 return RddV;
1081}
1082
1083float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
1084{
1085 float64 RddV;
1086 arch_fpop_start(env);
d76dd816 1087 RddV = float64_minimum_number(RssV, RttV, &env->fp_status);
b5ed786f
TS
1088 arch_fpop_end(env);
1089 return RddV;
1090}
1091
1092int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
1093{
1094 int32_t PdV;
1095 arch_fpop_start(env);
1096 PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
1097 arch_fpop_end(env);
1098 return PdV;
1099}
1100
1101int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
1102{
1103 int cmp;
1104 int32_t PdV;
1105 arch_fpop_start(env);
1106 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
1107 PdV = f8BITSOF(cmp == float_relation_greater);
1108 arch_fpop_end(env);
1109 return PdV;
1110}
1111
1112int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
1113{
1114 int cmp;
1115 int32_t PdV;
1116 arch_fpop_start(env);
1117 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
1118 PdV = f8BITSOF(cmp == float_relation_greater ||
1119 cmp == float_relation_equal);
1120 arch_fpop_end(env);
1121 return PdV;
1122}
1123
1124int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
1125{
1126 int32_t PdV;
1127 arch_fpop_start(env);
9a659903 1128 PdV = f8BITSOF(float64_unordered_quiet(RssV, RttV, &env->fp_status));
b5ed786f
TS
1129 arch_fpop_end(env);
1130 return PdV;
1131}
1132
1133int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
1134{
1135 int32_t PdV = 0;
1136 arch_fpop_start(env);
1137 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
1138 PdV = 0xff;
1139 }
1140 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
1141 PdV = 0xff;
1142 }
1143 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
1144 PdV = 0xff;
1145 }
1146 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
1147 PdV = 0xff;
1148 }
1149 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
1150 PdV = 0xff;
1151 }
1152 set_float_exception_flags(0, &env->fp_status);
1153 arch_fpop_end(env);
1154 return PdV;
1155}
1156
1157float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
1158{
1159 float32 RdV;
1160 arch_fpop_start(env);
1161 RdV = internal_mpyf(RsV, RtV, &env->fp_status);
b5ed786f
TS
1162 arch_fpop_end(env);
1163 return RdV;
1164}
1165
1166float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
1167 float32 RsV, float32 RtV)
1168{
1169 arch_fpop_start(env);
1170 RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
b5ed786f
TS
1171 arch_fpop_end(env);
1172 return RxV;
1173}
1174
1175static bool is_zero_prod(float32 a, float32 b)
1176{
1177 return ((float32_is_zero(a) && is_finite(b)) ||
1178 (float32_is_zero(b) && is_finite(a)));
1179}
1180
1181static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
1182{
1183 float32 ret = dst;
1184 if (float32_is_any_nan(x)) {
1185 if (extract32(x, 22, 1) == 0) {
1186 float_raise(float_flag_invalid, fp_status);
1187 }
1188 ret = make_float32(0xffffffff); /* nan */
1189 }
1190 return ret;
1191}
1192
1193float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
1194 float32 RsV, float32 RtV, float32 PuV)
1195{
1196 size4s_t tmp;
1197 arch_fpop_start(env);
1198 RxV = check_nan(RxV, RxV, &env->fp_status);
1199 RxV = check_nan(RxV, RsV, &env->fp_status);
1200 RxV = check_nan(RxV, RtV, &env->fp_status);
1201 tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
b5ed786f
TS
1202 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1203 RxV = tmp;
1204 }
1205 arch_fpop_end(env);
1206 return RxV;
1207}
1208
1209float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
1210 float32 RsV, float32 RtV)
1211{
1212 float32 neg_RsV;
1213 arch_fpop_start(env);
1a442c09 1214 neg_RsV = float32_set_sign(RsV, float32_is_neg(RsV) ? 0 : 1);
b5ed786f 1215 RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
b5ed786f
TS
1216 arch_fpop_end(env);
1217 return RxV;
1218}
1219
2d27cebb 1220static bool is_inf_prod(int32_t a, int32_t b)
b5ed786f
TS
1221{
1222 return (float32_is_infinity(a) && float32_is_infinity(b)) ||
1223 (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
1224 (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
1225}
1226
1227float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
1228 float32 RsV, float32 RtV)
1229{
92cfa25f
TS
1230 bool infinp;
1231 bool infminusinf;
b5ed786f
TS
1232 float32 tmp;
1233
1234 arch_fpop_start(env);
1235 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1236 infminusinf = float32_is_infinity(RxV) &&
1237 is_inf_prod(RsV, RtV) &&
1238 (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
1239 infinp = float32_is_infinity(RxV) ||
1240 float32_is_infinity(RtV) ||
1241 float32_is_infinity(RsV);
1242 RxV = check_nan(RxV, RxV, &env->fp_status);
1243 RxV = check_nan(RxV, RsV, &env->fp_status);
1244 RxV = check_nan(RxV, RtV, &env->fp_status);
1245 tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
b5ed786f
TS
1246 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1247 RxV = tmp;
1248 }
1249 set_float_exception_flags(0, &env->fp_status);
1250 if (float32_is_infinity(RxV) && !infinp) {
1251 RxV = RxV - 1;
1252 }
1253 if (infminusinf) {
1254 RxV = 0;
1255 }
1256 arch_fpop_end(env);
1257 return RxV;
1258}
1259
1260float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
1261 float32 RsV, float32 RtV)
1262{
92cfa25f
TS
1263 bool infinp;
1264 bool infminusinf;
b5ed786f
TS
1265 float32 tmp;
1266
1267 arch_fpop_start(env);
1268 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1269 infminusinf = float32_is_infinity(RxV) &&
1270 is_inf_prod(RsV, RtV) &&
1271 (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
1272 infinp = float32_is_infinity(RxV) ||
1273 float32_is_infinity(RtV) ||
1274 float32_is_infinity(RsV);
1275 RxV = check_nan(RxV, RxV, &env->fp_status);
1276 RxV = check_nan(RxV, RsV, &env->fp_status);
1277 RxV = check_nan(RxV, RtV, &env->fp_status);
1278 float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1279 tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
b5ed786f
TS
1280 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1281 RxV = tmp;
1282 }
1283 set_float_exception_flags(0, &env->fp_status);
1284 if (float32_is_infinity(RxV) && !infinp) {
1285 RxV = RxV - 1;
1286 }
1287 if (infminusinf) {
1288 RxV = 0;
1289 }
1290 arch_fpop_end(env);
1291 return RxV;
1292}
1293
1294float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
1295{
1296 int64_t RddV;
1297 arch_fpop_start(env);
1298 if (float64_is_denormal(RssV) &&
1299 (float64_getexp(RttV) >= 512) &&
1300 float64_is_normal(RttV)) {
1301 RddV = float64_mul(RssV, make_float64(0x4330000000000000),
1302 &env->fp_status);
b5ed786f
TS
1303 } else if (float64_is_denormal(RttV) &&
1304 (float64_getexp(RssV) >= 512) &&
1305 float64_is_normal(RssV)) {
1306 RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
1307 &env->fp_status);
b5ed786f
TS
1308 } else {
1309 RddV = RssV;
1310 }
1311 arch_fpop_end(env);
1312 return RddV;
1313}
1314
1315float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1316 float64 RssV, float64 RttV)
1317{
1318 arch_fpop_start(env);
1319 RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
b5ed786f
TS
1320 arch_fpop_end(env);
1321 return RxxV;
1322}
1323
33e9ed11
TS
1324/* Histogram instructions */
1325
1326void HELPER(vhist)(CPUHexagonState *env)
1327{
1328 MMVector *input = &env->tmp_VRegs[0];
1329
1330 for (int lane = 0; lane < 8; lane++) {
1331 for (int i = 0; i < sizeof(MMVector) / 8; ++i) {
1332 unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i];
1333 unsigned char regno = value >> 3;
1334 unsigned char element = value & 7;
1335
1336 env->VRegs[regno].uh[(sizeof(MMVector) / 16) * lane + element]++;
1337 }
1338 }
1339}
1340
1341void HELPER(vhistq)(CPUHexagonState *env)
1342{
1343 MMVector *input = &env->tmp_VRegs[0];
1344
1345 for (int lane = 0; lane < 8; lane++) {
1346 for (int i = 0; i < sizeof(MMVector) / 8; ++i) {
1347 unsigned char value = input->ub[(sizeof(MMVector) / 8) * lane + i];
1348 unsigned char regno = value >> 3;
1349 unsigned char element = value & 7;
1350
1351 if (fGETQBIT(env->qtmp, sizeof(MMVector) / 8 * lane + i)) {
1352 env->VRegs[regno].uh[
1353 (sizeof(MMVector) / 16) * lane + element]++;
1354 }
1355 }
1356 }
1357}
1358
1359void HELPER(vwhist256)(CPUHexagonState *env)
1360{
1361 MMVector *input = &env->tmp_VRegs[0];
1362
1363 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1364 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1365 unsigned int weight = fGETUBYTE(1, input->h[i]);
1366 unsigned int vindex = (bucket >> 3) & 0x1F;
1367 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1368
1369 env->VRegs[vindex].uh[elindex] =
1370 env->VRegs[vindex].uh[elindex] + weight;
1371 }
1372}
1373
1374void HELPER(vwhist256q)(CPUHexagonState *env)
1375{
1376 MMVector *input = &env->tmp_VRegs[0];
1377
1378 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1379 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1380 unsigned int weight = fGETUBYTE(1, input->h[i]);
1381 unsigned int vindex = (bucket >> 3) & 0x1F;
1382 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1383
1384 if (fGETQBIT(env->qtmp, 2 * i)) {
1385 env->VRegs[vindex].uh[elindex] =
1386 env->VRegs[vindex].uh[elindex] + weight;
1387 }
1388 }
1389}
1390
1391void HELPER(vwhist256_sat)(CPUHexagonState *env)
1392{
1393 MMVector *input = &env->tmp_VRegs[0];
1394
1395 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1396 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1397 unsigned int weight = fGETUBYTE(1, input->h[i]);
1398 unsigned int vindex = (bucket >> 3) & 0x1F;
1399 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1400
1401 env->VRegs[vindex].uh[elindex] =
1402 fVSATUH(env->VRegs[vindex].uh[elindex] + weight);
1403 }
1404}
1405
1406void HELPER(vwhist256q_sat)(CPUHexagonState *env)
1407{
1408 MMVector *input = &env->tmp_VRegs[0];
1409
1410 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1411 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1412 unsigned int weight = fGETUBYTE(1, input->h[i]);
1413 unsigned int vindex = (bucket >> 3) & 0x1F;
1414 unsigned int elindex = ((i >> 0) & (~7)) | ((bucket >> 0) & 7);
1415
1416 if (fGETQBIT(env->qtmp, 2 * i)) {
1417 env->VRegs[vindex].uh[elindex] =
1418 fVSATUH(env->VRegs[vindex].uh[elindex] + weight);
1419 }
1420 }
1421}
1422
1423void HELPER(vwhist128)(CPUHexagonState *env)
1424{
1425 MMVector *input = &env->tmp_VRegs[0];
1426
1427 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1428 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1429 unsigned int weight = fGETUBYTE(1, input->h[i]);
1430 unsigned int vindex = (bucket >> 3) & 0x1F;
1431 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1432
1433 env->VRegs[vindex].uw[elindex] =
1434 env->VRegs[vindex].uw[elindex] + weight;
1435 }
1436}
1437
1438void HELPER(vwhist128q)(CPUHexagonState *env)
1439{
1440 MMVector *input = &env->tmp_VRegs[0];
1441
1442 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1443 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1444 unsigned int weight = fGETUBYTE(1, input->h[i]);
1445 unsigned int vindex = (bucket >> 3) & 0x1F;
1446 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1447
1448 if (fGETQBIT(env->qtmp, 2 * i)) {
1449 env->VRegs[vindex].uw[elindex] =
1450 env->VRegs[vindex].uw[elindex] + weight;
1451 }
1452 }
1453}
1454
1455void HELPER(vwhist128m)(CPUHexagonState *env, int32_t uiV)
1456{
1457 MMVector *input = &env->tmp_VRegs[0];
1458
1459 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1460 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1461 unsigned int weight = fGETUBYTE(1, input->h[i]);
1462 unsigned int vindex = (bucket >> 3) & 0x1F;
1463 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1464
1465 if ((bucket & 1) == uiV) {
1466 env->VRegs[vindex].uw[elindex] =
1467 env->VRegs[vindex].uw[elindex] + weight;
1468 }
1469 }
1470}
1471
1472void HELPER(vwhist128qm)(CPUHexagonState *env, int32_t uiV)
1473{
1474 MMVector *input = &env->tmp_VRegs[0];
1475
1476 for (int i = 0; i < (sizeof(MMVector) / 2); i++) {
1477 unsigned int bucket = fGETUBYTE(0, input->h[i]);
1478 unsigned int weight = fGETUBYTE(1, input->h[i]);
1479 unsigned int vindex = (bucket >> 3) & 0x1F;
1480 unsigned int elindex = ((i >> 1) & (~3)) | ((bucket >> 1) & 3);
1481
1482 if (((bucket & 1) == uiV) && fGETQBIT(env->qtmp, 2 * i)) {
1483 env->VRegs[vindex].uw[elindex] =
1484 env->VRegs[vindex].uw[elindex] + weight;
1485 }
1486 }
1487}
1488
b5ed786f
TS
1489/* These macros can be referenced in the generated helper functions */
1490#define warn(...) /* Nothing */
1491#define fatal(...) g_assert_not_reached();
1492
1493#define BOGUS_HELPER(tag) \
1494 printf("ERROR: bogus helper: " #tag "\n")
1495
1496#include "helper_funcs_generated.c.inc"