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