cpu: Directly use get_memory_mapping() fallback handlers in place
[qemu/ar7.git] / target / hexagon / op_helper.c
blob63dd6856586cf20f1c2c2735c4f6d186d76c9745
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.h"
20 #include "exec/helper-proto.h"
21 #include "fpu/softfloat.h"
22 #include "cpu.h"
23 #include "internal.h"
24 #include "macros.h"
25 #include "arch.h"
26 #include "hex_arch_types.h"
27 #include "fma_emu.h"
29 #define SF_BIAS 127
30 #define SF_MANTBITS 23
32 /* Exceptions processing helpers */
33 static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
34 uint32_t exception,
35 uintptr_t pc)
37 CPUState *cs = env_cpu(env);
38 qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
39 cs->exception_index = exception;
40 cpu_loop_exit_restore(cs, pc);
43 void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
45 do_raise_exception_err(env, excp, 0);
48 static void log_reg_write(CPUHexagonState *env, int rnum,
49 target_ulong val, uint32_t slot)
51 HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
52 rnum, val, val);
53 if (val == env->gpr[rnum]) {
54 HEX_DEBUG_LOG(" NO CHANGE");
56 HEX_DEBUG_LOG("\n");
58 env->new_value[rnum] = val;
59 if (HEX_DEBUG) {
60 /* Do this so HELPER(debug_commit_end) will know */
61 env->reg_written[rnum] = 1;
65 static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
67 HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
68 " (0x" TARGET_FMT_lx ")\n",
69 pnum, val, val);
71 /* Multiple writes to the same preg are and'ed together */
72 if (env->pred_written & (1 << pnum)) {
73 env->new_pred_value[pnum] &= val & 0xff;
74 } else {
75 env->new_pred_value[pnum] = val & 0xff;
76 env->pred_written |= 1 << pnum;
80 static void log_store32(CPUHexagonState *env, target_ulong addr,
81 target_ulong val, int width, int slot)
83 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
84 ", %" PRId32 " [0x08%" PRIx32 "])\n",
85 width, addr, val, val);
86 env->mem_log_stores[slot].va = addr;
87 env->mem_log_stores[slot].width = width;
88 env->mem_log_stores[slot].data32 = val;
91 static void log_store64(CPUHexagonState *env, target_ulong addr,
92 int64_t val, int width, int slot)
94 HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
95 ", %" PRId64 " [0x016%" PRIx64 "])\n",
96 width, addr, val, val);
97 env->mem_log_stores[slot].va = addr;
98 env->mem_log_stores[slot].width = width;
99 env->mem_log_stores[slot].data64 = val;
102 static void write_new_pc(CPUHexagonState *env, target_ulong addr)
104 HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
107 * If more than one branch is taken in a packet, only the first one
108 * is actually done.
110 if (env->branch_taken) {
111 HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
112 "ignoring the second one\n");
113 } else {
114 fCHECK_PCALIGN(addr);
115 env->branch_taken = 1;
116 env->next_PC = addr;
120 /* Handy place to set a breakpoint */
121 void HELPER(debug_start_packet)(CPUHexagonState *env)
123 HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
124 env->gpr[HEX_REG_PC]);
126 for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
127 env->reg_written[i] = 0;
131 static int32_t new_pred_value(CPUHexagonState *env, int pnum)
133 return env->new_pred_value[pnum];
136 /* Checks for bookkeeping errors between disassembly context and runtime */
137 void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
139 if (env->mem_log_stores[slot].width != check) {
140 HEX_DEBUG_LOG("ERROR: %d != %d\n",
141 env->mem_log_stores[slot].width, check);
142 g_assert_not_reached();
146 void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
148 switch (env->mem_log_stores[slot_num].width) {
149 case 1:
150 put_user_u8(env->mem_log_stores[slot_num].data32,
151 env->mem_log_stores[slot_num].va);
152 break;
153 case 2:
154 put_user_u16(env->mem_log_stores[slot_num].data32,
155 env->mem_log_stores[slot_num].va);
156 break;
157 case 4:
158 put_user_u32(env->mem_log_stores[slot_num].data32,
159 env->mem_log_stores[slot_num].va);
160 break;
161 case 8:
162 put_user_u64(env->mem_log_stores[slot_num].data64,
163 env->mem_log_stores[slot_num].va);
164 break;
165 default:
166 g_assert_not_reached();
170 static void print_store(CPUHexagonState *env, int slot)
172 if (!(env->slot_cancelled & (1 << slot))) {
173 uint8_t width = env->mem_log_stores[slot].width;
174 if (width == 1) {
175 uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
176 HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
177 " (0x%02" PRIx32 ")\n",
178 env->mem_log_stores[slot].va, data, data);
179 } else if (width == 2) {
180 uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
181 HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
182 " (0x%04" PRIx32 ")\n",
183 env->mem_log_stores[slot].va, data, data);
184 } else if (width == 4) {
185 uint32_t data = env->mem_log_stores[slot].data32;
186 HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
187 " (0x%08" PRIx32 ")\n",
188 env->mem_log_stores[slot].va, data, data);
189 } else if (width == 8) {
190 HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
191 " (0x%016" PRIx64 ")\n",
192 env->mem_log_stores[slot].va,
193 env->mem_log_stores[slot].data64,
194 env->mem_log_stores[slot].data64);
195 } else {
196 HEX_DEBUG_LOG("\tBad store width %d\n", width);
197 g_assert_not_reached();
202 /* This function is a handy place to set a breakpoint */
203 void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
205 bool reg_printed = false;
206 bool pred_printed = false;
207 int i;
209 HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n",
210 env->this_PC);
211 HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
213 for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
214 if (env->reg_written[i]) {
215 if (!reg_printed) {
216 HEX_DEBUG_LOG("Regs written\n");
217 reg_printed = true;
219 HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
220 i, env->new_value[i], env->new_value[i]);
224 for (i = 0; i < NUM_PREGS; i++) {
225 if (env->pred_written & (1 << i)) {
226 if (!pred_printed) {
227 HEX_DEBUG_LOG("Predicates written\n");
228 pred_printed = true;
230 HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
231 i, env->new_pred_value[i]);
235 if (has_st0 || has_st1) {
236 HEX_DEBUG_LOG("Stores\n");
237 if (has_st0) {
238 print_store(env, 0);
240 if (has_st1) {
241 print_store(env, 1);
245 HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC);
246 HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
247 ", insn = " TARGET_FMT_lx
248 "\n",
249 env->gpr[HEX_REG_QEMU_PKT_CNT],
250 env->gpr[HEX_REG_QEMU_INSN_CNT]);
254 int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
256 int32_t K_const = sextract32(M, 24, 4);
257 int32_t length = sextract32(M, 0, 17);
258 uint32_t new_ptr = RxV + offset;
259 uint32_t start_addr;
260 uint32_t end_addr;
262 if (K_const == 0 && length >= 4) {
263 start_addr = CS;
264 end_addr = start_addr + length;
265 } else {
267 * Versions v3 and earlier used the K value to specify a power-of-2 size
268 * 2^(K+2) that is greater than the buffer length
270 int32_t mask = (1 << (K_const + 2)) - 1;
271 start_addr = RxV & (~mask);
272 end_addr = start_addr | length;
275 if (new_ptr >= end_addr) {
276 new_ptr -= length;
277 } else if (new_ptr < start_addr) {
278 new_ptr += length;
281 return new_ptr;
284 uint32_t HELPER(fbrev)(uint32_t addr)
287 * Bit reverse the low 16 bits of the address
289 return deposit32(addr, 0, 16, revbit16(addr));
292 static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
294 return make_float32(
295 ((sign & 1) << 31) |
296 ((exp & 0xff) << SF_MANTBITS) |
297 (mant & ((1 << SF_MANTBITS) - 1)));
301 * sfrecipa, sfinvsqrta have two 32-bit results
302 * r0,p0=sfrecipa(r1,r2)
303 * r0,p0=sfinvsqrta(r1)
305 * Since helpers can only return a single value, we pack the two results
306 * into a 64-bit value.
308 uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
310 int32_t PeV = 0;
311 float32 RdV;
312 int idx;
313 int adjust;
314 int mant;
315 int exp;
317 arch_fpop_start(env);
318 if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
319 PeV = adjust;
320 idx = (RtV >> 16) & 0x7f;
321 mant = (recip_lookup_table[idx] << 15) | 1;
322 exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
323 RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
325 arch_fpop_end(env);
326 return ((uint64_t)RdV << 32) | PeV;
329 uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
331 int PeV = 0;
332 float32 RdV;
333 int idx;
334 int adjust;
335 int mant;
336 int exp;
338 arch_fpop_start(env);
339 if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
340 PeV = adjust;
341 idx = (RsV >> 17) & 0x7f;
342 mant = (invsqrt_lookup_table[idx] << 15);
343 exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
344 RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
346 arch_fpop_end(env);
347 return ((uint64_t)RdV << 32) | PeV;
350 int64_t HELPER(vacsh_val)(CPUHexagonState *env,
351 int64_t RxxV, int64_t RssV, int64_t RttV)
353 for (int i = 0; i < 4; i++) {
354 int xv = sextract64(RxxV, i * 16, 16);
355 int sv = sextract64(RssV, i * 16, 16);
356 int tv = sextract64(RttV, i * 16, 16);
357 int max;
358 xv = xv + tv;
359 sv = sv - tv;
360 max = xv > sv ? xv : sv;
361 /* Note that fSATH can set the OVF bit in usr */
362 RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
364 return RxxV;
367 int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
368 int64_t RxxV, int64_t RssV, int64_t RttV)
370 int32_t PeV = 0;
371 for (int i = 0; i < 4; i++) {
372 int xv = sextract64(RxxV, i * 16, 16);
373 int sv = sextract64(RssV, i * 16, 16);
374 int tv = sextract64(RttV, i * 16, 16);
375 xv = xv + tv;
376 sv = sv - tv;
377 PeV = deposit32(PeV, i * 2, 1, (xv > sv));
378 PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
380 return PeV;
384 * mem_noshuf
385 * Section 5.5 of the Hexagon V67 Programmer's Reference Manual
387 * If the load is in slot 0 and there is a store in slot1 (that
388 * wasn't cancelled), we have to do the store first.
390 static void check_noshuf(CPUHexagonState *env, uint32_t slot)
392 if (slot == 0 && env->pkt_has_store_s1 &&
393 ((env->slot_cancelled & (1 << 1)) == 0)) {
394 HELPER(commit_store)(env, 1);
398 static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
399 target_ulong vaddr)
401 uint8_t retval;
402 check_noshuf(env, slot);
403 get_user_u8(retval, vaddr);
404 return retval;
407 static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
408 target_ulong vaddr)
410 uint16_t retval;
411 check_noshuf(env, slot);
412 get_user_u16(retval, vaddr);
413 return retval;
416 static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
417 target_ulong vaddr)
419 uint32_t retval;
420 check_noshuf(env, slot);
421 get_user_u32(retval, vaddr);
422 return retval;
425 static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
426 target_ulong vaddr)
428 uint64_t retval;
429 check_noshuf(env, slot);
430 get_user_u64(retval, vaddr);
431 return retval;
434 /* Floating point */
435 float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
437 float64 out_f64;
438 arch_fpop_start(env);
439 out_f64 = float32_to_float64(RsV, &env->fp_status);
440 arch_fpop_end(env);
441 return out_f64;
444 float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
446 float32 out_f32;
447 arch_fpop_start(env);
448 out_f32 = float64_to_float32(RssV, &env->fp_status);
449 arch_fpop_end(env);
450 return out_f32;
453 float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
455 float32 RdV;
456 arch_fpop_start(env);
457 RdV = uint32_to_float32(RsV, &env->fp_status);
458 arch_fpop_end(env);
459 return RdV;
462 float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
464 float64 RddV;
465 arch_fpop_start(env);
466 RddV = uint32_to_float64(RsV, &env->fp_status);
467 arch_fpop_end(env);
468 return RddV;
471 float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
473 float32 RdV;
474 arch_fpop_start(env);
475 RdV = int32_to_float32(RsV, &env->fp_status);
476 arch_fpop_end(env);
477 return RdV;
480 float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
482 float64 RddV;
483 arch_fpop_start(env);
484 RddV = int32_to_float64(RsV, &env->fp_status);
485 arch_fpop_end(env);
486 return RddV;
489 float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
491 float32 RdV;
492 arch_fpop_start(env);
493 RdV = uint64_to_float32(RssV, &env->fp_status);
494 arch_fpop_end(env);
495 return RdV;
498 float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
500 float64 RddV;
501 arch_fpop_start(env);
502 RddV = uint64_to_float64(RssV, &env->fp_status);
503 arch_fpop_end(env);
504 return RddV;
507 float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
509 float32 RdV;
510 arch_fpop_start(env);
511 RdV = int64_to_float32(RssV, &env->fp_status);
512 arch_fpop_end(env);
513 return RdV;
516 float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
518 float64 RddV;
519 arch_fpop_start(env);
520 RddV = int64_to_float64(RssV, &env->fp_status);
521 arch_fpop_end(env);
522 return RddV;
525 uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
527 uint32_t RdV;
528 arch_fpop_start(env);
529 /* Hexagon checks the sign before rounding */
530 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
531 float_raise(float_flag_invalid, &env->fp_status);
532 RdV = 0;
533 } else {
534 RdV = float32_to_uint32(RsV, &env->fp_status);
536 arch_fpop_end(env);
537 return RdV;
540 int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
542 int32_t RdV;
543 arch_fpop_start(env);
544 /* Hexagon returns -1 for NaN */
545 if (float32_is_any_nan(RsV)) {
546 float_raise(float_flag_invalid, &env->fp_status);
547 RdV = -1;
548 } else {
549 RdV = float32_to_int32(RsV, &env->fp_status);
551 arch_fpop_end(env);
552 return RdV;
555 uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
557 uint64_t RddV;
558 arch_fpop_start(env);
559 /* Hexagon checks the sign before rounding */
560 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
561 float_raise(float_flag_invalid, &env->fp_status);
562 RddV = 0;
563 } else {
564 RddV = float32_to_uint64(RsV, &env->fp_status);
566 arch_fpop_end(env);
567 return RddV;
570 int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
572 int64_t RddV;
573 arch_fpop_start(env);
574 /* Hexagon returns -1 for NaN */
575 if (float32_is_any_nan(RsV)) {
576 float_raise(float_flag_invalid, &env->fp_status);
577 RddV = -1;
578 } else {
579 RddV = float32_to_int64(RsV, &env->fp_status);
581 arch_fpop_end(env);
582 return RddV;
585 uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
587 uint32_t RdV;
588 arch_fpop_start(env);
589 /* Hexagon checks the sign before rounding */
590 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
591 float_raise(float_flag_invalid, &env->fp_status);
592 RdV = 0;
593 } else {
594 RdV = float64_to_uint32(RssV, &env->fp_status);
596 arch_fpop_end(env);
597 return RdV;
600 int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
602 int32_t RdV;
603 arch_fpop_start(env);
604 /* Hexagon returns -1 for NaN */
605 if (float64_is_any_nan(RssV)) {
606 float_raise(float_flag_invalid, &env->fp_status);
607 RdV = -1;
608 } else {
609 RdV = float64_to_int32(RssV, &env->fp_status);
611 arch_fpop_end(env);
612 return RdV;
615 uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
617 uint64_t RddV;
618 arch_fpop_start(env);
619 /* Hexagon checks the sign before rounding */
620 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
621 float_raise(float_flag_invalid, &env->fp_status);
622 RddV = 0;
623 } else {
624 RddV = float64_to_uint64(RssV, &env->fp_status);
626 arch_fpop_end(env);
627 return RddV;
630 int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
632 int64_t RddV;
633 arch_fpop_start(env);
634 /* Hexagon returns -1 for NaN */
635 if (float64_is_any_nan(RssV)) {
636 float_raise(float_flag_invalid, &env->fp_status);
637 RddV = -1;
638 } else {
639 RddV = float64_to_int64(RssV, &env->fp_status);
641 arch_fpop_end(env);
642 return RddV;
645 uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
647 uint32_t RdV;
648 arch_fpop_start(env);
649 /* Hexagon checks the sign before rounding */
650 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
651 float_raise(float_flag_invalid, &env->fp_status);
652 RdV = 0;
653 } else {
654 RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
656 arch_fpop_end(env);
657 return RdV;
660 int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
662 int32_t RdV;
663 arch_fpop_start(env);
664 /* Hexagon returns -1 for NaN */
665 if (float32_is_any_nan(RsV)) {
666 float_raise(float_flag_invalid, &env->fp_status);
667 RdV = -1;
668 } else {
669 RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
671 arch_fpop_end(env);
672 return RdV;
675 uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
677 uint64_t RddV;
678 arch_fpop_start(env);
679 /* Hexagon checks the sign before rounding */
680 if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
681 float_raise(float_flag_invalid, &env->fp_status);
682 RddV = 0;
683 } else {
684 RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
686 arch_fpop_end(env);
687 return RddV;
690 int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
692 int64_t RddV;
693 arch_fpop_start(env);
694 /* Hexagon returns -1 for NaN */
695 if (float32_is_any_nan(RsV)) {
696 float_raise(float_flag_invalid, &env->fp_status);
697 RddV = -1;
698 } else {
699 RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
701 arch_fpop_end(env);
702 return RddV;
705 uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
707 uint32_t RdV;
708 arch_fpop_start(env);
709 /* Hexagon checks the sign before rounding */
710 if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
711 float_raise(float_flag_invalid, &env->fp_status);
712 RdV = 0;
713 } else {
714 RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
716 arch_fpop_end(env);
717 return RdV;
720 int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
722 int32_t RdV;
723 arch_fpop_start(env);
724 /* Hexagon returns -1 for NaN */
725 if (float64_is_any_nan(RssV)) {
726 float_raise(float_flag_invalid, &env->fp_status);
727 RdV = -1;
728 } else {
729 RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
731 arch_fpop_end(env);
732 return RdV;
735 uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
737 uint64_t RddV;
738 arch_fpop_start(env);
739 /* Hexagon checks the sign before rounding */
740 if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
741 float_raise(float_flag_invalid, &env->fp_status);
742 RddV = 0;
743 } else {
744 RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
746 arch_fpop_end(env);
747 return RddV;
750 int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
752 int64_t RddV;
753 arch_fpop_start(env);
754 /* Hexagon returns -1 for NaN */
755 if (float64_is_any_nan(RssV)) {
756 float_raise(float_flag_invalid, &env->fp_status);
757 RddV = -1;
758 } else {
759 RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
761 arch_fpop_end(env);
762 return RddV;
765 float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
767 float32 RdV;
768 arch_fpop_start(env);
769 RdV = float32_add(RsV, RtV, &env->fp_status);
770 arch_fpop_end(env);
771 return RdV;
774 float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
776 float32 RdV;
777 arch_fpop_start(env);
778 RdV = float32_sub(RsV, RtV, &env->fp_status);
779 arch_fpop_end(env);
780 return RdV;
783 int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
785 int32_t PdV;
786 arch_fpop_start(env);
787 PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
788 arch_fpop_end(env);
789 return PdV;
792 int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
794 int cmp;
795 int32_t PdV;
796 arch_fpop_start(env);
797 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
798 PdV = f8BITSOF(cmp == float_relation_greater);
799 arch_fpop_end(env);
800 return PdV;
803 int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
805 int cmp;
806 int32_t PdV;
807 arch_fpop_start(env);
808 cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
809 PdV = f8BITSOF(cmp == float_relation_greater ||
810 cmp == float_relation_equal);
811 arch_fpop_end(env);
812 return PdV;
815 int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
817 int32_t PdV;
818 arch_fpop_start(env);
819 PdV = f8BITSOF(float32_is_any_nan(RsV) ||
820 float32_is_any_nan(RtV));
821 arch_fpop_end(env);
822 return PdV;
825 float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
827 float32 RdV;
828 arch_fpop_start(env);
829 RdV = float32_maxnum(RsV, RtV, &env->fp_status);
830 arch_fpop_end(env);
831 return RdV;
834 float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
836 float32 RdV;
837 arch_fpop_start(env);
838 RdV = float32_minnum(RsV, RtV, &env->fp_status);
839 arch_fpop_end(env);
840 return RdV;
843 int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
845 int32_t PdV = 0;
846 arch_fpop_start(env);
847 if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
848 PdV = 0xff;
850 if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
851 PdV = 0xff;
853 if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
854 PdV = 0xff;
856 if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
857 PdV = 0xff;
859 if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
860 PdV = 0xff;
862 set_float_exception_flags(0, &env->fp_status);
863 arch_fpop_end(env);
864 return PdV;
867 float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
869 float32 RdV = 0;
870 int adjust;
871 arch_fpop_start(env);
872 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
873 RdV = RsV;
874 arch_fpop_end(env);
875 return RdV;
878 float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
880 float32 RdV = 0;
881 int adjust;
882 arch_fpop_start(env);
883 arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
884 RdV = RtV;
885 arch_fpop_end(env);
886 return RdV;
889 float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
891 float32 RdV = 0;
892 int adjust;
893 arch_fpop_start(env);
894 arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
895 RdV = RsV;
896 arch_fpop_end(env);
897 return RdV;
900 float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
902 float64 RddV;
903 arch_fpop_start(env);
904 RddV = float64_add(RssV, RttV, &env->fp_status);
905 arch_fpop_end(env);
906 return RddV;
909 float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
911 float64 RddV;
912 arch_fpop_start(env);
913 RddV = float64_sub(RssV, RttV, &env->fp_status);
914 arch_fpop_end(env);
915 return RddV;
918 float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
920 float64 RddV;
921 arch_fpop_start(env);
922 RddV = float64_maxnum(RssV, RttV, &env->fp_status);
923 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
924 float_raise(float_flag_invalid, &env->fp_status);
926 arch_fpop_end(env);
927 return RddV;
930 float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
932 float64 RddV;
933 arch_fpop_start(env);
934 RddV = float64_minnum(RssV, RttV, &env->fp_status);
935 if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
936 float_raise(float_flag_invalid, &env->fp_status);
938 arch_fpop_end(env);
939 return RddV;
942 int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
944 int32_t PdV;
945 arch_fpop_start(env);
946 PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
947 arch_fpop_end(env);
948 return PdV;
951 int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
953 int cmp;
954 int32_t PdV;
955 arch_fpop_start(env);
956 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
957 PdV = f8BITSOF(cmp == float_relation_greater);
958 arch_fpop_end(env);
959 return PdV;
962 int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
964 int cmp;
965 int32_t PdV;
966 arch_fpop_start(env);
967 cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
968 PdV = f8BITSOF(cmp == float_relation_greater ||
969 cmp == float_relation_equal);
970 arch_fpop_end(env);
971 return PdV;
974 int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
976 int32_t PdV;
977 arch_fpop_start(env);
978 PdV = f8BITSOF(float64_is_any_nan(RssV) ||
979 float64_is_any_nan(RttV));
980 arch_fpop_end(env);
981 return PdV;
984 int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
986 int32_t PdV = 0;
987 arch_fpop_start(env);
988 if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
989 PdV = 0xff;
991 if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
992 PdV = 0xff;
994 if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
995 PdV = 0xff;
997 if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
998 PdV = 0xff;
1000 if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
1001 PdV = 0xff;
1003 set_float_exception_flags(0, &env->fp_status);
1004 arch_fpop_end(env);
1005 return PdV;
1008 float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
1010 float32 RdV;
1011 arch_fpop_start(env);
1012 RdV = internal_mpyf(RsV, RtV, &env->fp_status);
1013 arch_fpop_end(env);
1014 return RdV;
1017 float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
1018 float32 RsV, float32 RtV)
1020 arch_fpop_start(env);
1021 RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1022 arch_fpop_end(env);
1023 return RxV;
1026 static bool is_zero_prod(float32 a, float32 b)
1028 return ((float32_is_zero(a) && is_finite(b)) ||
1029 (float32_is_zero(b) && is_finite(a)));
1032 static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
1034 float32 ret = dst;
1035 if (float32_is_any_nan(x)) {
1036 if (extract32(x, 22, 1) == 0) {
1037 float_raise(float_flag_invalid, fp_status);
1039 ret = make_float32(0xffffffff); /* nan */
1041 return ret;
1044 float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
1045 float32 RsV, float32 RtV, float32 PuV)
1047 size4s_t tmp;
1048 arch_fpop_start(env);
1049 RxV = check_nan(RxV, RxV, &env->fp_status);
1050 RxV = check_nan(RxV, RsV, &env->fp_status);
1051 RxV = check_nan(RxV, RtV, &env->fp_status);
1052 tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
1053 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1054 RxV = tmp;
1056 arch_fpop_end(env);
1057 return RxV;
1060 float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
1061 float32 RsV, float32 RtV)
1063 float32 neg_RsV;
1064 arch_fpop_start(env);
1065 neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1066 RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
1067 arch_fpop_end(env);
1068 return RxV;
1071 static bool is_inf_prod(int32_t a, int32_t b)
1073 return (float32_is_infinity(a) && float32_is_infinity(b)) ||
1074 (float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
1075 (float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
1078 float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
1079 float32 RsV, float32 RtV)
1081 bool infinp;
1082 bool infminusinf;
1083 float32 tmp;
1085 arch_fpop_start(env);
1086 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1087 infminusinf = float32_is_infinity(RxV) &&
1088 is_inf_prod(RsV, RtV) &&
1089 (fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
1090 infinp = float32_is_infinity(RxV) ||
1091 float32_is_infinity(RtV) ||
1092 float32_is_infinity(RsV);
1093 RxV = check_nan(RxV, RxV, &env->fp_status);
1094 RxV = check_nan(RxV, RsV, &env->fp_status);
1095 RxV = check_nan(RxV, RtV, &env->fp_status);
1096 tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
1097 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1098 RxV = tmp;
1100 set_float_exception_flags(0, &env->fp_status);
1101 if (float32_is_infinity(RxV) && !infinp) {
1102 RxV = RxV - 1;
1104 if (infminusinf) {
1105 RxV = 0;
1107 arch_fpop_end(env);
1108 return RxV;
1111 float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
1112 float32 RsV, float32 RtV)
1114 bool infinp;
1115 bool infminusinf;
1116 float32 tmp;
1118 arch_fpop_start(env);
1119 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
1120 infminusinf = float32_is_infinity(RxV) &&
1121 is_inf_prod(RsV, RtV) &&
1122 (fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
1123 infinp = float32_is_infinity(RxV) ||
1124 float32_is_infinity(RtV) ||
1125 float32_is_infinity(RsV);
1126 RxV = check_nan(RxV, RxV, &env->fp_status);
1127 RxV = check_nan(RxV, RsV, &env->fp_status);
1128 RxV = check_nan(RxV, RtV, &env->fp_status);
1129 float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
1130 tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
1131 if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
1132 RxV = tmp;
1134 set_float_exception_flags(0, &env->fp_status);
1135 if (float32_is_infinity(RxV) && !infinp) {
1136 RxV = RxV - 1;
1138 if (infminusinf) {
1139 RxV = 0;
1141 arch_fpop_end(env);
1142 return RxV;
1145 float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
1147 int64_t RddV;
1148 arch_fpop_start(env);
1149 if (float64_is_denormal(RssV) &&
1150 (float64_getexp(RttV) >= 512) &&
1151 float64_is_normal(RttV)) {
1152 RddV = float64_mul(RssV, make_float64(0x4330000000000000),
1153 &env->fp_status);
1154 } else if (float64_is_denormal(RttV) &&
1155 (float64_getexp(RssV) >= 512) &&
1156 float64_is_normal(RssV)) {
1157 RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
1158 &env->fp_status);
1159 } else {
1160 RddV = RssV;
1162 arch_fpop_end(env);
1163 return RddV;
1166 float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
1167 float64 RssV, float64 RttV)
1169 arch_fpop_start(env);
1170 RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
1171 arch_fpop_end(env);
1172 return RxxV;
1175 static void cancel_slot(CPUHexagonState *env, uint32_t slot)
1177 HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
1178 env->slot_cancelled |= (1 << slot);
1181 /* These macros can be referenced in the generated helper functions */
1182 #define warn(...) /* Nothing */
1183 #define fatal(...) g_assert_not_reached();
1185 #define BOGUS_HELPER(tag) \
1186 printf("ERROR: bogus helper: " #tag "\n")
1188 #include "helper_funcs_generated.c.inc"