Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-migration-20210726a...
[qemu/armbru.git] / target / hexagon / op_helper.c
blob61d5cde939a3297624d264ea4fd56f5779ef543a
1 /*
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"
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"
31 #define SF_BIAS 127
32 #define SF_MANTBITS 23
34 /* Exceptions processing helpers */
35 static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
36 uint32_t exception,
37 uintptr_t pc)
39 CPUState *cs = env_cpu(env);
40 qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
41 cs->exception_index = exception;
42 cpu_loop_exit_restore(cs, pc);
45 void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
47 do_raise_exception_err(env, excp, 0);
50 static void log_reg_write(CPUHexagonState *env, int rnum,
51 target_ulong val, uint32_t slot)
53 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
54 rnum, val, val);
55 if (val == env->gpr[rnum]) {
56 HEX_DEBUG_LOG(" NO CHANGE");
58 HEX_DEBUG_LOG("\n");
60 env->new_value[rnum] = val;
61 if (HEX_DEBUG) {
62 /* Do this so HELPER(debug_commit_end) will know */
63 env->reg_written[rnum] = 1;
67 static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
69 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
70 " (0x" TARGET_FMT_lx ")\n",
71 pnum, val, val);
73 /* Multiple writes to the same preg are and'ed together */
74 if (env->pred_written & (1 << pnum)) {
75 env->new_pred_value[pnum] &= val & 0xff;
76 } else {
77 env->new_pred_value[pnum] = val & 0xff;
78 env->pred_written |= 1 << pnum;
82 static void log_store32(CPUHexagonState *env, target_ulong addr,
83 target_ulong val, int width, int slot)
85 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
86 ", %" PRId32 " [0x08%" PRIx32 "])\n",
87 width, addr, val, val);
88 env->mem_log_stores[slot].va = addr;
89 env->mem_log_stores[slot].width = width;
90 env->mem_log_stores[slot].data32 = val;
93 static void log_store64(CPUHexagonState *env, target_ulong addr,
94 int64_t val, int width, int slot)
96 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
97 ", %" PRId64 " [0x016%" PRIx64 "])\n",
98 width, addr, val, val);
99 env->mem_log_stores[slot].va = addr;
100 env->mem_log_stores[slot].width = width;
101 env->mem_log_stores[slot].data64 = val;
104 static void write_new_pc(CPUHexagonState *env, target_ulong addr)
106 HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
109 * If more than one branch is taken in a packet, only the first one
110 * is actually done.
112 if (env->branch_taken) {
113 HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
114 "ignoring the second one\n");
115 } else {
116 fCHECK_PCALIGN(addr);
117 env->branch_taken = 1;
118 env->next_PC = addr;
122 /* Handy place to set a breakpoint */
123 void HELPER(debug_start_packet)(CPUHexagonState *env)
125 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
126 env->gpr[HEX_REG_PC]);
128 for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
129 env->reg_written[i] = 0;
133 /* Checks for bookkeeping errors between disassembly context and runtime */
134 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
136 if (env->mem_log_stores[slot].width != check) {
137 HEX_DEBUG_LOG("ERROR: %d != %d\n",
138 env->mem_log_stores[slot].width, check);
139 g_assert_not_reached();
143 void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
145 uintptr_t ra = GETPC();
146 uint8_t width = env->mem_log_stores[slot_num].width;
147 target_ulong va = env->mem_log_stores[slot_num].va;
149 switch (width) {
150 case 1:
151 cpu_stb_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
152 break;
153 case 2:
154 cpu_stw_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
155 break;
156 case 4:
157 cpu_stl_data_ra(env, va, env->mem_log_stores[slot_num].data32, ra);
158 break;
159 case 8:
160 cpu_stq_data_ra(env, va, env->mem_log_stores[slot_num].data64, ra);
161 break;
162 default:
163 g_assert_not_reached();
167 static void print_store(CPUHexagonState *env, int slot)
169 if (!(env->slot_cancelled & (1 << slot))) {
170 uint8_t width = env->mem_log_stores[slot].width;
171 if (width == 1) {
172 uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
173 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
174 " (0x%02" PRIx32 ")\n",
175 env->mem_log_stores[slot].va, data, data);
176 } else if (width == 2) {
177 uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
178 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
179 " (0x%04" PRIx32 ")\n",
180 env->mem_log_stores[slot].va, data, data);
181 } else if (width == 4) {
182 uint32_t data = env->mem_log_stores[slot].data32;
183 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
184 " (0x%08" PRIx32 ")\n",
185 env->mem_log_stores[slot].va, data, data);
186 } else if (width == 8) {
187 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
188 " (0x%016" PRIx64 ")\n",
189 env->mem_log_stores[slot].va,
190 env->mem_log_stores[slot].data64,
191 env->mem_log_stores[slot].data64);
192 } else {
193 HEX_DEBUG_LOG("\tBad store width %d\n", width);
194 g_assert_not_reached();
199 /* This function is a handy place to set a breakpoint */
200 void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
202 bool reg_printed = false;
203 bool pred_printed = false;
204 int i;
206 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n",
207 env->this_PC);
208 HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
210 for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
211 if (env->reg_written[i]) {
212 if (!reg_printed) {
213 HEX_DEBUG_LOG("Regs written\n");
214 reg_printed = true;
216 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
217 i, env->new_value[i], env->new_value[i]);
221 for (i = 0; i < NUM_PREGS; i++) {
222 if (env->pred_written & (1 << i)) {
223 if (!pred_printed) {
224 HEX_DEBUG_LOG("Predicates written\n");
225 pred_printed = true;
227 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
228 i, env->new_pred_value[i]);
232 if (has_st0 || has_st1) {
233 HEX_DEBUG_LOG("Stores\n");
234 if (has_st0) {
235 print_store(env, 0);
237 if (has_st1) {
238 print_store(env, 1);
242 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC);
243 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
244 ", insn = " TARGET_FMT_lx
245 "\n",
246 env->gpr[HEX_REG_QEMU_PKT_CNT],
247 env->gpr[HEX_REG_QEMU_INSN_CNT]);
251 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
253 int32_t K_const = sextract32(M, 24, 4);
254 int32_t length = sextract32(M, 0, 17);
255 uint32_t new_ptr = RxV + offset;
256 uint32_t start_addr;
257 uint32_t end_addr;
259 if (K_const == 0 && length >= 4) {
260 start_addr = CS;
261 end_addr = start_addr + length;
262 } else {
264 * Versions v3 and earlier used the K value to specify a power-of-2 size
265 * 2^(K+2) that is greater than the buffer length
267 int32_t mask = (1 << (K_const + 2)) - 1;
268 start_addr = RxV & (~mask);
269 end_addr = start_addr | length;
272 if (new_ptr >= end_addr) {
273 new_ptr -= length;
274 } else if (new_ptr < start_addr) {
275 new_ptr += length;
278 return new_ptr;
281 uint32_t HELPER(fbrev)(uint32_t addr)
284 * Bit reverse the low 16 bits of the address
286 return deposit32(addr, 0, 16, revbit16(addr));
289 static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
291 return make_float32(
292 ((sign & 1) << 31) |
293 ((exp & 0xff) << SF_MANTBITS) |
294 (mant & ((1 << SF_MANTBITS) - 1)));
298 * sfrecipa, sfinvsqrta have two 32-bit results
299 * r0,p0=sfrecipa(r1,r2)
300 * r0,p0=sfinvsqrta(r1)
302 * Since helpers can only return a single value, we pack the two results
303 * into a 64-bit value.
305 uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
307 int32_t PeV = 0;
308 float32 RdV;
309 int idx;
310 int adjust;
311 int mant;
312 int exp;
314 arch_fpop_start(env);
315 if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
316 PeV = adjust;
317 idx = (RtV >> 16) & 0x7f;
318 mant = (recip_lookup_table[idx] << 15) | 1;
319 exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
320 RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
322 arch_fpop_end(env);
323 return ((uint64_t)RdV << 32) | PeV;
326 uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
328 int PeV = 0;
329 float32 RdV;
330 int idx;
331 int adjust;
332 int mant;
333 int exp;
335 arch_fpop_start(env);
336 if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
337 PeV = adjust;
338 idx = (RsV >> 17) & 0x7f;
339 mant = (invsqrt_lookup_table[idx] << 15);
340 exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
341 RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
343 arch_fpop_end(env);
344 return ((uint64_t)RdV << 32) | PeV;
347 int64_t HELPER(vacsh_val)(CPUHexagonState *env,
348 int64_t RxxV, int64_t RssV, int64_t RttV)
350 for (int i = 0; i < 4; i++) {
351 int xv = sextract64(RxxV, i * 16, 16);
352 int sv = sextract64(RssV, i * 16, 16);
353 int tv = sextract64(RttV, i * 16, 16);
354 int max;
355 xv = xv + tv;
356 sv = sv - tv;
357 max = xv > sv ? xv : sv;
358 /* Note that fSATH can set the OVF bit in usr */
359 RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
361 return RxxV;
364 int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
365 int64_t RxxV, int64_t RssV, int64_t RttV)
367 int32_t PeV = 0;
368 for (int i = 0; i < 4; i++) {
369 int xv = sextract64(RxxV, i * 16, 16);
370 int sv = sextract64(RssV, i * 16, 16);
371 int tv = sextract64(RttV, i * 16, 16);
372 xv = xv + tv;
373 sv = sv - tv;
374 PeV = deposit32(PeV, i * 2, 1, (xv > sv));
375 PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
377 return PeV;
381 * mem_noshuf
382 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
384 * If the load is in slot 0 and there is a store in slot1 (that
385 * wasn't cancelled), we have to do the store first.
387 static void check_noshuf(CPUHexagonState *env, uint32_t slot)
389 if (slot == 0 && env->pkt_has_store_s1 &&
390 ((env->slot_cancelled & (1 << 1)) == 0)) {
391 HELPER(commit_store)(env, 1);
395 static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
396 target_ulong vaddr)
398 uintptr_t ra = GETPC();
399 check_noshuf(env, slot);
400 return cpu_ldub_data_ra(env, vaddr, ra);
403 static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
404 target_ulong vaddr)
406 uintptr_t ra = GETPC();
407 check_noshuf(env, slot);
408 return cpu_lduw_data_ra(env, vaddr, ra);
411 static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
412 target_ulong vaddr)
414 uintptr_t ra = GETPC();
415 check_noshuf(env, slot);
416 return cpu_ldl_data_ra(env, vaddr, ra);
419 static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
420 target_ulong vaddr)
422 uintptr_t ra = GETPC();
423 check_noshuf(env, slot);
424 return cpu_ldq_data_ra(env, vaddr, ra);
427 /* Floating point */
428 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
430 float64 out_f64;
431 arch_fpop_start(env);
432 out_f64 = float32_to_float64(RsV, &env->fp_status);
433 arch_fpop_end(env);
434 return out_f64;
437 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
439 float32 out_f32;
440 arch_fpop_start(env);
441 out_f32 = float64_to_float32(RssV, &env->fp_status);
442 arch_fpop_end(env);
443 return out_f32;
446 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
448 float32 RdV;
449 arch_fpop_start(env);
450 RdV = uint32_to_float32(RsV, &env->fp_status);
451 arch_fpop_end(env);
452 return RdV;
455 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
457 float64 RddV;
458 arch_fpop_start(env);
459 RddV = uint32_to_float64(RsV, &env->fp_status);
460 arch_fpop_end(env);
461 return RddV;
464 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
466 float32 RdV;
467 arch_fpop_start(env);
468 RdV = int32_to_float32(RsV, &env->fp_status);
469 arch_fpop_end(env);
470 return RdV;
473 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
475 float64 RddV;
476 arch_fpop_start(env);
477 RddV = int32_to_float64(RsV, &env->fp_status);
478 arch_fpop_end(env);
479 return RddV;
482 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
484 float32 RdV;
485 arch_fpop_start(env);
486 RdV = uint64_to_float32(RssV, &env->fp_status);
487 arch_fpop_end(env);
488 return RdV;
491 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
493 float64 RddV;
494 arch_fpop_start(env);
495 RddV = uint64_to_float64(RssV, &env->fp_status);
496 arch_fpop_end(env);
497 return RddV;
500 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
502 float32 RdV;
503 arch_fpop_start(env);
504 RdV = int64_to_float32(RssV, &env->fp_status);
505 arch_fpop_end(env);
506 return RdV;
509 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
511 float64 RddV;
512 arch_fpop_start(env);
513 RddV = int64_to_float64(RssV, &env->fp_status);
514 arch_fpop_end(env);
515 return RddV;
518 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
520 uint32_t RdV;
521 arch_fpop_start(env);
522 /* Hexagon checks the sign before rounding */
523 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
524 float_raise(float_flag_invalid, &env->fp_status);
525 RdV = 0;
526 } else {
527 RdV = float32_to_uint32(RsV, &env->fp_status);
529 arch_fpop_end(env);
530 return RdV;
533 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
535 int32_t RdV;
536 arch_fpop_start(env);
537 /* Hexagon returns -1 for NaN */
538 if (float32_is_any_nan(RsV)) {
539 float_raise(float_flag_invalid, &env->fp_status);
540 RdV = -1;
541 } else {
542 RdV = float32_to_int32(RsV, &env->fp_status);
544 arch_fpop_end(env);
545 return RdV;
548 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
550 uint64_t RddV;
551 arch_fpop_start(env);
552 /* Hexagon checks the sign before rounding */
553 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
554 float_raise(float_flag_invalid, &env->fp_status);
555 RddV = 0;
556 } else {
557 RddV = float32_to_uint64(RsV, &env->fp_status);
559 arch_fpop_end(env);
560 return RddV;
563 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
565 int64_t RddV;
566 arch_fpop_start(env);
567 /* Hexagon returns -1 for NaN */
568 if (float32_is_any_nan(RsV)) {
569 float_raise(float_flag_invalid, &env->fp_status);
570 RddV = -1;
571 } else {
572 RddV = float32_to_int64(RsV, &env->fp_status);
574 arch_fpop_end(env);
575 return RddV;
578 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
580 uint32_t RdV;
581 arch_fpop_start(env);
582 /* Hexagon checks the sign before rounding */
583 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
584 float_raise(float_flag_invalid, &env->fp_status);
585 RdV = 0;
586 } else {
587 RdV = float64_to_uint32(RssV, &env->fp_status);
589 arch_fpop_end(env);
590 return RdV;
593 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
595 int32_t RdV;
596 arch_fpop_start(env);
597 /* Hexagon returns -1 for NaN */
598 if (float64_is_any_nan(RssV)) {
599 float_raise(float_flag_invalid, &env->fp_status);
600 RdV = -1;
601 } else {
602 RdV = float64_to_int32(RssV, &env->fp_status);
604 arch_fpop_end(env);
605 return RdV;
608 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
610 uint64_t RddV;
611 arch_fpop_start(env);
612 /* Hexagon checks the sign before rounding */
613 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
614 float_raise(float_flag_invalid, &env->fp_status);
615 RddV = 0;
616 } else {
617 RddV = float64_to_uint64(RssV, &env->fp_status);
619 arch_fpop_end(env);
620 return RddV;
623 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
625 int64_t RddV;
626 arch_fpop_start(env);
627 /* Hexagon returns -1 for NaN */
628 if (float64_is_any_nan(RssV)) {
629 float_raise(float_flag_invalid, &env->fp_status);
630 RddV = -1;
631 } else {
632 RddV = float64_to_int64(RssV, &env->fp_status);
634 arch_fpop_end(env);
635 return RddV;
638 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
640 uint32_t RdV;
641 arch_fpop_start(env);
642 /* Hexagon checks the sign before rounding */
643 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
644 float_raise(float_flag_invalid, &env->fp_status);
645 RdV = 0;
646 } else {
647 RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
649 arch_fpop_end(env);
650 return RdV;
653 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
655 int32_t RdV;
656 arch_fpop_start(env);
657 /* Hexagon returns -1 for NaN */
658 if (float32_is_any_nan(RsV)) {
659 float_raise(float_flag_invalid, &env->fp_status);
660 RdV = -1;
661 } else {
662 RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
664 arch_fpop_end(env);
665 return RdV;
668 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
670 uint64_t RddV;
671 arch_fpop_start(env);
672 /* Hexagon checks the sign before rounding */
673 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
674 float_raise(float_flag_invalid, &env->fp_status);
675 RddV = 0;
676 } else {
677 RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
679 arch_fpop_end(env);
680 return RddV;
683 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
685 int64_t RddV;
686 arch_fpop_start(env);
687 /* Hexagon returns -1 for NaN */
688 if (float32_is_any_nan(RsV)) {
689 float_raise(float_flag_invalid, &env->fp_status);
690 RddV = -1;
691 } else {
692 RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
694 arch_fpop_end(env);
695 return RddV;
698 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
700 uint32_t RdV;
701 arch_fpop_start(env);
702 /* Hexagon checks the sign before rounding */
703 if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
704 float_raise(float_flag_invalid, &env->fp_status);
705 RdV = 0;
706 } else {
707 RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
709 arch_fpop_end(env);
710 return RdV;
713 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
715 int32_t RdV;
716 arch_fpop_start(env);
717 /* Hexagon returns -1 for NaN */
718 if (float64_is_any_nan(RssV)) {
719 float_raise(float_flag_invalid, &env->fp_status);
720 RdV = -1;
721 } else {
722 RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
724 arch_fpop_end(env);
725 return RdV;
728 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
730 uint64_t RddV;
731 arch_fpop_start(env);
732 /* Hexagon checks the sign before rounding */
733 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
734 float_raise(float_flag_invalid, &env->fp_status);
735 RddV = 0;
736 } else {
737 RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
739 arch_fpop_end(env);
740 return RddV;
743 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
745 int64_t RddV;
746 arch_fpop_start(env);
747 /* Hexagon returns -1 for NaN */
748 if (float64_is_any_nan(RssV)) {
749 float_raise(float_flag_invalid, &env->fp_status);
750 RddV = -1;
751 } else {
752 RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
754 arch_fpop_end(env);
755 return RddV;
758 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
760 float32 RdV;
761 arch_fpop_start(env);
762 RdV = float32_add(RsV, RtV, &env->fp_status);
763 arch_fpop_end(env);
764 return RdV;
767 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
769 float32 RdV;
770 arch_fpop_start(env);
771 RdV = float32_sub(RsV, RtV, &env->fp_status);
772 arch_fpop_end(env);
773 return RdV;
776 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
778 int32_t PdV;
779 arch_fpop_start(env);
780 PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
781 arch_fpop_end(env);
782 return PdV;
785 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
787 int cmp;
788 int32_t PdV;
789 arch_fpop_start(env);
790 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
791 PdV = f8BITSOF(cmp == float_relation_greater);
792 arch_fpop_end(env);
793 return PdV;
796 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
798 int cmp;
799 int32_t PdV;
800 arch_fpop_start(env);
801 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
802 PdV = f8BITSOF(cmp == float_relation_greater ||
803 cmp == float_relation_equal);
804 arch_fpop_end(env);
805 return PdV;
808 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
810 int32_t PdV;
811 arch_fpop_start(env);
812 PdV = f8BITSOF(float32_is_any_nan(RsV) ||
813 float32_is_any_nan(RtV));
814 arch_fpop_end(env);
815 return PdV;
818 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
820 float32 RdV;
821 arch_fpop_start(env);
822 RdV = float32_maxnum(RsV, RtV, &env->fp_status);
823 arch_fpop_end(env);
824 return RdV;
827 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
829 float32 RdV;
830 arch_fpop_start(env);
831 RdV = float32_minnum(RsV, RtV, &env->fp_status);
832 arch_fpop_end(env);
833 return RdV;
836 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
838 int32_t PdV = 0;
839 arch_fpop_start(env);
840 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
841 PdV = 0xff;
843 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
844 PdV = 0xff;
846 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
847 PdV = 0xff;
849 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
850 PdV = 0xff;
852 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
853 PdV = 0xff;
855 set_float_exception_flags(0, &env->fp_status);
856 arch_fpop_end(env);
857 return PdV;
860 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
862 float32 RdV = 0;
863 int adjust;
864 arch_fpop_start(env);
865 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
866 RdV = RsV;
867 arch_fpop_end(env);
868 return RdV;
871 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
873 float32 RdV = 0;
874 int adjust;
875 arch_fpop_start(env);
876 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
877 RdV = RtV;
878 arch_fpop_end(env);
879 return RdV;
882 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
884 float32 RdV = 0;
885 int adjust;
886 arch_fpop_start(env);
887 arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
888 RdV = RsV;
889 arch_fpop_end(env);
890 return RdV;
893 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
895 float64 RddV;
896 arch_fpop_start(env);
897 RddV = float64_add(RssV, RttV, &env->fp_status);
898 arch_fpop_end(env);
899 return RddV;
902 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
904 float64 RddV;
905 arch_fpop_start(env);
906 RddV = float64_sub(RssV, RttV, &env->fp_status);
907 arch_fpop_end(env);
908 return RddV;
911 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
913 float64 RddV;
914 arch_fpop_start(env);
915 RddV = float64_maxnum(RssV, RttV, &env->fp_status);
916 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
917 float_raise(float_flag_invalid, &env->fp_status);
919 arch_fpop_end(env);
920 return RddV;
923 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
925 float64 RddV;
926 arch_fpop_start(env);
927 RddV = float64_minnum(RssV, RttV, &env->fp_status);
928 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
929 float_raise(float_flag_invalid, &env->fp_status);
931 arch_fpop_end(env);
932 return RddV;
935 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
937 int32_t PdV;
938 arch_fpop_start(env);
939 PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
940 arch_fpop_end(env);
941 return PdV;
944 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
946 int cmp;
947 int32_t PdV;
948 arch_fpop_start(env);
949 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
950 PdV = f8BITSOF(cmp == float_relation_greater);
951 arch_fpop_end(env);
952 return PdV;
955 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
957 int cmp;
958 int32_t PdV;
959 arch_fpop_start(env);
960 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
961 PdV = f8BITSOF(cmp == float_relation_greater ||
962 cmp == float_relation_equal);
963 arch_fpop_end(env);
964 return PdV;
967 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
969 int32_t PdV;
970 arch_fpop_start(env);
971 PdV = f8BITSOF(float64_is_any_nan(RssV) ||
972 float64_is_any_nan(RttV));
973 arch_fpop_end(env);
974 return PdV;
977 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
979 int32_t PdV = 0;
980 arch_fpop_start(env);
981 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
982 PdV = 0xff;
984 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
985 PdV = 0xff;
987 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
988 PdV = 0xff;
990 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
991 PdV = 0xff;
993 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
994 PdV = 0xff;
996 set_float_exception_flags(0, &env->fp_status);
997 arch_fpop_end(env);
998 return PdV;
1001 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
1003 float32 RdV;
1004 arch_fpop_start(env);
1005 RdV = internal_mpyf(RsV, RtV, &env->fp_status);
1006 arch_fpop_end(env);
1007 return RdV;
1010 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
1011 float32 RsV, float32 RtV)
1013 arch_fpop_start(env);
1014 RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1015 arch_fpop_end(env);
1016 return RxV;
1019 static bool is_zero_prod(float32 a, float32 b)
1021 return ((float32_is_zero(a) && is_finite(b)) ||
1022 (float32_is_zero(b) && is_finite(a)));
1025 static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
1027 float32 ret = dst;
1028 if (float32_is_any_nan(x)) {
1029 if (extract32(x, 22, 1) == 0) {
1030 float_raise(float_flag_invalid, fp_status);
1032 ret = make_float32(0xffffffff); /* nan */
1034 return ret;
1037 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
1038 float32 RsV, float32 RtV, float32 PuV)
1040 size4s_t tmp;
1041 arch_fpop_start(env);
1042 RxV = check_nan(RxV, RxV, &env->fp_status);
1043 RxV = check_nan(RxV, RsV, &env->fp_status);
1044 RxV = check_nan(RxV, RtV, &env->fp_status);
1045 tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
1046 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1047 RxV = tmp;
1049 arch_fpop_end(env);
1050 return RxV;
1053 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
1054 float32 RsV, float32 RtV)
1056 float32 neg_RsV;
1057 arch_fpop_start(env);
1058 neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1059 RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
1060 arch_fpop_end(env);
1061 return RxV;
1064 static bool is_inf_prod(int32_t a, int32_t b)
1066 return (float32_is_infinity(a) && float32_is_infinity(b)) ||
1067 (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
1068 (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
1071 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
1072 float32 RsV, float32 RtV)
1074 bool infinp;
1075 bool infminusinf;
1076 float32 tmp;
1078 arch_fpop_start(env);
1079 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1080 infminusinf = float32_is_infinity(RxV) &&
1081 is_inf_prod(RsV, RtV) &&
1082 (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
1083 infinp = float32_is_infinity(RxV) ||
1084 float32_is_infinity(RtV) ||
1085 float32_is_infinity(RsV);
1086 RxV = check_nan(RxV, RxV, &env->fp_status);
1087 RxV = check_nan(RxV, RsV, &env->fp_status);
1088 RxV = check_nan(RxV, RtV, &env->fp_status);
1089 tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1090 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1091 RxV = tmp;
1093 set_float_exception_flags(0, &env->fp_status);
1094 if (float32_is_infinity(RxV) && !infinp) {
1095 RxV = RxV - 1;
1097 if (infminusinf) {
1098 RxV = 0;
1100 arch_fpop_end(env);
1101 return RxV;
1104 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
1105 float32 RsV, float32 RtV)
1107 bool infinp;
1108 bool infminusinf;
1109 float32 tmp;
1111 arch_fpop_start(env);
1112 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1113 infminusinf = float32_is_infinity(RxV) &&
1114 is_inf_prod(RsV, RtV) &&
1115 (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
1116 infinp = float32_is_infinity(RxV) ||
1117 float32_is_infinity(RtV) ||
1118 float32_is_infinity(RsV);
1119 RxV = check_nan(RxV, RxV, &env->fp_status);
1120 RxV = check_nan(RxV, RsV, &env->fp_status);
1121 RxV = check_nan(RxV, RtV, &env->fp_status);
1122 float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1123 tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
1124 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1125 RxV = tmp;
1127 set_float_exception_flags(0, &env->fp_status);
1128 if (float32_is_infinity(RxV) && !infinp) {
1129 RxV = RxV - 1;
1131 if (infminusinf) {
1132 RxV = 0;
1134 arch_fpop_end(env);
1135 return RxV;
1138 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
1140 int64_t RddV;
1141 arch_fpop_start(env);
1142 if (float64_is_denormal(RssV) &&
1143 (float64_getexp(RttV) >= 512) &&
1144 float64_is_normal(RttV)) {
1145 RddV = float64_mul(RssV, make_float64(0x4330000000000000),
1146 &env->fp_status);
1147 } else if (float64_is_denormal(RttV) &&
1148 (float64_getexp(RssV) >= 512) &&
1149 float64_is_normal(RssV)) {
1150 RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
1151 &env->fp_status);
1152 } else {
1153 RddV = RssV;
1155 arch_fpop_end(env);
1156 return RddV;
1159 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1160 float64 RssV, float64 RttV)
1162 arch_fpop_start(env);
1163 RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
1164 arch_fpop_end(env);
1165 return RxxV;
1168 static void cancel_slot(CPUHexagonState *env, uint32_t slot)
1170 HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
1171 env->slot_cancelled |= (1 << slot);
1174 /* These macros can be referenced in the generated helper functions */
1175 #define warn(...) /* Nothing */
1176 #define fatal(...) g_assert_not_reached();
1178 #define BOGUS_HELPER(tag) \
1179 printf("ERROR: bogus helper: " #tag "\n")
1181 #include "helper_funcs_generated.c.inc"