af7f182127
The following instructions are added L2_loadrub_pbr Rd32 = memub(Rx32++Mu2:brev) L2_loadrb_pbr Rd32 = memb(Rx32++Mu2:brev) L2_loadruh_pbr Rd32 = memuh(Rx32++Mu2:brev) L2_loadrh_pbr Rd32 = memh(Rx32++Mu2:brev) L2_loadri_pbr Rd32 = memw(Rx32++Mu2:brev) L2_loadrd_pbr Rdd32 = memd(Rx32++Mu2:brev) S2_storerb_pbr memb(Rx32++Mu2:brev).=.Rt32 S2_storerh_pbr memh(Rx32++Mu2:brev).=.Rt32 S2_storerf_pbr memh(Rx32++Mu2:brev).=.Rt.H32 S2_storeri_pbr memw(Rx32++Mu2:brev).=.Rt32 S2_storerd_pbr memd(Rx32++Mu2:brev).=.Rt32 S2_storerinew_pbr memw(Rx32++Mu2:brev).=.Nt8.new S2_storerbnew_pbr memw(Rx32++Mu2:brev).=.Nt8.new S2_storerhnew_pbr memw(Rx32++Mu2:brev).=.Nt8.new Test cases in tests/tcg/hexagon/brev.c Signed-off-by: Taylor Simpson <tsimpson@quicinc.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <1617930474-31979-24-git-send-email-tsimpson@quicinc.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
1189 lines
33 KiB
C
1189 lines
33 KiB
C
/*
|
|
* Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu.h"
|
|
#include "exec/helper-proto.h"
|
|
#include "fpu/softfloat.h"
|
|
#include "cpu.h"
|
|
#include "internal.h"
|
|
#include "macros.h"
|
|
#include "arch.h"
|
|
#include "hex_arch_types.h"
|
|
#include "fma_emu.h"
|
|
|
|
#define SF_BIAS 127
|
|
#define SF_MANTBITS 23
|
|
|
|
/* Exceptions processing helpers */
|
|
static void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
|
|
uint32_t exception,
|
|
uintptr_t pc)
|
|
{
|
|
CPUState *cs = env_cpu(env);
|
|
qemu_log_mask(CPU_LOG_INT, "%s: %d\n", __func__, exception);
|
|
cs->exception_index = exception;
|
|
cpu_loop_exit_restore(cs, pc);
|
|
}
|
|
|
|
void QEMU_NORETURN HELPER(raise_exception)(CPUHexagonState *env, uint32_t excp)
|
|
{
|
|
do_raise_exception_err(env, excp, 0);
|
|
}
|
|
|
|
static void log_reg_write(CPUHexagonState *env, int rnum,
|
|
target_ulong val, uint32_t slot)
|
|
{
|
|
HEX_DEBUG_LOG("log_reg_write[%d] = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")",
|
|
rnum, val, val);
|
|
if (val == env->gpr[rnum]) {
|
|
HEX_DEBUG_LOG(" NO CHANGE");
|
|
}
|
|
HEX_DEBUG_LOG("\n");
|
|
|
|
env->new_value[rnum] = val;
|
|
if (HEX_DEBUG) {
|
|
/* Do this so HELPER(debug_commit_end) will know */
|
|
env->reg_written[rnum] = 1;
|
|
}
|
|
}
|
|
|
|
static void log_pred_write(CPUHexagonState *env, int pnum, target_ulong val)
|
|
{
|
|
HEX_DEBUG_LOG("log_pred_write[%d] = " TARGET_FMT_ld
|
|
" (0x" TARGET_FMT_lx ")\n",
|
|
pnum, val, val);
|
|
|
|
/* Multiple writes to the same preg are and'ed together */
|
|
if (env->pred_written & (1 << pnum)) {
|
|
env->new_pred_value[pnum] &= val & 0xff;
|
|
} else {
|
|
env->new_pred_value[pnum] = val & 0xff;
|
|
env->pred_written |= 1 << pnum;
|
|
}
|
|
}
|
|
|
|
static void log_store32(CPUHexagonState *env, target_ulong addr,
|
|
target_ulong val, int width, int slot)
|
|
{
|
|
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
|
|
", %" PRId32 " [0x08%" PRIx32 "])\n",
|
|
width, addr, val, val);
|
|
env->mem_log_stores[slot].va = addr;
|
|
env->mem_log_stores[slot].width = width;
|
|
env->mem_log_stores[slot].data32 = val;
|
|
}
|
|
|
|
static void log_store64(CPUHexagonState *env, target_ulong addr,
|
|
int64_t val, int width, int slot)
|
|
{
|
|
HEX_DEBUG_LOG("log_store%d(0x" TARGET_FMT_lx
|
|
", %" PRId64 " [0x016%" PRIx64 "])\n",
|
|
width, addr, val, val);
|
|
env->mem_log_stores[slot].va = addr;
|
|
env->mem_log_stores[slot].width = width;
|
|
env->mem_log_stores[slot].data64 = val;
|
|
}
|
|
|
|
static void write_new_pc(CPUHexagonState *env, target_ulong addr)
|
|
{
|
|
HEX_DEBUG_LOG("write_new_pc(0x" TARGET_FMT_lx ")\n", addr);
|
|
|
|
/*
|
|
* If more than one branch is taken in a packet, only the first one
|
|
* is actually done.
|
|
*/
|
|
if (env->branch_taken) {
|
|
HEX_DEBUG_LOG("INFO: multiple branches taken in same packet, "
|
|
"ignoring the second one\n");
|
|
} else {
|
|
fCHECK_PCALIGN(addr);
|
|
env->branch_taken = 1;
|
|
env->next_PC = addr;
|
|
}
|
|
}
|
|
|
|
/* Handy place to set a breakpoint */
|
|
void HELPER(debug_start_packet)(CPUHexagonState *env)
|
|
{
|
|
HEX_DEBUG_LOG("Start packet: pc = 0x" TARGET_FMT_lx "\n",
|
|
env->gpr[HEX_REG_PC]);
|
|
|
|
for (int i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
|
|
env->reg_written[i] = 0;
|
|
}
|
|
}
|
|
|
|
static int32_t new_pred_value(CPUHexagonState *env, int pnum)
|
|
{
|
|
return env->new_pred_value[pnum];
|
|
}
|
|
|
|
/* Checks for bookkeeping errors between disassembly context and runtime */
|
|
void HELPER(debug_check_store_width)(CPUHexagonState *env, int slot, int check)
|
|
{
|
|
if (env->mem_log_stores[slot].width != check) {
|
|
HEX_DEBUG_LOG("ERROR: %d != %d\n",
|
|
env->mem_log_stores[slot].width, check);
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
|
|
void HELPER(commit_store)(CPUHexagonState *env, int slot_num)
|
|
{
|
|
switch (env->mem_log_stores[slot_num].width) {
|
|
case 1:
|
|
put_user_u8(env->mem_log_stores[slot_num].data32,
|
|
env->mem_log_stores[slot_num].va);
|
|
break;
|
|
case 2:
|
|
put_user_u16(env->mem_log_stores[slot_num].data32,
|
|
env->mem_log_stores[slot_num].va);
|
|
break;
|
|
case 4:
|
|
put_user_u32(env->mem_log_stores[slot_num].data32,
|
|
env->mem_log_stores[slot_num].va);
|
|
break;
|
|
case 8:
|
|
put_user_u64(env->mem_log_stores[slot_num].data64,
|
|
env->mem_log_stores[slot_num].va);
|
|
break;
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
|
|
static void print_store(CPUHexagonState *env, int slot)
|
|
{
|
|
if (!(env->slot_cancelled & (1 << slot))) {
|
|
uint8_t width = env->mem_log_stores[slot].width;
|
|
if (width == 1) {
|
|
uint32_t data = env->mem_log_stores[slot].data32 & 0xff;
|
|
HEX_DEBUG_LOG("\tmemb[0x" TARGET_FMT_lx "] = %" PRId32
|
|
" (0x%02" PRIx32 ")\n",
|
|
env->mem_log_stores[slot].va, data, data);
|
|
} else if (width == 2) {
|
|
uint32_t data = env->mem_log_stores[slot].data32 & 0xffff;
|
|
HEX_DEBUG_LOG("\tmemh[0x" TARGET_FMT_lx "] = %" PRId32
|
|
" (0x%04" PRIx32 ")\n",
|
|
env->mem_log_stores[slot].va, data, data);
|
|
} else if (width == 4) {
|
|
uint32_t data = env->mem_log_stores[slot].data32;
|
|
HEX_DEBUG_LOG("\tmemw[0x" TARGET_FMT_lx "] = %" PRId32
|
|
" (0x%08" PRIx32 ")\n",
|
|
env->mem_log_stores[slot].va, data, data);
|
|
} else if (width == 8) {
|
|
HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %" PRId64
|
|
" (0x%016" PRIx64 ")\n",
|
|
env->mem_log_stores[slot].va,
|
|
env->mem_log_stores[slot].data64,
|
|
env->mem_log_stores[slot].data64);
|
|
} else {
|
|
HEX_DEBUG_LOG("\tBad store width %d\n", width);
|
|
g_assert_not_reached();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* This function is a handy place to set a breakpoint */
|
|
void HELPER(debug_commit_end)(CPUHexagonState *env, int has_st0, int has_st1)
|
|
{
|
|
bool reg_printed = false;
|
|
bool pred_printed = false;
|
|
int i;
|
|
|
|
HEX_DEBUG_LOG("Packet committed: pc = 0x" TARGET_FMT_lx "\n",
|
|
env->this_PC);
|
|
HEX_DEBUG_LOG("slot_cancelled = %d\n", env->slot_cancelled);
|
|
|
|
for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) {
|
|
if (env->reg_written[i]) {
|
|
if (!reg_printed) {
|
|
HEX_DEBUG_LOG("Regs written\n");
|
|
reg_printed = true;
|
|
}
|
|
HEX_DEBUG_LOG("\tr%d = " TARGET_FMT_ld " (0x" TARGET_FMT_lx ")\n",
|
|
i, env->new_value[i], env->new_value[i]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < NUM_PREGS; i++) {
|
|
if (env->pred_written & (1 << i)) {
|
|
if (!pred_printed) {
|
|
HEX_DEBUG_LOG("Predicates written\n");
|
|
pred_printed = true;
|
|
}
|
|
HEX_DEBUG_LOG("\tp%d = 0x" TARGET_FMT_lx "\n",
|
|
i, env->new_pred_value[i]);
|
|
}
|
|
}
|
|
|
|
if (has_st0 || has_st1) {
|
|
HEX_DEBUG_LOG("Stores\n");
|
|
if (has_st0) {
|
|
print_store(env, 0);
|
|
}
|
|
if (has_st1) {
|
|
print_store(env, 1);
|
|
}
|
|
}
|
|
|
|
HEX_DEBUG_LOG("Next PC = " TARGET_FMT_lx "\n", env->next_PC);
|
|
HEX_DEBUG_LOG("Exec counters: pkt = " TARGET_FMT_lx
|
|
", insn = " TARGET_FMT_lx
|
|
"\n",
|
|
env->gpr[HEX_REG_QEMU_PKT_CNT],
|
|
env->gpr[HEX_REG_QEMU_INSN_CNT]);
|
|
|
|
}
|
|
|
|
int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS)
|
|
{
|
|
int32_t K_const = sextract32(M, 24, 4);
|
|
int32_t length = sextract32(M, 0, 17);
|
|
uint32_t new_ptr = RxV + offset;
|
|
uint32_t start_addr;
|
|
uint32_t end_addr;
|
|
|
|
if (K_const == 0 && length >= 4) {
|
|
start_addr = CS;
|
|
end_addr = start_addr + length;
|
|
} else {
|
|
/*
|
|
* Versions v3 and earlier used the K value to specify a power-of-2 size
|
|
* 2^(K+2) that is greater than the buffer length
|
|
*/
|
|
int32_t mask = (1 << (K_const + 2)) - 1;
|
|
start_addr = RxV & (~mask);
|
|
end_addr = start_addr | length;
|
|
}
|
|
|
|
if (new_ptr >= end_addr) {
|
|
new_ptr -= length;
|
|
} else if (new_ptr < start_addr) {
|
|
new_ptr += length;
|
|
}
|
|
|
|
return new_ptr;
|
|
}
|
|
|
|
uint32_t HELPER(fbrev)(uint32_t addr)
|
|
{
|
|
/*
|
|
* Bit reverse the low 16 bits of the address
|
|
*/
|
|
return deposit32(addr, 0, 16, revbit16(addr));
|
|
}
|
|
|
|
static float32 build_float32(uint8_t sign, uint32_t exp, uint32_t mant)
|
|
{
|
|
return make_float32(
|
|
((sign & 1) << 31) |
|
|
((exp & 0xff) << SF_MANTBITS) |
|
|
(mant & ((1 << SF_MANTBITS) - 1)));
|
|
}
|
|
|
|
/*
|
|
* sfrecipa, sfinvsqrta have two 32-bit results
|
|
* r0,p0=sfrecipa(r1,r2)
|
|
* r0,p0=sfinvsqrta(r1)
|
|
*
|
|
* Since helpers can only return a single value, we pack the two results
|
|
* into a 64-bit value.
|
|
*/
|
|
uint64_t HELPER(sfrecipa)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
int32_t PeV = 0;
|
|
float32 RdV;
|
|
int idx;
|
|
int adjust;
|
|
int mant;
|
|
int exp;
|
|
|
|
arch_fpop_start(env);
|
|
if (arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status)) {
|
|
PeV = adjust;
|
|
idx = (RtV >> 16) & 0x7f;
|
|
mant = (recip_lookup_table[idx] << 15) | 1;
|
|
exp = SF_BIAS - (float32_getexp(RtV) - SF_BIAS) - 1;
|
|
RdV = build_float32(extract32(RtV, 31, 1), exp, mant);
|
|
}
|
|
arch_fpop_end(env);
|
|
return ((uint64_t)RdV << 32) | PeV;
|
|
}
|
|
|
|
uint64_t HELPER(sfinvsqrta)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
int PeV = 0;
|
|
float32 RdV;
|
|
int idx;
|
|
int adjust;
|
|
int mant;
|
|
int exp;
|
|
|
|
arch_fpop_start(env);
|
|
if (arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status)) {
|
|
PeV = adjust;
|
|
idx = (RsV >> 17) & 0x7f;
|
|
mant = (invsqrt_lookup_table[idx] << 15);
|
|
exp = SF_BIAS - ((float32_getexp(RsV) - SF_BIAS) >> 1) - 1;
|
|
RdV = build_float32(extract32(RsV, 31, 1), exp, mant);
|
|
}
|
|
arch_fpop_end(env);
|
|
return ((uint64_t)RdV << 32) | PeV;
|
|
}
|
|
|
|
int64_t HELPER(vacsh_val)(CPUHexagonState *env,
|
|
int64_t RxxV, int64_t RssV, int64_t RttV)
|
|
{
|
|
for (int i = 0; i < 4; i++) {
|
|
int xv = sextract64(RxxV, i * 16, 16);
|
|
int sv = sextract64(RssV, i * 16, 16);
|
|
int tv = sextract64(RttV, i * 16, 16);
|
|
int max;
|
|
xv = xv + tv;
|
|
sv = sv - tv;
|
|
max = xv > sv ? xv : sv;
|
|
/* Note that fSATH can set the OVF bit in usr */
|
|
RxxV = deposit64(RxxV, i * 16, 16, fSATH(max));
|
|
}
|
|
return RxxV;
|
|
}
|
|
|
|
int32_t HELPER(vacsh_pred)(CPUHexagonState *env,
|
|
int64_t RxxV, int64_t RssV, int64_t RttV)
|
|
{
|
|
int32_t PeV = 0;
|
|
for (int i = 0; i < 4; i++) {
|
|
int xv = sextract64(RxxV, i * 16, 16);
|
|
int sv = sextract64(RssV, i * 16, 16);
|
|
int tv = sextract64(RttV, i * 16, 16);
|
|
xv = xv + tv;
|
|
sv = sv - tv;
|
|
PeV = deposit32(PeV, i * 2, 1, (xv > sv));
|
|
PeV = deposit32(PeV, i * 2 + 1, 1, (xv > sv));
|
|
}
|
|
return PeV;
|
|
}
|
|
|
|
/*
|
|
* mem_noshuf
|
|
* Section 5.5 of the Hexagon V67 Programmer's Reference Manual
|
|
*
|
|
* If the load is in slot 0 and there is a store in slot1 (that
|
|
* wasn't cancelled), we have to do the store first.
|
|
*/
|
|
static void check_noshuf(CPUHexagonState *env, uint32_t slot)
|
|
{
|
|
if (slot == 0 && env->pkt_has_store_s1 &&
|
|
((env->slot_cancelled & (1 << 1)) == 0)) {
|
|
HELPER(commit_store)(env, 1);
|
|
}
|
|
}
|
|
|
|
static uint8_t mem_load1(CPUHexagonState *env, uint32_t slot,
|
|
target_ulong vaddr)
|
|
{
|
|
uint8_t retval;
|
|
check_noshuf(env, slot);
|
|
get_user_u8(retval, vaddr);
|
|
return retval;
|
|
}
|
|
|
|
static uint16_t mem_load2(CPUHexagonState *env, uint32_t slot,
|
|
target_ulong vaddr)
|
|
{
|
|
uint16_t retval;
|
|
check_noshuf(env, slot);
|
|
get_user_u16(retval, vaddr);
|
|
return retval;
|
|
}
|
|
|
|
static uint32_t mem_load4(CPUHexagonState *env, uint32_t slot,
|
|
target_ulong vaddr)
|
|
{
|
|
uint32_t retval;
|
|
check_noshuf(env, slot);
|
|
get_user_u32(retval, vaddr);
|
|
return retval;
|
|
}
|
|
|
|
static uint64_t mem_load8(CPUHexagonState *env, uint32_t slot,
|
|
target_ulong vaddr)
|
|
{
|
|
uint64_t retval;
|
|
check_noshuf(env, slot);
|
|
get_user_u64(retval, vaddr);
|
|
return retval;
|
|
}
|
|
|
|
/* Floating point */
|
|
float64 HELPER(conv_sf2df)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
float64 out_f64;
|
|
arch_fpop_start(env);
|
|
out_f64 = float32_to_float64(RsV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return out_f64;
|
|
}
|
|
|
|
float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
float32 out_f32;
|
|
arch_fpop_start(env);
|
|
out_f32 = float64_to_float32(RssV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return out_f32;
|
|
}
|
|
|
|
float32 HELPER(conv_uw2sf)(CPUHexagonState *env, int32_t RsV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = uint32_to_float32(RsV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = uint32_to_float64(RsV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = int32_to_float32(RsV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = int32_to_float64(RsV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = uint64_to_float32(RssV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = uint64_to_float64(RssV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = int64_to_float32(RssV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = int64_to_float64(RssV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
uint32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
uint32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = 0;
|
|
} else {
|
|
RdV = float32_to_uint32(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
int32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = -1;
|
|
} else {
|
|
RdV = float32_to_int32(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
uint64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
uint64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = 0;
|
|
} else {
|
|
RddV = float32_to_uint64(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
int64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = -1;
|
|
} else {
|
|
RddV = float32_to_int64(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
uint32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
uint32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = 0;
|
|
} else {
|
|
RdV = float64_to_uint32(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
int32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = -1;
|
|
} else {
|
|
RdV = float64_to_int32(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
uint64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
uint64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = 0;
|
|
} else {
|
|
RddV = float64_to_uint64(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
int64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = -1;
|
|
} else {
|
|
RddV = float64_to_int64(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
uint32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
uint32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = 0;
|
|
} else {
|
|
RdV = float32_to_uint32_round_to_zero(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
int32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = -1;
|
|
} else {
|
|
RdV = float32_to_int32_round_to_zero(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
uint64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
uint64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float32_is_neg(RsV) && !float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = 0;
|
|
} else {
|
|
RddV = float32_to_uint64_round_to_zero(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
int64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float32_is_any_nan(RsV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = -1;
|
|
} else {
|
|
RddV = float32_to_int64_round_to_zero(RsV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
uint32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
uint32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float64_is_neg(RssV) && !float32_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = 0;
|
|
} else {
|
|
RdV = float64_to_uint32_round_to_zero(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
int32_t RdV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RdV = -1;
|
|
} else {
|
|
RdV = float64_to_int32_round_to_zero(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
uint64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
uint64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon checks the sign before rounding */
|
|
if (float64_is_neg(RssV) && !float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = 0;
|
|
} else {
|
|
RddV = float64_to_uint64_round_to_zero(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV)
|
|
{
|
|
int64_t RddV;
|
|
arch_fpop_start(env);
|
|
/* Hexagon returns -1 for NaN */
|
|
if (float64_is_any_nan(RssV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
RddV = -1;
|
|
} else {
|
|
RddV = float64_to_int64_round_to_zero(RssV, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = float32_add(RsV, RtV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = float32_sub(RsV, RtV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
PdV = f8BITSOF(float32_eq_quiet(RsV, RtV, &env->fp_status));
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
int cmp;
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
|
|
PdV = f8BITSOF(cmp == float_relation_greater);
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
int cmp;
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
cmp = float32_compare_quiet(RsV, RtV, &env->fp_status);
|
|
PdV = f8BITSOF(cmp == float_relation_greater ||
|
|
cmp == float_relation_equal);
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(sfcmpuo)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
PdV = f8BITSOF(float32_is_any_nan(RsV) ||
|
|
float32_is_any_nan(RtV));
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
float32 HELPER(sfmax)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = float32_maxnum(RsV, RtV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = float32_minnum(RsV, RtV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV)
|
|
{
|
|
int32_t PdV = 0;
|
|
arch_fpop_start(env);
|
|
if (fGETBIT(0, uiV) && float32_is_zero(RsV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(1, uiV) && float32_is_normal(RsV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(2, uiV) && float32_is_denormal(RsV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(3, uiV) && float32_is_infinity(RsV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(4, uiV) && float32_is_any_nan(RsV)) {
|
|
PdV = 0xff;
|
|
}
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
float32 HELPER(sffixupn)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV = 0;
|
|
int adjust;
|
|
arch_fpop_start(env);
|
|
arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
|
|
RdV = RsV;
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float32 HELPER(sffixupd)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV = 0;
|
|
int adjust;
|
|
arch_fpop_start(env);
|
|
arch_sf_recip_common(&RsV, &RtV, &RdV, &adjust, &env->fp_status);
|
|
RdV = RtV;
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float32 HELPER(sffixupr)(CPUHexagonState *env, float32 RsV)
|
|
{
|
|
float32 RdV = 0;
|
|
int adjust;
|
|
arch_fpop_start(env);
|
|
arch_sf_invsqrt_common(&RsV, &RdV, &adjust, &env->fp_status);
|
|
RdV = RsV;
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float64 HELPER(dfadd)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = float64_add(RssV, RttV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = float64_sub(RssV, RttV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = float64_maxnum(RssV, RttV, &env->fp_status);
|
|
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
float64 RddV;
|
|
arch_fpop_start(env);
|
|
RddV = float64_minnum(RssV, RttV, &env->fp_status);
|
|
if (float64_is_any_nan(RssV) || float64_is_any_nan(RttV)) {
|
|
float_raise(float_flag_invalid, &env->fp_status);
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
PdV = f8BITSOF(float64_eq_quiet(RssV, RttV, &env->fp_status));
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
int cmp;
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
|
|
PdV = f8BITSOF(cmp == float_relation_greater);
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
int cmp;
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
cmp = float64_compare_quiet(RssV, RttV, &env->fp_status);
|
|
PdV = f8BITSOF(cmp == float_relation_greater ||
|
|
cmp == float_relation_equal);
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(dfcmpuo)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
int32_t PdV;
|
|
arch_fpop_start(env);
|
|
PdV = f8BITSOF(float64_is_any_nan(RssV) ||
|
|
float64_is_any_nan(RttV));
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
int32_t HELPER(dfclass)(CPUHexagonState *env, float64 RssV, int32_t uiV)
|
|
{
|
|
int32_t PdV = 0;
|
|
arch_fpop_start(env);
|
|
if (fGETBIT(0, uiV) && float64_is_zero(RssV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(1, uiV) && float64_is_normal(RssV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(2, uiV) && float64_is_denormal(RssV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(3, uiV) && float64_is_infinity(RssV)) {
|
|
PdV = 0xff;
|
|
}
|
|
if (fGETBIT(4, uiV) && float64_is_any_nan(RssV)) {
|
|
PdV = 0xff;
|
|
}
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return PdV;
|
|
}
|
|
|
|
float32 HELPER(sfmpy)(CPUHexagonState *env, float32 RsV, float32 RtV)
|
|
{
|
|
float32 RdV;
|
|
arch_fpop_start(env);
|
|
RdV = internal_mpyf(RsV, RtV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RdV;
|
|
}
|
|
|
|
float32 HELPER(sffma)(CPUHexagonState *env, float32 RxV,
|
|
float32 RsV, float32 RtV)
|
|
{
|
|
arch_fpop_start(env);
|
|
RxV = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RxV;
|
|
}
|
|
|
|
static bool is_zero_prod(float32 a, float32 b)
|
|
{
|
|
return ((float32_is_zero(a) && is_finite(b)) ||
|
|
(float32_is_zero(b) && is_finite(a)));
|
|
}
|
|
|
|
static float32 check_nan(float32 dst, float32 x, float_status *fp_status)
|
|
{
|
|
float32 ret = dst;
|
|
if (float32_is_any_nan(x)) {
|
|
if (extract32(x, 22, 1) == 0) {
|
|
float_raise(float_flag_invalid, fp_status);
|
|
}
|
|
ret = make_float32(0xffffffff); /* nan */
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
float32 HELPER(sffma_sc)(CPUHexagonState *env, float32 RxV,
|
|
float32 RsV, float32 RtV, float32 PuV)
|
|
{
|
|
size4s_t tmp;
|
|
arch_fpop_start(env);
|
|
RxV = check_nan(RxV, RxV, &env->fp_status);
|
|
RxV = check_nan(RxV, RsV, &env->fp_status);
|
|
RxV = check_nan(RxV, RtV, &env->fp_status);
|
|
tmp = internal_fmafx(RsV, RtV, RxV, fSXTN(8, 64, PuV), &env->fp_status);
|
|
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
|
RxV = tmp;
|
|
}
|
|
arch_fpop_end(env);
|
|
return RxV;
|
|
}
|
|
|
|
float32 HELPER(sffms)(CPUHexagonState *env, float32 RxV,
|
|
float32 RsV, float32 RtV)
|
|
{
|
|
float32 neg_RsV;
|
|
arch_fpop_start(env);
|
|
neg_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
|
|
RxV = internal_fmafx(neg_RsV, RtV, RxV, 0, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RxV;
|
|
}
|
|
|
|
static bool is_inf_prod(int32_t a, int32_t b)
|
|
{
|
|
return (float32_is_infinity(a) && float32_is_infinity(b)) ||
|
|
(float32_is_infinity(a) && is_finite(b) && !float32_is_zero(b)) ||
|
|
(float32_is_infinity(b) && is_finite(a) && !float32_is_zero(a));
|
|
}
|
|
|
|
float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV,
|
|
float32 RsV, float32 RtV)
|
|
{
|
|
bool infinp;
|
|
bool infminusinf;
|
|
float32 tmp;
|
|
|
|
arch_fpop_start(env);
|
|
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
|
|
infminusinf = float32_is_infinity(RxV) &&
|
|
is_inf_prod(RsV, RtV) &&
|
|
(fGETBIT(31, RsV ^ RxV ^ RtV) != 0);
|
|
infinp = float32_is_infinity(RxV) ||
|
|
float32_is_infinity(RtV) ||
|
|
float32_is_infinity(RsV);
|
|
RxV = check_nan(RxV, RxV, &env->fp_status);
|
|
RxV = check_nan(RxV, RsV, &env->fp_status);
|
|
RxV = check_nan(RxV, RtV, &env->fp_status);
|
|
tmp = internal_fmafx(RsV, RtV, RxV, 0, &env->fp_status);
|
|
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
|
RxV = tmp;
|
|
}
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
if (float32_is_infinity(RxV) && !infinp) {
|
|
RxV = RxV - 1;
|
|
}
|
|
if (infminusinf) {
|
|
RxV = 0;
|
|
}
|
|
arch_fpop_end(env);
|
|
return RxV;
|
|
}
|
|
|
|
float32 HELPER(sffms_lib)(CPUHexagonState *env, float32 RxV,
|
|
float32 RsV, float32 RtV)
|
|
{
|
|
bool infinp;
|
|
bool infminusinf;
|
|
float32 tmp;
|
|
|
|
arch_fpop_start(env);
|
|
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
|
|
infminusinf = float32_is_infinity(RxV) &&
|
|
is_inf_prod(RsV, RtV) &&
|
|
(fGETBIT(31, RsV ^ RxV ^ RtV) == 0);
|
|
infinp = float32_is_infinity(RxV) ||
|
|
float32_is_infinity(RtV) ||
|
|
float32_is_infinity(RsV);
|
|
RxV = check_nan(RxV, RxV, &env->fp_status);
|
|
RxV = check_nan(RxV, RsV, &env->fp_status);
|
|
RxV = check_nan(RxV, RtV, &env->fp_status);
|
|
float32 minus_RsV = float32_sub(float32_zero, RsV, &env->fp_status);
|
|
tmp = internal_fmafx(minus_RsV, RtV, RxV, 0, &env->fp_status);
|
|
if (!(float32_is_zero(RxV) && is_zero_prod(RsV, RtV))) {
|
|
RxV = tmp;
|
|
}
|
|
set_float_exception_flags(0, &env->fp_status);
|
|
if (float32_is_infinity(RxV) && !infinp) {
|
|
RxV = RxV - 1;
|
|
}
|
|
if (infminusinf) {
|
|
RxV = 0;
|
|
}
|
|
arch_fpop_end(env);
|
|
return RxV;
|
|
}
|
|
|
|
float64 HELPER(dfmpyfix)(CPUHexagonState *env, float64 RssV, float64 RttV)
|
|
{
|
|
int64_t RddV;
|
|
arch_fpop_start(env);
|
|
if (float64_is_denormal(RssV) &&
|
|
(float64_getexp(RttV) >= 512) &&
|
|
float64_is_normal(RttV)) {
|
|
RddV = float64_mul(RssV, make_float64(0x4330000000000000),
|
|
&env->fp_status);
|
|
} else if (float64_is_denormal(RttV) &&
|
|
(float64_getexp(RssV) >= 512) &&
|
|
float64_is_normal(RssV)) {
|
|
RddV = float64_mul(RssV, make_float64(0x3cb0000000000000),
|
|
&env->fp_status);
|
|
} else {
|
|
RddV = RssV;
|
|
}
|
|
arch_fpop_end(env);
|
|
return RddV;
|
|
}
|
|
|
|
float64 HELPER(dfmpyhh)(CPUHexagonState *env, float64 RxxV,
|
|
float64 RssV, float64 RttV)
|
|
{
|
|
arch_fpop_start(env);
|
|
RxxV = internal_mpyhh(RssV, RttV, RxxV, &env->fp_status);
|
|
arch_fpop_end(env);
|
|
return RxxV;
|
|
}
|
|
|
|
static void cancel_slot(CPUHexagonState *env, uint32_t slot)
|
|
{
|
|
HEX_DEBUG_LOG("Slot %d cancelled\n", slot);
|
|
env->slot_cancelled |= (1 << slot);
|
|
}
|
|
|
|
/* These macros can be referenced in the generated helper functions */
|
|
#define warn(...) /* Nothing */
|
|
#define fatal(...) g_assert_not_reached();
|
|
|
|
#define BOGUS_HELPER(tag) \
|
|
printf("ERROR: bogus helper: " #tag "\n")
|
|
|
|
#include "helper_funcs_generated.c.inc"
|