1996a729fSBastian Koppelmann /* 2996a729fSBastian Koppelmann * TriCore emulation for qemu: fpu helper. 3996a729fSBastian Koppelmann * 4996a729fSBastian Koppelmann * Copyright (c) 2016 Bastian Koppelmann University of Paderborn 5996a729fSBastian Koppelmann * 6996a729fSBastian Koppelmann * This library is free software; you can redistribute it and/or 7996a729fSBastian Koppelmann * modify it under the terms of the GNU Lesser General Public 8996a729fSBastian Koppelmann * License as published by the Free Software Foundation; either 902754acdSThomas Huth * version 2.1 of the License, or (at your option) any later version. 10996a729fSBastian Koppelmann * 11996a729fSBastian Koppelmann * This library is distributed in the hope that it will be useful, 12996a729fSBastian Koppelmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 13996a729fSBastian Koppelmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14996a729fSBastian Koppelmann * Lesser General Public License for more details. 15996a729fSBastian Koppelmann * 16996a729fSBastian Koppelmann * You should have received a copy of the GNU Lesser General Public 17996a729fSBastian Koppelmann * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18996a729fSBastian Koppelmann */ 19996a729fSBastian Koppelmann 20996a729fSBastian Koppelmann #include "qemu/osdep.h" 21996a729fSBastian Koppelmann #include "cpu.h" 22996a729fSBastian Koppelmann #include "exec/helper-proto.h" 2324f91e81SAlex Bennée #include "fpu/softfloat.h" 24996a729fSBastian Koppelmann 25ddd7feadSBastian Koppelmann #define QUIET_NAN 0x7fc00000 26ddd7feadSBastian Koppelmann #define ADD_NAN 0x7fc00001 278317ea06SAndreas Konopik #define SQRT_NAN 0x7fc00004 28996a729fSBastian Koppelmann #define DIV_NAN 0x7fc00008 29996a729fSBastian Koppelmann #define MUL_NAN 0x7fc00002 30996a729fSBastian Koppelmann #define FPU_FS PSW_USB_C 31996a729fSBastian Koppelmann #define FPU_FI PSW_USB_V 32996a729fSBastian Koppelmann #define FPU_FV PSW_USB_SV 33996a729fSBastian Koppelmann #define FPU_FZ PSW_USB_AV 34996a729fSBastian Koppelmann #define FPU_FU PSW_USB_SAV 35996a729fSBastian Koppelmann 368317ea06SAndreas Konopik #define float32_sqrt_nan make_float32(SQRT_NAN) 378317ea06SAndreas Konopik #define float32_quiet_nan make_float32(QUIET_NAN) 388317ea06SAndreas Konopik 39996a729fSBastian Koppelmann /* we don't care about input_denormal */ 40996a729fSBastian Koppelmann static inline uint8_t f_get_excp_flags(CPUTriCoreState *env) 41996a729fSBastian Koppelmann { 42996a729fSBastian Koppelmann return get_float_exception_flags(&env->fp_status) 43996a729fSBastian Koppelmann & (float_flag_invalid 44996a729fSBastian Koppelmann | float_flag_overflow 45996a729fSBastian Koppelmann | float_flag_underflow 46996a729fSBastian Koppelmann | float_flag_output_denormal 47996a729fSBastian Koppelmann | float_flag_divbyzero 48996a729fSBastian Koppelmann | float_flag_inexact); 49996a729fSBastian Koppelmann } 50996a729fSBastian Koppelmann 51ddd7feadSBastian Koppelmann static inline float32 f_maddsub_nan_result(float32 arg1, float32 arg2, 52ddd7feadSBastian Koppelmann float32 arg3, float32 result, 53ddd7feadSBastian Koppelmann uint32_t muladd_negate_c) 54ddd7feadSBastian Koppelmann { 55ddd7feadSBastian Koppelmann uint32_t aSign, bSign, cSign; 56ddd7feadSBastian Koppelmann uint32_t aExp, bExp, cExp; 57ddd7feadSBastian Koppelmann 58ddd7feadSBastian Koppelmann if (float32_is_any_nan(arg1) || float32_is_any_nan(arg2) || 59ddd7feadSBastian Koppelmann float32_is_any_nan(arg3)) { 60ddd7feadSBastian Koppelmann return QUIET_NAN; 61ddd7feadSBastian Koppelmann } else if (float32_is_infinity(arg1) && float32_is_zero(arg2)) { 62ddd7feadSBastian Koppelmann return MUL_NAN; 63ddd7feadSBastian Koppelmann } else if (float32_is_zero(arg1) && float32_is_infinity(arg2)) { 64ddd7feadSBastian Koppelmann return MUL_NAN; 65ddd7feadSBastian Koppelmann } else { 66ddd7feadSBastian Koppelmann aSign = arg1 >> 31; 67ddd7feadSBastian Koppelmann bSign = arg2 >> 31; 68ddd7feadSBastian Koppelmann cSign = arg3 >> 31; 69ddd7feadSBastian Koppelmann 70ddd7feadSBastian Koppelmann aExp = (arg1 >> 23) & 0xff; 71ddd7feadSBastian Koppelmann bExp = (arg2 >> 23) & 0xff; 72ddd7feadSBastian Koppelmann cExp = (arg3 >> 23) & 0xff; 73ddd7feadSBastian Koppelmann 74ddd7feadSBastian Koppelmann if (muladd_negate_c) { 75ddd7feadSBastian Koppelmann cSign ^= 1; 76ddd7feadSBastian Koppelmann } 77ddd7feadSBastian Koppelmann if (((aExp == 0xff) || (bExp == 0xff)) && (cExp == 0xff)) { 78ddd7feadSBastian Koppelmann if (aSign ^ bSign ^ cSign) { 79ddd7feadSBastian Koppelmann return ADD_NAN; 80ddd7feadSBastian Koppelmann } 81ddd7feadSBastian Koppelmann } 82ddd7feadSBastian Koppelmann } 83ddd7feadSBastian Koppelmann 84ddd7feadSBastian Koppelmann return result; 85ddd7feadSBastian Koppelmann } 86ddd7feadSBastian Koppelmann 87baf410dcSBastian Koppelmann static void f_update_psw_flags(CPUTriCoreState *env, uint8_t flags) 88996a729fSBastian Koppelmann { 89996a729fSBastian Koppelmann uint8_t some_excp = 0; 90996a729fSBastian Koppelmann set_float_exception_flags(0, &env->fp_status); 91996a729fSBastian Koppelmann 92996a729fSBastian Koppelmann if (flags & float_flag_invalid) { 93996a729fSBastian Koppelmann env->FPU_FI = 1 << 31; 94996a729fSBastian Koppelmann some_excp = 1; 95996a729fSBastian Koppelmann } 96996a729fSBastian Koppelmann 97996a729fSBastian Koppelmann if (flags & float_flag_overflow) { 98996a729fSBastian Koppelmann env->FPU_FV = 1 << 31; 99996a729fSBastian Koppelmann some_excp = 1; 100996a729fSBastian Koppelmann } 101996a729fSBastian Koppelmann 102996a729fSBastian Koppelmann if (flags & float_flag_underflow || flags & float_flag_output_denormal) { 103996a729fSBastian Koppelmann env->FPU_FU = 1 << 31; 104996a729fSBastian Koppelmann some_excp = 1; 105996a729fSBastian Koppelmann } 106996a729fSBastian Koppelmann 107996a729fSBastian Koppelmann if (flags & float_flag_divbyzero) { 108996a729fSBastian Koppelmann env->FPU_FZ = 1 << 31; 109996a729fSBastian Koppelmann some_excp = 1; 110996a729fSBastian Koppelmann } 111996a729fSBastian Koppelmann 112996a729fSBastian Koppelmann if (flags & float_flag_inexact || flags & float_flag_output_denormal) { 113996a729fSBastian Koppelmann env->PSW |= 1 << 26; 114996a729fSBastian Koppelmann some_excp = 1; 115996a729fSBastian Koppelmann } 116996a729fSBastian Koppelmann 117996a729fSBastian Koppelmann env->FPU_FS = some_excp; 118996a729fSBastian Koppelmann } 119baf410dcSBastian Koppelmann 120baf410dcSBastian Koppelmann #define FADD_SUB(op) \ 121baf410dcSBastian Koppelmann uint32_t helper_f##op(CPUTriCoreState *env, uint32_t r1, uint32_t r2) \ 122baf410dcSBastian Koppelmann { \ 123baf410dcSBastian Koppelmann float32 arg1 = make_float32(r1); \ 124baf410dcSBastian Koppelmann float32 arg2 = make_float32(r2); \ 125baf410dcSBastian Koppelmann uint32_t flags; \ 126baf410dcSBastian Koppelmann float32 f_result; \ 127baf410dcSBastian Koppelmann \ 128baf410dcSBastian Koppelmann f_result = float32_##op(arg2, arg1, &env->fp_status); \ 129baf410dcSBastian Koppelmann flags = f_get_excp_flags(env); \ 130baf410dcSBastian Koppelmann if (flags) { \ 131baf410dcSBastian Koppelmann /* If the output is a NaN, but the inputs aren't, \ 132baf410dcSBastian Koppelmann we return a unique value. */ \ 133baf410dcSBastian Koppelmann if ((flags & float_flag_invalid) \ 134baf410dcSBastian Koppelmann && !float32_is_any_nan(arg1) \ 135baf410dcSBastian Koppelmann && !float32_is_any_nan(arg2)) { \ 136baf410dcSBastian Koppelmann f_result = ADD_NAN; \ 137baf410dcSBastian Koppelmann } \ 138baf410dcSBastian Koppelmann f_update_psw_flags(env, flags); \ 139baf410dcSBastian Koppelmann } else { \ 140baf410dcSBastian Koppelmann env->FPU_FS = 0; \ 141baf410dcSBastian Koppelmann } \ 142baf410dcSBastian Koppelmann return (uint32_t)f_result; \ 143baf410dcSBastian Koppelmann } 144baf410dcSBastian Koppelmann FADD_SUB(add) 145baf410dcSBastian Koppelmann FADD_SUB(sub) 146daab3f7fSBastian Koppelmann 147daab3f7fSBastian Koppelmann uint32_t helper_fmul(CPUTriCoreState *env, uint32_t r1, uint32_t r2) 148daab3f7fSBastian Koppelmann { 149daab3f7fSBastian Koppelmann uint32_t flags; 150daab3f7fSBastian Koppelmann float32 arg1 = make_float32(r1); 151daab3f7fSBastian Koppelmann float32 arg2 = make_float32(r2); 152daab3f7fSBastian Koppelmann float32 f_result; 153daab3f7fSBastian Koppelmann 154daab3f7fSBastian Koppelmann f_result = float32_mul(arg1, arg2, &env->fp_status); 155daab3f7fSBastian Koppelmann 156daab3f7fSBastian Koppelmann flags = f_get_excp_flags(env); 157daab3f7fSBastian Koppelmann if (flags) { 158daab3f7fSBastian Koppelmann /* If the output is a NaN, but the inputs aren't, 159daab3f7fSBastian Koppelmann we return a unique value. */ 160daab3f7fSBastian Koppelmann if ((flags & float_flag_invalid) 161daab3f7fSBastian Koppelmann && !float32_is_any_nan(arg1) 162daab3f7fSBastian Koppelmann && !float32_is_any_nan(arg2)) { 163daab3f7fSBastian Koppelmann f_result = MUL_NAN; 164daab3f7fSBastian Koppelmann } 165daab3f7fSBastian Koppelmann f_update_psw_flags(env, flags); 166daab3f7fSBastian Koppelmann } else { 167daab3f7fSBastian Koppelmann env->FPU_FS = 0; 168daab3f7fSBastian Koppelmann } 169daab3f7fSBastian Koppelmann return (uint32_t)f_result; 170daab3f7fSBastian Koppelmann 171daab3f7fSBastian Koppelmann } 172446ee5b2SBastian Koppelmann 1738317ea06SAndreas Konopik /* 1748317ea06SAndreas Konopik * Target TriCore QSEED.F significand Lookup Table 1758317ea06SAndreas Konopik * 1768317ea06SAndreas Konopik * The QSEED.F output significand depends on the least-significant 1778317ea06SAndreas Konopik * exponent bit and the 6 most-significant significand bits. 1788317ea06SAndreas Konopik * 1798317ea06SAndreas Konopik * IEEE 754 float datatype 1808317ea06SAndreas Konopik * partitioned into Sign (S), Exponent (E) and Significand (M): 1818317ea06SAndreas Konopik * 1828317ea06SAndreas Konopik * S E E E E E E E E M M M M M M ... 1838317ea06SAndreas Konopik * | | | 1848317ea06SAndreas Konopik * +------+------+-------+-------+ 1858317ea06SAndreas Konopik * | | 1868317ea06SAndreas Konopik * for lookup table 1878317ea06SAndreas Konopik * calculating index for 1888317ea06SAndreas Konopik * output E output M 1898317ea06SAndreas Konopik * 1908317ea06SAndreas Konopik * This lookup table was extracted by analyzing QSEED output 1918317ea06SAndreas Konopik * from the real hardware 1928317ea06SAndreas Konopik */ 1938317ea06SAndreas Konopik static const uint8_t target_qseed_significand_table[128] = { 1948317ea06SAndreas Konopik 253, 252, 245, 244, 239, 238, 231, 230, 225, 224, 217, 216, 1958317ea06SAndreas Konopik 211, 210, 205, 204, 201, 200, 195, 194, 189, 188, 185, 184, 1968317ea06SAndreas Konopik 179, 178, 175, 174, 169, 168, 165, 164, 161, 160, 157, 156, 1978317ea06SAndreas Konopik 153, 152, 149, 148, 145, 144, 141, 140, 137, 136, 133, 132, 1988317ea06SAndreas Konopik 131, 130, 127, 126, 123, 122, 121, 120, 117, 116, 115, 114, 1998317ea06SAndreas Konopik 111, 110, 109, 108, 103, 102, 99, 98, 93, 92, 89, 88, 83, 2008317ea06SAndreas Konopik 82, 79, 78, 75, 74, 71, 70, 67, 66, 63, 62, 59, 58, 55, 2018317ea06SAndreas Konopik 54, 53, 52, 49, 48, 45, 44, 43, 42, 39, 38, 37, 36, 33, 2028317ea06SAndreas Konopik 32, 31, 30, 27, 26, 25, 24, 23, 22, 19, 18, 17, 16, 15, 2038317ea06SAndreas Konopik 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 2048317ea06SAndreas Konopik }; 2058317ea06SAndreas Konopik 2068317ea06SAndreas Konopik uint32_t helper_qseed(CPUTriCoreState *env, uint32_t r1) 2078317ea06SAndreas Konopik { 2088317ea06SAndreas Konopik uint32_t arg1, S, E, M, E_minus_one, m_idx; 2098317ea06SAndreas Konopik uint32_t new_E, new_M, new_S, result; 2108317ea06SAndreas Konopik 2118317ea06SAndreas Konopik arg1 = make_float32(r1); 2128317ea06SAndreas Konopik 2138317ea06SAndreas Konopik /* fetch IEEE-754 fields S, E and the uppermost 6-bit of M */ 2148317ea06SAndreas Konopik S = extract32(arg1, 31, 1); 2158317ea06SAndreas Konopik E = extract32(arg1, 23, 8); 2168317ea06SAndreas Konopik M = extract32(arg1, 17, 6); 2178317ea06SAndreas Konopik 2188317ea06SAndreas Konopik if (float32_is_any_nan(arg1)) { 2198317ea06SAndreas Konopik result = float32_quiet_nan; 2208317ea06SAndreas Konopik } else if (float32_is_zero_or_denormal(arg1)) { 2218317ea06SAndreas Konopik if (float32_is_neg(arg1)) { 2228317ea06SAndreas Konopik result = float32_infinity | (1 << 31); 2238317ea06SAndreas Konopik } else { 2248317ea06SAndreas Konopik result = float32_infinity; 2258317ea06SAndreas Konopik } 2268317ea06SAndreas Konopik } else if (float32_is_neg(arg1)) { 2278317ea06SAndreas Konopik result = float32_sqrt_nan; 2288317ea06SAndreas Konopik } else if (float32_is_infinity(arg1)) { 2298317ea06SAndreas Konopik result = float32_zero; 2308317ea06SAndreas Konopik } else { 2318317ea06SAndreas Konopik E_minus_one = E - 1; 2328317ea06SAndreas Konopik m_idx = ((E_minus_one & 1) << 6) | M; 2338317ea06SAndreas Konopik new_S = S; 2348317ea06SAndreas Konopik new_E = 0xBD - E_minus_one / 2; 2358317ea06SAndreas Konopik new_M = target_qseed_significand_table[m_idx]; 2368317ea06SAndreas Konopik 2378317ea06SAndreas Konopik result = 0; 2388317ea06SAndreas Konopik result = deposit32(result, 31, 1, new_S); 2398317ea06SAndreas Konopik result = deposit32(result, 23, 8, new_E); 2408317ea06SAndreas Konopik result = deposit32(result, 15, 8, new_M); 2418317ea06SAndreas Konopik } 2428317ea06SAndreas Konopik 2438317ea06SAndreas Konopik if (float32_is_signaling_nan(arg1, &env->fp_status) 2448317ea06SAndreas Konopik || result == float32_sqrt_nan) { 2458317ea06SAndreas Konopik env->FPU_FI = 1 << 31; 2468317ea06SAndreas Konopik env->FPU_FS = 1; 2478317ea06SAndreas Konopik } else { 2488317ea06SAndreas Konopik env->FPU_FS = 0; 2498317ea06SAndreas Konopik } 2508317ea06SAndreas Konopik 2518317ea06SAndreas Konopik return (uint32_t) result; 2528317ea06SAndreas Konopik } 2538317ea06SAndreas Konopik 254446ee5b2SBastian Koppelmann uint32_t helper_fdiv(CPUTriCoreState *env, uint32_t r1, uint32_t r2) 255446ee5b2SBastian Koppelmann { 256446ee5b2SBastian Koppelmann uint32_t flags; 257446ee5b2SBastian Koppelmann float32 arg1 = make_float32(r1); 258446ee5b2SBastian Koppelmann float32 arg2 = make_float32(r2); 259446ee5b2SBastian Koppelmann float32 f_result; 260446ee5b2SBastian Koppelmann 261446ee5b2SBastian Koppelmann f_result = float32_div(arg1, arg2 , &env->fp_status); 262446ee5b2SBastian Koppelmann 263446ee5b2SBastian Koppelmann flags = f_get_excp_flags(env); 264446ee5b2SBastian Koppelmann if (flags) { 265446ee5b2SBastian Koppelmann /* If the output is a NaN, but the inputs aren't, 266446ee5b2SBastian Koppelmann we return a unique value. */ 267446ee5b2SBastian Koppelmann if ((flags & float_flag_invalid) 268446ee5b2SBastian Koppelmann && !float32_is_any_nan(arg1) 269446ee5b2SBastian Koppelmann && !float32_is_any_nan(arg2)) { 270446ee5b2SBastian Koppelmann f_result = DIV_NAN; 271446ee5b2SBastian Koppelmann } 272446ee5b2SBastian Koppelmann f_update_psw_flags(env, flags); 273446ee5b2SBastian Koppelmann } else { 274446ee5b2SBastian Koppelmann env->FPU_FS = 0; 275446ee5b2SBastian Koppelmann } 276446ee5b2SBastian Koppelmann 277446ee5b2SBastian Koppelmann return (uint32_t)f_result; 278446ee5b2SBastian Koppelmann } 279743cd09dSBastian Koppelmann 280ddd7feadSBastian Koppelmann uint32_t helper_fmadd(CPUTriCoreState *env, uint32_t r1, 281ddd7feadSBastian Koppelmann uint32_t r2, uint32_t r3) 282ddd7feadSBastian Koppelmann { 283ddd7feadSBastian Koppelmann uint32_t flags; 284ddd7feadSBastian Koppelmann float32 arg1 = make_float32(r1); 285ddd7feadSBastian Koppelmann float32 arg2 = make_float32(r2); 286ddd7feadSBastian Koppelmann float32 arg3 = make_float32(r3); 287ddd7feadSBastian Koppelmann float32 f_result; 288ddd7feadSBastian Koppelmann 289ddd7feadSBastian Koppelmann f_result = float32_muladd(arg1, arg2, arg3, 0, &env->fp_status); 290ddd7feadSBastian Koppelmann 291ddd7feadSBastian Koppelmann flags = f_get_excp_flags(env); 292ddd7feadSBastian Koppelmann if (flags) { 293ddd7feadSBastian Koppelmann if (flags & float_flag_invalid) { 294ddd7feadSBastian Koppelmann arg1 = float32_squash_input_denormal(arg1, &env->fp_status); 295ddd7feadSBastian Koppelmann arg2 = float32_squash_input_denormal(arg2, &env->fp_status); 296ddd7feadSBastian Koppelmann arg3 = float32_squash_input_denormal(arg3, &env->fp_status); 297ddd7feadSBastian Koppelmann f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, 0); 298ddd7feadSBastian Koppelmann } 299ddd7feadSBastian Koppelmann f_update_psw_flags(env, flags); 300ddd7feadSBastian Koppelmann } else { 301ddd7feadSBastian Koppelmann env->FPU_FS = 0; 302ddd7feadSBastian Koppelmann } 303ddd7feadSBastian Koppelmann return (uint32_t)f_result; 304ddd7feadSBastian Koppelmann } 305ddd7feadSBastian Koppelmann 306ddd7feadSBastian Koppelmann uint32_t helper_fmsub(CPUTriCoreState *env, uint32_t r1, 307ddd7feadSBastian Koppelmann uint32_t r2, uint32_t r3) 308ddd7feadSBastian Koppelmann { 309ddd7feadSBastian Koppelmann uint32_t flags; 310ddd7feadSBastian Koppelmann float32 arg1 = make_float32(r1); 311ddd7feadSBastian Koppelmann float32 arg2 = make_float32(r2); 312ddd7feadSBastian Koppelmann float32 arg3 = make_float32(r3); 313ddd7feadSBastian Koppelmann float32 f_result; 314ddd7feadSBastian Koppelmann 315ddd7feadSBastian Koppelmann f_result = float32_muladd(arg1, arg2, arg3, float_muladd_negate_product, 316ddd7feadSBastian Koppelmann &env->fp_status); 317ddd7feadSBastian Koppelmann 318ddd7feadSBastian Koppelmann flags = f_get_excp_flags(env); 319ddd7feadSBastian Koppelmann if (flags) { 320ddd7feadSBastian Koppelmann if (flags & float_flag_invalid) { 321ddd7feadSBastian Koppelmann arg1 = float32_squash_input_denormal(arg1, &env->fp_status); 322ddd7feadSBastian Koppelmann arg2 = float32_squash_input_denormal(arg2, &env->fp_status); 323ddd7feadSBastian Koppelmann arg3 = float32_squash_input_denormal(arg3, &env->fp_status); 324ddd7feadSBastian Koppelmann 325ddd7feadSBastian Koppelmann f_result = f_maddsub_nan_result(arg1, arg2, arg3, f_result, 1); 326ddd7feadSBastian Koppelmann } 327ddd7feadSBastian Koppelmann f_update_psw_flags(env, flags); 328ddd7feadSBastian Koppelmann } else { 329ddd7feadSBastian Koppelmann env->FPU_FS = 0; 330ddd7feadSBastian Koppelmann } 331ddd7feadSBastian Koppelmann return (uint32_t)f_result; 332ddd7feadSBastian Koppelmann } 333ddd7feadSBastian Koppelmann 334743cd09dSBastian Koppelmann uint32_t helper_fcmp(CPUTriCoreState *env, uint32_t r1, uint32_t r2) 335743cd09dSBastian Koppelmann { 336743cd09dSBastian Koppelmann uint32_t result, flags; 337743cd09dSBastian Koppelmann float32 arg1 = make_float32(r1); 338743cd09dSBastian Koppelmann float32 arg2 = make_float32(r2); 339743cd09dSBastian Koppelmann 340743cd09dSBastian Koppelmann set_flush_inputs_to_zero(0, &env->fp_status); 341743cd09dSBastian Koppelmann 342743cd09dSBastian Koppelmann result = 1 << (float32_compare_quiet(arg1, arg2, &env->fp_status) + 1); 343b8c54700SEmilio G. Cota result |= float32_is_denormal(arg1) << 4; 344b8c54700SEmilio G. Cota result |= float32_is_denormal(arg2) << 5; 345743cd09dSBastian Koppelmann 346743cd09dSBastian Koppelmann flags = f_get_excp_flags(env); 347743cd09dSBastian Koppelmann if (flags) { 348743cd09dSBastian Koppelmann f_update_psw_flags(env, flags); 349743cd09dSBastian Koppelmann } else { 350743cd09dSBastian Koppelmann env->FPU_FS = 0; 351743cd09dSBastian Koppelmann } 352743cd09dSBastian Koppelmann 353743cd09dSBastian Koppelmann set_flush_inputs_to_zero(1, &env->fp_status); 354743cd09dSBastian Koppelmann return result; 355743cd09dSBastian Koppelmann } 3560d4c3b80SBastian Koppelmann 3570d4c3b80SBastian Koppelmann uint32_t helper_ftoi(CPUTriCoreState *env, uint32_t arg) 3580d4c3b80SBastian Koppelmann { 3590d4c3b80SBastian Koppelmann float32 f_arg = make_float32(arg); 3600d4c3b80SBastian Koppelmann int32_t result, flags; 3610d4c3b80SBastian Koppelmann 3620d4c3b80SBastian Koppelmann result = float32_to_int32(f_arg, &env->fp_status); 3630d4c3b80SBastian Koppelmann 3640d4c3b80SBastian Koppelmann flags = f_get_excp_flags(env); 3650d4c3b80SBastian Koppelmann if (flags) { 3660d4c3b80SBastian Koppelmann if (float32_is_any_nan(f_arg)) { 3670d4c3b80SBastian Koppelmann result = 0; 3680d4c3b80SBastian Koppelmann } 3690d4c3b80SBastian Koppelmann f_update_psw_flags(env, flags); 3700d4c3b80SBastian Koppelmann } else { 3710d4c3b80SBastian Koppelmann env->FPU_FS = 0; 3720d4c3b80SBastian Koppelmann } 3730d4c3b80SBastian Koppelmann return (uint32_t)result; 3740d4c3b80SBastian Koppelmann } 3750d4c3b80SBastian Koppelmann 376*815061b9SBastian Koppelmann uint32_t helper_ftohp(CPUTriCoreState *env, uint32_t arg) 377*815061b9SBastian Koppelmann { 378*815061b9SBastian Koppelmann float32 f_arg = make_float32(arg); 379*815061b9SBastian Koppelmann uint32_t result = 0; 380*815061b9SBastian Koppelmann int32_t flags = 0; 381*815061b9SBastian Koppelmann 382*815061b9SBastian Koppelmann /* 383*815061b9SBastian Koppelmann * if we have any NAN we need to move the top 2 and lower 8 input mantissa 384*815061b9SBastian Koppelmann * bits to the top 2 and lower 8 output mantissa bits respectively. 385*815061b9SBastian Koppelmann * Softfloat on the other hand uses the top 10 mantissa bits. 386*815061b9SBastian Koppelmann */ 387*815061b9SBastian Koppelmann if (float32_is_any_nan(f_arg)) { 388*815061b9SBastian Koppelmann if (float32_is_signaling_nan(f_arg, &env->fp_status)) { 389*815061b9SBastian Koppelmann flags |= float_flag_invalid; 390*815061b9SBastian Koppelmann } 391*815061b9SBastian Koppelmann result = float16_set_sign(result, arg >> 31); 392*815061b9SBastian Koppelmann result = deposit32(result, 10, 5, 0x1f); 393*815061b9SBastian Koppelmann result = deposit32(result, 8, 2, extract32(arg, 21, 2)); 394*815061b9SBastian Koppelmann result = deposit32(result, 0, 8, extract32(arg, 0, 8)); 395*815061b9SBastian Koppelmann if (extract32(result, 0, 10) == 0) { 396*815061b9SBastian Koppelmann result |= (1 << 8); 397*815061b9SBastian Koppelmann } 398*815061b9SBastian Koppelmann } else { 399*815061b9SBastian Koppelmann set_flush_to_zero(0, &env->fp_status); 400*815061b9SBastian Koppelmann result = float32_to_float16(f_arg, true, &env->fp_status); 401*815061b9SBastian Koppelmann set_flush_to_zero(1, &env->fp_status); 402*815061b9SBastian Koppelmann flags = f_get_excp_flags(env); 403*815061b9SBastian Koppelmann } 404*815061b9SBastian Koppelmann 405*815061b9SBastian Koppelmann if (flags) { 406*815061b9SBastian Koppelmann f_update_psw_flags(env, flags); 407*815061b9SBastian Koppelmann } else { 408*815061b9SBastian Koppelmann env->FPU_FS = 0; 409*815061b9SBastian Koppelmann } 410*815061b9SBastian Koppelmann 411*815061b9SBastian Koppelmann return result; 412*815061b9SBastian Koppelmann } 413*815061b9SBastian Koppelmann 4140d4c3b80SBastian Koppelmann uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg) 4150d4c3b80SBastian Koppelmann { 4160d4c3b80SBastian Koppelmann float32 f_result; 4170d4c3b80SBastian Koppelmann uint32_t flags; 4180d4c3b80SBastian Koppelmann f_result = int32_to_float32(arg, &env->fp_status); 4190d4c3b80SBastian Koppelmann 4200d4c3b80SBastian Koppelmann flags = f_get_excp_flags(env); 4210d4c3b80SBastian Koppelmann if (flags) { 4220d4c3b80SBastian Koppelmann f_update_psw_flags(env, flags); 4230d4c3b80SBastian Koppelmann } else { 4240d4c3b80SBastian Koppelmann env->FPU_FS = 0; 4250d4c3b80SBastian Koppelmann } 4260d4c3b80SBastian Koppelmann return (uint32_t)f_result; 4270d4c3b80SBastian Koppelmann } 4288f75983dSBastian Koppelmann 4294e6fd2e3SDavid Brenken uint32_t helper_utof(CPUTriCoreState *env, uint32_t arg) 4304e6fd2e3SDavid Brenken { 4314e6fd2e3SDavid Brenken float32 f_result; 4324e6fd2e3SDavid Brenken uint32_t flags; 4334e6fd2e3SDavid Brenken 4344e6fd2e3SDavid Brenken f_result = uint32_to_float32(arg, &env->fp_status); 4354e6fd2e3SDavid Brenken 4364e6fd2e3SDavid Brenken flags = f_get_excp_flags(env); 4374e6fd2e3SDavid Brenken if (flags) { 4384e6fd2e3SDavid Brenken f_update_psw_flags(env, flags); 4394e6fd2e3SDavid Brenken } else { 4404e6fd2e3SDavid Brenken env->FPU_FS = 0; 4414e6fd2e3SDavid Brenken } 4424e6fd2e3SDavid Brenken return (uint32_t)f_result; 4434e6fd2e3SDavid Brenken } 4444e6fd2e3SDavid Brenken 4451fa79fb0SDavid Brenken uint32_t helper_ftoiz(CPUTriCoreState *env, uint32_t arg) 4461fa79fb0SDavid Brenken { 4471fa79fb0SDavid Brenken float32 f_arg = make_float32(arg); 4481fa79fb0SDavid Brenken uint32_t result; 4491fa79fb0SDavid Brenken int32_t flags; 4501fa79fb0SDavid Brenken 4511fa79fb0SDavid Brenken result = float32_to_int32_round_to_zero(f_arg, &env->fp_status); 4521fa79fb0SDavid Brenken 4531fa79fb0SDavid Brenken flags = f_get_excp_flags(env); 4541fa79fb0SDavid Brenken if (flags & float_flag_invalid) { 4551fa79fb0SDavid Brenken flags &= ~float_flag_inexact; 4561fa79fb0SDavid Brenken if (float32_is_any_nan(f_arg)) { 4571fa79fb0SDavid Brenken result = 0; 4581fa79fb0SDavid Brenken } 4591fa79fb0SDavid Brenken } 4601fa79fb0SDavid Brenken 4611fa79fb0SDavid Brenken if (flags) { 4621fa79fb0SDavid Brenken f_update_psw_flags(env, flags); 4631fa79fb0SDavid Brenken } else { 4641fa79fb0SDavid Brenken env->FPU_FS = 0; 4651fa79fb0SDavid Brenken } 4661fa79fb0SDavid Brenken 4671fa79fb0SDavid Brenken return result; 4681fa79fb0SDavid Brenken } 4691fa79fb0SDavid Brenken 4702bdbe356SBastian Koppelmann uint32_t helper_ftou(CPUTriCoreState *env, uint32_t arg) 4712bdbe356SBastian Koppelmann { 4722bdbe356SBastian Koppelmann float32 f_arg = make_float32(arg); 4732bdbe356SBastian Koppelmann uint32_t result; 4742bdbe356SBastian Koppelmann int32_t flags = 0; 4752bdbe356SBastian Koppelmann 4762bdbe356SBastian Koppelmann result = float32_to_uint32(f_arg, &env->fp_status); 4772bdbe356SBastian Koppelmann 4782bdbe356SBastian Koppelmann flags = f_get_excp_flags(env); 4792bdbe356SBastian Koppelmann if (flags & float_flag_invalid) { 4802bdbe356SBastian Koppelmann flags &= ~float_flag_inexact; 4812bdbe356SBastian Koppelmann if (float32_is_any_nan(f_arg)) { 4822bdbe356SBastian Koppelmann result = 0; 4832bdbe356SBastian Koppelmann } 4842bdbe356SBastian Koppelmann /* 4852bdbe356SBastian Koppelmann * we need to check arg < 0.0 before rounding as TriCore needs to raise 4862bdbe356SBastian Koppelmann * float_flag_invalid as well. For instance, when we have a negative 4872bdbe356SBastian Koppelmann * exponent and sign, softfloat would only raise float_flat_inexact. 4882bdbe356SBastian Koppelmann */ 4892bdbe356SBastian Koppelmann } else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) { 4902bdbe356SBastian Koppelmann flags = float_flag_invalid; 4912bdbe356SBastian Koppelmann result = 0; 4922bdbe356SBastian Koppelmann } 4932bdbe356SBastian Koppelmann 4942bdbe356SBastian Koppelmann if (flags) { 4952bdbe356SBastian Koppelmann f_update_psw_flags(env, flags); 4962bdbe356SBastian Koppelmann } else { 4972bdbe356SBastian Koppelmann env->FPU_FS = 0; 4982bdbe356SBastian Koppelmann } 4992bdbe356SBastian Koppelmann return result; 5002bdbe356SBastian Koppelmann } 5012bdbe356SBastian Koppelmann 5028f75983dSBastian Koppelmann uint32_t helper_ftouz(CPUTriCoreState *env, uint32_t arg) 5038f75983dSBastian Koppelmann { 5048f75983dSBastian Koppelmann float32 f_arg = make_float32(arg); 5058f75983dSBastian Koppelmann uint32_t result; 5068f75983dSBastian Koppelmann int32_t flags; 5078f75983dSBastian Koppelmann 5088f75983dSBastian Koppelmann result = float32_to_uint32_round_to_zero(f_arg, &env->fp_status); 5098f75983dSBastian Koppelmann 5108f75983dSBastian Koppelmann flags = f_get_excp_flags(env); 5118f75983dSBastian Koppelmann if (flags & float_flag_invalid) { 5128f75983dSBastian Koppelmann flags &= ~float_flag_inexact; 5138f75983dSBastian Koppelmann if (float32_is_any_nan(f_arg)) { 5148f75983dSBastian Koppelmann result = 0; 5158f75983dSBastian Koppelmann } 516e43692bcSBastian Koppelmann /* 517e43692bcSBastian Koppelmann * we need to check arg < 0.0 before rounding as TriCore needs to raise 518e43692bcSBastian Koppelmann * float_flag_invalid as well. For instance, when we have a negative 519e43692bcSBastian Koppelmann * exponent and sign, softfloat would only raise float_flat_inexact. 520e43692bcSBastian Koppelmann */ 5218f75983dSBastian Koppelmann } else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) { 5228f75983dSBastian Koppelmann flags = float_flag_invalid; 5238f75983dSBastian Koppelmann result = 0; 5248f75983dSBastian Koppelmann } 5258f75983dSBastian Koppelmann 5268f75983dSBastian Koppelmann if (flags) { 5278f75983dSBastian Koppelmann f_update_psw_flags(env, flags); 5288f75983dSBastian Koppelmann } else { 5298f75983dSBastian Koppelmann env->FPU_FS = 0; 5308f75983dSBastian Koppelmann } 5318f75983dSBastian Koppelmann return result; 5328f75983dSBastian Koppelmann } 53350788a3fSBastian Koppelmann 53450788a3fSBastian Koppelmann void helper_updfl(CPUTriCoreState *env, uint32_t arg) 53550788a3fSBastian Koppelmann { 53650788a3fSBastian Koppelmann env->FPU_FS = extract32(arg, 7, 1) & extract32(arg, 15, 1); 53750788a3fSBastian Koppelmann env->FPU_FI = (extract32(arg, 6, 1) & extract32(arg, 14, 1)) << 31; 53850788a3fSBastian Koppelmann env->FPU_FV = (extract32(arg, 5, 1) & extract32(arg, 13, 1)) << 31; 53950788a3fSBastian Koppelmann env->FPU_FZ = (extract32(arg, 4, 1) & extract32(arg, 12, 1)) << 31; 54050788a3fSBastian Koppelmann env->FPU_FU = (extract32(arg, 3, 1) & extract32(arg, 11, 1)) << 31; 54150788a3fSBastian Koppelmann /* clear FX and RM */ 54250788a3fSBastian Koppelmann env->PSW &= ~(extract32(arg, 10, 1) << 26); 54350788a3fSBastian Koppelmann env->PSW |= (extract32(arg, 2, 1) & extract32(arg, 10, 1)) << 26; 54450788a3fSBastian Koppelmann 54550788a3fSBastian Koppelmann fpu_set_state(env); 54650788a3fSBastian Koppelmann } 547