From patchwork Fri Oct 30 00:08:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Taylor Simpson X-Patchwork-Id: 316565 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5A627C2D0A3 for ; Fri, 30 Oct 2020 00:42:32 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8263320691 for ; Fri, 30 Oct 2020 00:42:31 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=quicinc.com header.i=@quicinc.com header.b="Bvf6rj+X" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8263320691 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=quicinc.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:53018 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kYIUw-0002tf-FM for qemu-devel@archiver.kernel.org; Thu, 29 Oct 2020 20:42:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38992) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kYHyb-00040B-Db for qemu-devel@nongnu.org; Thu, 29 Oct 2020 20:09:08 -0400 Received: from alexa-out-sd-02.qualcomm.com ([199.106.114.39]:38752) by eggs.gnu.org with esmtps (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.90_1) (envelope-from ) id 1kYHyR-0005Qs-9N for qemu-devel@nongnu.org; Thu, 29 Oct 2020 20:09:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=quicinc.com; i=@quicinc.com; q=dns/txt; s=qcdkim; t=1604016535; x=1635552535; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=R3q9GIbeVnVM9QC3wyACZHw3p76H9oXLdeGRHiAPy5c=; b=Bvf6rj+X+0gW27QyxxB/H9/pAuvwj5oueZnb2T+r7/482VOlG5+RVN6K +9qO3dSsJC5I10diVC1ABUXUjMkBt5wKK+drcahGROQknKdY8F69Rz5hx 3LCnHOW6W+s0u5ryLjjXqeZRTwl7ZrcB7baHOwOmTlvYFcltsWbVe/2m5 w=; Received: from unknown (HELO ironmsg04-sd.qualcomm.com) ([10.53.140.144]) by alexa-out-sd-02.qualcomm.com with ESMTP; 29 Oct 2020 17:08:44 -0700 X-QCInternal: smtphost Received: from vu-tsimpson-aus.qualcomm.com (HELO vu-tsimpson1-aus.qualcomm.com) ([10.222.150.1]) by ironmsg04-sd.qualcomm.com with ESMTP; 29 Oct 2020 17:08:44 -0700 Received: by vu-tsimpson1-aus.qualcomm.com (Postfix, from userid 47164) id 9370E411F; Thu, 29 Oct 2020 19:08:43 -0500 (CDT) From: Taylor Simpson To: qemu-devel@nongnu.org Subject: [RFC PATCH v5 07/33] Hexagon (target/hexagon) scalar core helpers Date: Thu, 29 Oct 2020 19:08:13 -0500 Message-Id: <1604016519-28065-8-git-send-email-tsimpson@quicinc.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1604016519-28065-1-git-send-email-tsimpson@quicinc.com> References: <1604016519-28065-1-git-send-email-tsimpson@quicinc.com> MIME-Version: 1.0 Received-SPF: pass client-ip=199.106.114.39; envelope-from=tsimpson@qualcomm.com; helo=alexa-out-sd-02.qualcomm.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/29 19:58:53 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -40 X-Spam_score: -4.1 X-Spam_bar: ---- X-Spam_report: (-4.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.249, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ale@rev.ng, bcain@quicinc.com, richard.henderson@linaro.org, at.org@qualcomm.com, laurent@vivier.eu, tsimpson@quicinc.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The majority of helpers are generated. Define the helper functions needed then include the generated file Signed-off-by: Taylor Simpson --- target/hexagon/helper.h | 85 ++++ target/hexagon/op_helper.c | 971 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1056 insertions(+) create mode 100644 target/hexagon/helper.h create mode 100644 target/hexagon/op_helper.c diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h new file mode 100644 index 0000000..9246b28 --- /dev/null +++ b/target/hexagon/helper.h @@ -0,0 +1,85 @@ +/* + * Copyright(c) 2019-2020 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 . + */ + +DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_RETURN, noreturn, env, i32) +DEF_HELPER_1(debug_start_packet, void, env) +DEF_HELPER_FLAGS_3(debug_check_store_width, TCG_CALL_NO_WG, void, env, int, int) +DEF_HELPER_2(commit_store, void, env, int) +DEF_HELPER_FLAGS_3(debug_commit_end, TCG_CALL_NO_WG, void, env, int, int) +DEF_HELPER_4(fcircadd, s32, s32, s32, s32, s32) + +/* Floating point */ +DEF_HELPER_2(conv_sf2df, f64, env, f32) +DEF_HELPER_2(conv_df2sf, f32, env, f64) +DEF_HELPER_2(conv_uw2sf, f32, env, s32) +DEF_HELPER_2(conv_uw2df, f64, env, s32) +DEF_HELPER_2(conv_w2sf, f32, env, s32) +DEF_HELPER_2(conv_w2df, f64, env, s32) +DEF_HELPER_2(conv_ud2sf, f32, env, s64) +DEF_HELPER_2(conv_ud2df, f64, env, s64) +DEF_HELPER_2(conv_d2sf, f32, env, s64) +DEF_HELPER_2(conv_d2df, f64, env, s64) +DEF_HELPER_2(conv_sf2uw, s32, env, f32) +DEF_HELPER_2(conv_sf2w, s32, env, f32) +DEF_HELPER_2(conv_sf2ud, s64, env, f32) +DEF_HELPER_2(conv_sf2d, s64, env, f32) +DEF_HELPER_2(conv_df2uw, s32, env, f64) +DEF_HELPER_2(conv_df2w, s32, env, f64) +DEF_HELPER_2(conv_df2ud, s64, env, f64) +DEF_HELPER_2(conv_df2d, s64, env, f64) +DEF_HELPER_2(conv_sf2uw_chop, s32, env, f32) +DEF_HELPER_2(conv_sf2w_chop, s32, env, f32) +DEF_HELPER_2(conv_sf2ud_chop, s64, env, f32) +DEF_HELPER_2(conv_sf2d_chop, s64, env, f32) +DEF_HELPER_2(conv_df2uw_chop, s32, env, f64) +DEF_HELPER_2(conv_df2w_chop, s32, env, f64) +DEF_HELPER_2(conv_df2ud_chop, s64, env, f64) +DEF_HELPER_2(conv_df2d_chop, s64, env, f64) +DEF_HELPER_3(sfadd, f32, env, f32, f32) +DEF_HELPER_3(sfsub, f32, env, f32, f32) +DEF_HELPER_3(sfcmpeq, s32, env, f32, f32) +DEF_HELPER_3(sfcmpgt, s32, env, f32, f32) +DEF_HELPER_3(sfcmpge, s32, env, f32, f32) +DEF_HELPER_3(sfcmpuo, s32, env, f32, f32) +DEF_HELPER_3(sfmax, f32, env, f32, f32) +DEF_HELPER_3(sfmin, f32, env, f32, f32) +DEF_HELPER_3(sfclass, s32, env, f32, s32) +DEF_HELPER_3(sffixupn, f32, env, f32, f32) +DEF_HELPER_3(sffixupd, f32, env, f32, f32) +DEF_HELPER_2(sffixupr, f32, env, f32) + +DEF_HELPER_3(dfadd, f64, env, f64, f64) +DEF_HELPER_3(dfsub, f64, env, f64, f64) +DEF_HELPER_3(dfmax, f64, env, f64, f64) +DEF_HELPER_3(dfmin, f64, env, f64, f64) +DEF_HELPER_3(dfcmpeq, s32, env, f64, f64) +DEF_HELPER_3(dfcmpgt, s32, env, f64, f64) +DEF_HELPER_3(dfcmpge, s32, env, f64, f64) +DEF_HELPER_3(dfcmpuo, s32, env, f64, f64) +DEF_HELPER_3(dfclass, s32, env, f64, s32) + +DEF_HELPER_3(sfmpy, f32, env, f32, f32) +DEF_HELPER_4(sffma, f32, env, f32, f32, f32) +DEF_HELPER_5(sffma_sc, f32, env, f32, f32, f32, f32) +DEF_HELPER_4(sffms, f32, env, f32, f32, f32) +DEF_HELPER_4(sffma_lib, f32, env, f32, f32, f32) +DEF_HELPER_4(sffms_lib, f32, env, f32, f32, f32) + +DEF_HELPER_3(dfmpyfix, f64, env, f64, f64) +DEF_HELPER_4(dfmpyhh, f64, env, f64, f64, f64) + +#include "helper_protos_generated.h" diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c new file mode 100644 index 0000000..122a18d --- /dev/null +++ b/target/hexagon/op_helper.c @@ -0,0 +1,971 @@ +/* + * Copyright(c) 2019-2020 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 . + */ + +#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" +#include "conv_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 = CPU(hexagon_env_get_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 inline 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 (env->slot_cancelled & (1 << slot)) { + HEX_DEBUG_LOG(" CANCELLED"); + } + if (val == env->gpr[rnum]) { + HEX_DEBUG_LOG(" NO CHANGE"); + } + HEX_DEBUG_LOG("\n"); + if (!(env->slot_cancelled & (1 << slot))) { + env->new_value[rnum] = val; +#if HEX_DEBUG + /* Do this so HELPER(debug_commit_end) will know */ + env->reg_written[rnum] = 1; +#endif + } +} + +static __attribute__((unused)) +inline void log_reg_write_pair(CPUHexagonState *env, int rnum, + int64_t val, uint32_t slot) +{ + HEX_DEBUG_LOG("log_reg_write_pair[%d:%d] = %ld\n", rnum + 1, rnum, val); + log_reg_write(env, rnum, val & 0xFFFFFFFF, slot); + log_reg_write(env, rnum + 1, (val >> 32) & 0xFFFFFFFF, slot); +} + +static inline 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 inline 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 ", " TARGET_FMT_ld + " [0x" TARGET_FMT_lx "])\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 inline 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 ", %ld [0x%lx])\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 inline 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]); + + int i; + for (i = 0; i < TOTAL_PER_THREAD_REGS; i++) { + env->reg_written[i] = 0; + } +} + +static inline 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 "] = %d (0x%02x)\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 "] = %d (0x%04x)\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 "] = %d (0x%08x)\n", + env->mem_log_stores[slot].va, data, data); + } else if (width == 8) { + HEX_DEBUG_LOG("\tmemd[0x" TARGET_FMT_lx "] = %lu (0x%016lx)\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 = 0x%x\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]); + +} + +static int32_t fcircadd_v4(int32_t RxV, int32_t offset, int32_t M, int32_t CS) +{ + int32_t length = M & 0x0001ffff; + uint32_t new_ptr = RxV + offset; + uint32_t start_addr = CS; + uint32_t 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; +} + +int32_t HELPER(fcircadd)(int32_t RxV, int32_t offset, int32_t M, int32_t CS) +{ + int32_t K_const = (M >> 24) & 0xf; + int32_t length = M & 0x1ffff; + int32_t mask = (1 << (K_const + 2)) - 1; + uint32_t new_ptr = RxV + offset; + uint32_t start_addr = RxV & (~mask); + uint32_t end_addr = start_addr | length; + + if (K_const == 0 && length >= 4) { + return fcircadd_v4(RxV, offset, M, CS); + } + + if (new_ptr >= end_addr) { + new_ptr -= length; + } else if (new_ptr < start_addr) { + new_ptr += length; + } + + return new_ptr; +} + +/* + * 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 inline 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 inline 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 inline 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 inline 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) +{ + arch_fpop_start(env); + float64 out_f64 = float32_to_float64(RsV, &env->fp_status); + if (float64_is_any_nan(out_f64)) { + out_f64 = make_float64(0xFFFFFFFFFFFFFFFFULL); + } + arch_fpop_end(env); + return out_f64; +} + +float32 HELPER(conv_df2sf)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + float32 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) +{ + arch_fpop_start(env); + float32 RdV = uint32_to_float32(RsV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +float64 HELPER(conv_uw2df)(CPUHexagonState *env, int32_t RsV) +{ + arch_fpop_start(env); + float64 RddV = uint32_to_float64(RsV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float32 HELPER(conv_w2sf)(CPUHexagonState *env, int32_t RsV) +{ + arch_fpop_start(env); + float32 RdV = int32_to_float32(RsV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +float64 HELPER(conv_w2df)(CPUHexagonState *env, int32_t RsV) +{ + arch_fpop_start(env); + float64 RddV = int32_to_float64(RsV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float32 HELPER(conv_ud2sf)(CPUHexagonState *env, int64_t RssV) +{ + arch_fpop_start(env); + float32 RdV = uint64_to_float32(RssV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +float64 HELPER(conv_ud2df)(CPUHexagonState *env, int64_t RssV) +{ + arch_fpop_start(env); + float64 RddV = uint64_to_float64(RssV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float32 HELPER(conv_d2sf)(CPUHexagonState *env, int64_t RssV) +{ + arch_fpop_start(env); + float32 RdV = int64_to_float32(RssV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +float64 HELPER(conv_d2df)(CPUHexagonState *env, int64_t RssV) +{ + arch_fpop_start(env); + float64 RddV = int64_to_float64(RssV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int32_t HELPER(conv_sf2uw)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + int32_t RdV = conv_sf_to_4u(RsV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int32_t HELPER(conv_sf2w)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + int32_t RdV = conv_sf_to_4s(RsV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int64_t HELPER(conv_sf2ud)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + int64_t RddV = conv_sf_to_8u(RsV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int64_t HELPER(conv_sf2d)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + int64_t RddV = conv_sf_to_8s(RsV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int32_t HELPER(conv_df2uw)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + int32_t RdV = conv_df_to_4u(RssV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int32_t HELPER(conv_df2w)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + int32_t RdV = conv_df_to_4s(RssV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int64_t HELPER(conv_df2ud)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + int64_t RddV = conv_df_to_8u(RssV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int64_t HELPER(conv_df2d)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + int64_t RddV = conv_df_to_8s(RssV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int32_t HELPER(conv_sf2uw_chop)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int32_t RdV = conv_sf_to_4u(RsV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int32_t HELPER(conv_sf2w_chop)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int32_t RdV = conv_sf_to_4s(RsV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int64_t HELPER(conv_sf2ud_chop)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int64_t RddV = conv_sf_to_8u(RsV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int64_t HELPER(conv_sf2d_chop)(CPUHexagonState *env, float32 RsV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int64_t RddV = conv_sf_to_8s(RsV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int32_t HELPER(conv_df2uw_chop)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int32_t RdV = conv_df_to_4u(RssV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int32_t HELPER(conv_df2w_chop)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int32_t RdV = conv_df_to_4s(RssV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int64_t HELPER(conv_df2ud_chop)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int64_t RddV = conv_df_to_8u(RssV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int64_t HELPER(conv_df2d_chop)(CPUHexagonState *env, float64 RssV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_to_zero, &env->fp_status); + int64_t RddV = conv_df_to_8s(RssV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float32 HELPER(sfadd)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + float32 RdV = float32_add(RsV, RtV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +float32 HELPER(sfsub)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + float32 RdV = float32_sub(RsV, RtV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int32_t HELPER(sfcmpeq)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + int32_t PdV = f8BITSOF(float32_eq(RsV, RtV, &env->fp_status)); + arch_fpop_end(env); + return PdV; +} + +int32_t HELPER(sfcmpgt)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + int cmp = float32_compare(RsV, RtV, &env->fp_status); + int32_t PdV = f8BITSOF(cmp == float_relation_greater); + arch_fpop_end(env); + return PdV; +} + +int32_t HELPER(sfcmpge)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + int cmp = float32_compare(RsV, RtV, &env->fp_status); + int32_t 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) +{ + arch_fpop_start(env); + int32_t 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) +{ + arch_fpop_start(env); + float32 RdV = float32_max(RsV, RtV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +float32 HELPER(sfmin)(CPUHexagonState *env, float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + float32 RdV = float32_min(RsV, RtV, &env->fp_status); + arch_fpop_end(env); + return RdV; +} + +int32_t HELPER(sfclass)(CPUHexagonState *env, float32 RsV, int32_t uiV) +{ + arch_fpop_start(env); + int32_t PdV = 0; + 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; + arch_fpop_start(env); + int adjust; + 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; + arch_fpop_start(env); + int adjust; + 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; + arch_fpop_start(env); + int adjust; + 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) +{ + arch_fpop_start(env); + float64 RddV = float64_add(RssV, RttV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float64 HELPER(dfsub)(CPUHexagonState *env, float64 RssV, float64 RttV) +{ + arch_fpop_start(env); + float64 RddV = float64_sub(RssV, RttV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float64 HELPER(dfmax)(CPUHexagonState *env, float64 RssV, float64 RttV) +{ + arch_fpop_start(env); + float64 RddV = float64_max(RssV, RttV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +float64 HELPER(dfmin)(CPUHexagonState *env, float64 RssV, float64 RttV) +{ + arch_fpop_start(env); + float64 RddV = float64_min(RssV, RttV, &env->fp_status); + arch_fpop_end(env); + return RddV; +} + +int32_t HELPER(dfcmpeq)(CPUHexagonState *env, float64 RssV, float64 RttV) +{ + arch_fpop_start(env); + int32_t PdV = f8BITSOF(float64_eq(RssV, RttV, &env->fp_status)); + arch_fpop_end(env); + return PdV; +} + +int32_t HELPER(dfcmpgt)(CPUHexagonState *env, float64 RssV, float64 RttV) +{ + arch_fpop_start(env); + int cmp = float64_compare(RssV, RttV, &env->fp_status); + int32_t PdV = f8BITSOF(cmp == float_relation_greater); + arch_fpop_end(env); + return PdV; +} + +int32_t HELPER(dfcmpge)(CPUHexagonState *env, float64 RssV, float64 RttV) +{ + arch_fpop_start(env); + int cmp = float64_compare(RssV, RttV, &env->fp_status); + int32_t 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) +{ + arch_fpop_start(env); + int32_t 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) +{ + arch_fpop_start(env); + int32_t PdV = 0; + 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) +{ + arch_fpop_start(env); + float32 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 isfinite(float32 x) +{ + return !float32_is_any_nan(x) && !float32_is_infinity(x); +} + +static bool is_zero_prod(float32 a, float32 b) +{ + return ((float32_is_zero(a) && isfinite(b)) || + (float32_is_zero(b) && isfinite(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) +{ + arch_fpop_start(env); + size4s_t tmp; + 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) +{ + arch_fpop_start(env); + float32 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 inline bool is_inf_prod(int32_t a, int32_t b) +{ + return (float32_is_infinity(a) && float32_is_infinity(b)) || + (float32_is_infinity(a) && isfinite(b) && !float32_is_zero(b)) || + (float32_is_infinity(b) && isfinite(a) && !float32_is_zero(a)); +} + +float32 HELPER(sffma_lib)(CPUHexagonState *env, float32 RxV, + float32 RsV, float32 RtV) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + int infinp; + int infminusinf; + float32 tmp; + 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) +{ + arch_fpop_start(env); + set_float_rounding_mode(float_round_nearest_even, &env->fp_status); + int infinp; + int infminusinf; + float32 tmp; + 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; + 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.h"