xref: /qemu/target/tricore/fpu_helper.c (revision fb49b69bf9fd584546c7d946eaeec90941941d25)
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 */
f_get_excp_flags(CPUTriCoreState * env)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
46*7af64d10SPeter Maydell               | float_flag_output_denormal_flushed
47996a729fSBastian Koppelmann               | float_flag_divbyzero
48996a729fSBastian Koppelmann               | float_flag_inexact);
49996a729fSBastian Koppelmann }
50996a729fSBastian Koppelmann 
f_maddsub_nan_result(float32 arg1,float32 arg2,float32 arg3,float32 result,uint32_t muladd_negate_c)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 
f_update_psw_flags(CPUTriCoreState * env,uint8_t flags)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 
102*7af64d10SPeter Maydell     if (flags & float_flag_underflow || flags & float_flag_output_denormal_flushed) {
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 
112*7af64d10SPeter Maydell     if (flags & float_flag_inexact || flags & float_flag_output_denormal_flushed) {
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)
FADD_SUB(sub)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 
helper_qseed(CPUTriCoreState * env,uint32_t r1)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 
helper_fdiv(CPUTriCoreState * env,uint32_t r1,uint32_t r2)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 
helper_fmadd(CPUTriCoreState * env,uint32_t r1,uint32_t r2,uint32_t r3)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 
helper_fmsub(CPUTriCoreState * env,uint32_t r1,uint32_t r2,uint32_t r3)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 
helper_fcmp(CPUTriCoreState * env,uint32_t r1,uint32_t r2)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 
helper_ftoi(CPUTriCoreState * env,uint32_t arg)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 
helper_hptof(CPUTriCoreState * env,uint32_t arg)3765e0e06d9SBastian Koppelmann uint32_t helper_hptof(CPUTriCoreState *env, uint32_t arg)
3775e0e06d9SBastian Koppelmann {
3785e0e06d9SBastian Koppelmann     float16 f_arg = make_float16(arg);
3795e0e06d9SBastian Koppelmann     uint32_t result = 0;
3805e0e06d9SBastian Koppelmann     int32_t flags = 0;
3815e0e06d9SBastian Koppelmann 
3825e0e06d9SBastian Koppelmann     /*
3835e0e06d9SBastian Koppelmann      * if we have any NAN we need to move the top 2 and lower 8 input mantissa
3845e0e06d9SBastian Koppelmann      * bits to the top 2 and lower 8 output mantissa bits respectively.
3855e0e06d9SBastian Koppelmann      * Softfloat on the other hand uses the top 10 mantissa bits.
3865e0e06d9SBastian Koppelmann      */
3875e0e06d9SBastian Koppelmann     if (float16_is_any_nan(f_arg)) {
3885e0e06d9SBastian Koppelmann         if (float16_is_signaling_nan(f_arg, &env->fp_status)) {
3895e0e06d9SBastian Koppelmann             flags |= float_flag_invalid;
3905e0e06d9SBastian Koppelmann         }
3915e0e06d9SBastian Koppelmann         result = 0;
3925e0e06d9SBastian Koppelmann         result = float32_set_sign(result, f_arg >> 15);
3935e0e06d9SBastian Koppelmann         result = deposit32(result, 23, 8, 0xff);
3945e0e06d9SBastian Koppelmann         result = deposit32(result, 21, 2, extract32(f_arg, 8, 2));
3955e0e06d9SBastian Koppelmann         result = deposit32(result, 0, 8, extract32(f_arg, 0, 8));
3965e0e06d9SBastian Koppelmann     } else {
3975e0e06d9SBastian Koppelmann         set_flush_inputs_to_zero(0, &env->fp_status);
3985e0e06d9SBastian Koppelmann         result = float16_to_float32(f_arg, true, &env->fp_status);
3995e0e06d9SBastian Koppelmann         set_flush_inputs_to_zero(1, &env->fp_status);
4005e0e06d9SBastian Koppelmann         flags = f_get_excp_flags(env);
4015e0e06d9SBastian Koppelmann     }
4025e0e06d9SBastian Koppelmann 
4035e0e06d9SBastian Koppelmann     if (flags) {
4045e0e06d9SBastian Koppelmann         f_update_psw_flags(env, flags);
4055e0e06d9SBastian Koppelmann     } else {
4065e0e06d9SBastian Koppelmann         env->FPU_FS = 0;
4075e0e06d9SBastian Koppelmann     }
4085e0e06d9SBastian Koppelmann 
4095e0e06d9SBastian Koppelmann     return result;
4105e0e06d9SBastian Koppelmann }
4115e0e06d9SBastian Koppelmann 
helper_ftohp(CPUTriCoreState * env,uint32_t arg)412815061b9SBastian Koppelmann uint32_t helper_ftohp(CPUTriCoreState *env, uint32_t arg)
413815061b9SBastian Koppelmann {
414815061b9SBastian Koppelmann     float32 f_arg = make_float32(arg);
415815061b9SBastian Koppelmann     uint32_t result = 0;
416815061b9SBastian Koppelmann     int32_t flags = 0;
417815061b9SBastian Koppelmann 
418815061b9SBastian Koppelmann     /*
419815061b9SBastian Koppelmann      * if we have any NAN we need to move the top 2 and lower 8 input mantissa
420815061b9SBastian Koppelmann      * bits to the top 2 and lower 8 output mantissa bits respectively.
421815061b9SBastian Koppelmann      * Softfloat on the other hand uses the top 10 mantissa bits.
422815061b9SBastian Koppelmann      */
423815061b9SBastian Koppelmann     if (float32_is_any_nan(f_arg)) {
424815061b9SBastian Koppelmann         if (float32_is_signaling_nan(f_arg, &env->fp_status)) {
425815061b9SBastian Koppelmann             flags |= float_flag_invalid;
426815061b9SBastian Koppelmann         }
427815061b9SBastian Koppelmann         result = float16_set_sign(result, arg >> 31);
428815061b9SBastian Koppelmann         result = deposit32(result, 10, 5, 0x1f);
429815061b9SBastian Koppelmann         result = deposit32(result, 8, 2, extract32(arg, 21, 2));
430815061b9SBastian Koppelmann         result = deposit32(result, 0, 8, extract32(arg, 0, 8));
431815061b9SBastian Koppelmann         if (extract32(result, 0, 10) == 0) {
432815061b9SBastian Koppelmann             result |= (1 << 8);
433815061b9SBastian Koppelmann         }
434815061b9SBastian Koppelmann     } else {
435815061b9SBastian Koppelmann         set_flush_to_zero(0, &env->fp_status);
436815061b9SBastian Koppelmann         result = float32_to_float16(f_arg, true, &env->fp_status);
437815061b9SBastian Koppelmann         set_flush_to_zero(1, &env->fp_status);
438815061b9SBastian Koppelmann         flags = f_get_excp_flags(env);
439815061b9SBastian Koppelmann     }
440815061b9SBastian Koppelmann 
441815061b9SBastian Koppelmann     if (flags) {
442815061b9SBastian Koppelmann         f_update_psw_flags(env, flags);
443815061b9SBastian Koppelmann     } else {
444815061b9SBastian Koppelmann         env->FPU_FS = 0;
445815061b9SBastian Koppelmann     }
446815061b9SBastian Koppelmann 
447815061b9SBastian Koppelmann     return result;
448815061b9SBastian Koppelmann }
449815061b9SBastian Koppelmann 
helper_itof(CPUTriCoreState * env,uint32_t arg)4500d4c3b80SBastian Koppelmann uint32_t helper_itof(CPUTriCoreState *env, uint32_t arg)
4510d4c3b80SBastian Koppelmann {
4520d4c3b80SBastian Koppelmann     float32 f_result;
4530d4c3b80SBastian Koppelmann     uint32_t flags;
4540d4c3b80SBastian Koppelmann     f_result = int32_to_float32(arg, &env->fp_status);
4550d4c3b80SBastian Koppelmann 
4560d4c3b80SBastian Koppelmann     flags = f_get_excp_flags(env);
4570d4c3b80SBastian Koppelmann     if (flags) {
4580d4c3b80SBastian Koppelmann         f_update_psw_flags(env, flags);
4590d4c3b80SBastian Koppelmann     } else {
4600d4c3b80SBastian Koppelmann         env->FPU_FS = 0;
4610d4c3b80SBastian Koppelmann     }
4620d4c3b80SBastian Koppelmann     return (uint32_t)f_result;
4630d4c3b80SBastian Koppelmann }
4648f75983dSBastian Koppelmann 
helper_utof(CPUTriCoreState * env,uint32_t arg)4654e6fd2e3SDavid Brenken uint32_t helper_utof(CPUTriCoreState *env, uint32_t arg)
4664e6fd2e3SDavid Brenken {
4674e6fd2e3SDavid Brenken     float32 f_result;
4684e6fd2e3SDavid Brenken     uint32_t flags;
4694e6fd2e3SDavid Brenken 
4704e6fd2e3SDavid Brenken     f_result = uint32_to_float32(arg, &env->fp_status);
4714e6fd2e3SDavid Brenken 
4724e6fd2e3SDavid Brenken     flags = f_get_excp_flags(env);
4734e6fd2e3SDavid Brenken     if (flags) {
4744e6fd2e3SDavid Brenken         f_update_psw_flags(env, flags);
4754e6fd2e3SDavid Brenken     } else {
4764e6fd2e3SDavid Brenken         env->FPU_FS = 0;
4774e6fd2e3SDavid Brenken     }
4784e6fd2e3SDavid Brenken     return (uint32_t)f_result;
4794e6fd2e3SDavid Brenken }
4804e6fd2e3SDavid Brenken 
helper_ftoiz(CPUTriCoreState * env,uint32_t arg)4811fa79fb0SDavid Brenken uint32_t helper_ftoiz(CPUTriCoreState *env, uint32_t arg)
4821fa79fb0SDavid Brenken {
4831fa79fb0SDavid Brenken     float32 f_arg = make_float32(arg);
4841fa79fb0SDavid Brenken     uint32_t result;
4851fa79fb0SDavid Brenken     int32_t flags;
4861fa79fb0SDavid Brenken 
4871fa79fb0SDavid Brenken     result = float32_to_int32_round_to_zero(f_arg, &env->fp_status);
4881fa79fb0SDavid Brenken 
4891fa79fb0SDavid Brenken     flags = f_get_excp_flags(env);
4901fa79fb0SDavid Brenken     if (flags & float_flag_invalid) {
4911fa79fb0SDavid Brenken         flags &= ~float_flag_inexact;
4921fa79fb0SDavid Brenken         if (float32_is_any_nan(f_arg)) {
4931fa79fb0SDavid Brenken             result = 0;
4941fa79fb0SDavid Brenken         }
4951fa79fb0SDavid Brenken     }
4961fa79fb0SDavid Brenken 
4971fa79fb0SDavid Brenken     if (flags) {
4981fa79fb0SDavid Brenken         f_update_psw_flags(env, flags);
4991fa79fb0SDavid Brenken     } else {
5001fa79fb0SDavid Brenken         env->FPU_FS = 0;
5011fa79fb0SDavid Brenken     }
5021fa79fb0SDavid Brenken 
5031fa79fb0SDavid Brenken     return result;
5041fa79fb0SDavid Brenken }
5051fa79fb0SDavid Brenken 
helper_ftou(CPUTriCoreState * env,uint32_t arg)5062bdbe356SBastian Koppelmann uint32_t helper_ftou(CPUTriCoreState *env, uint32_t arg)
5072bdbe356SBastian Koppelmann {
5082bdbe356SBastian Koppelmann     float32 f_arg = make_float32(arg);
5092bdbe356SBastian Koppelmann     uint32_t result;
5102bdbe356SBastian Koppelmann     int32_t flags = 0;
5112bdbe356SBastian Koppelmann 
5122bdbe356SBastian Koppelmann     result = float32_to_uint32(f_arg, &env->fp_status);
5132bdbe356SBastian Koppelmann 
5142bdbe356SBastian Koppelmann     flags = f_get_excp_flags(env);
5152bdbe356SBastian Koppelmann     if (flags & float_flag_invalid) {
5162bdbe356SBastian Koppelmann         flags &= ~float_flag_inexact;
5172bdbe356SBastian Koppelmann         if (float32_is_any_nan(f_arg)) {
5182bdbe356SBastian Koppelmann             result = 0;
5192bdbe356SBastian Koppelmann         }
5202bdbe356SBastian Koppelmann     /*
5212bdbe356SBastian Koppelmann      * we need to check arg < 0.0 before rounding as TriCore needs to raise
5222bdbe356SBastian Koppelmann      * float_flag_invalid as well. For instance, when we have a negative
5232bdbe356SBastian Koppelmann      * exponent and sign, softfloat would only raise float_flat_inexact.
5242bdbe356SBastian Koppelmann      */
5252bdbe356SBastian Koppelmann     } else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) {
5262bdbe356SBastian Koppelmann         flags = float_flag_invalid;
5272bdbe356SBastian Koppelmann         result = 0;
5282bdbe356SBastian Koppelmann     }
5292bdbe356SBastian Koppelmann 
5302bdbe356SBastian Koppelmann     if (flags) {
5312bdbe356SBastian Koppelmann         f_update_psw_flags(env, flags);
5322bdbe356SBastian Koppelmann     } else {
5332bdbe356SBastian Koppelmann         env->FPU_FS = 0;
5342bdbe356SBastian Koppelmann     }
5352bdbe356SBastian Koppelmann     return result;
5362bdbe356SBastian Koppelmann }
5372bdbe356SBastian Koppelmann 
helper_ftouz(CPUTriCoreState * env,uint32_t arg)5388f75983dSBastian Koppelmann uint32_t helper_ftouz(CPUTriCoreState *env, uint32_t arg)
5398f75983dSBastian Koppelmann {
5408f75983dSBastian Koppelmann     float32 f_arg = make_float32(arg);
5418f75983dSBastian Koppelmann     uint32_t result;
5428f75983dSBastian Koppelmann     int32_t flags;
5438f75983dSBastian Koppelmann 
5448f75983dSBastian Koppelmann     result = float32_to_uint32_round_to_zero(f_arg, &env->fp_status);
5458f75983dSBastian Koppelmann 
5468f75983dSBastian Koppelmann     flags = f_get_excp_flags(env);
5478f75983dSBastian Koppelmann     if (flags & float_flag_invalid) {
5488f75983dSBastian Koppelmann         flags &= ~float_flag_inexact;
5498f75983dSBastian Koppelmann         if (float32_is_any_nan(f_arg)) {
5508f75983dSBastian Koppelmann             result = 0;
5518f75983dSBastian Koppelmann         }
552e43692bcSBastian Koppelmann     /*
553e43692bcSBastian Koppelmann      * we need to check arg < 0.0 before rounding as TriCore needs to raise
554e43692bcSBastian Koppelmann      * float_flag_invalid as well. For instance, when we have a negative
555e43692bcSBastian Koppelmann      * exponent and sign, softfloat would only raise float_flat_inexact.
556e43692bcSBastian Koppelmann      */
5578f75983dSBastian Koppelmann     } else if (float32_lt_quiet(f_arg, 0, &env->fp_status)) {
5588f75983dSBastian Koppelmann         flags = float_flag_invalid;
5598f75983dSBastian Koppelmann         result = 0;
5608f75983dSBastian Koppelmann     }
5618f75983dSBastian Koppelmann 
5628f75983dSBastian Koppelmann     if (flags) {
5638f75983dSBastian Koppelmann         f_update_psw_flags(env, flags);
5648f75983dSBastian Koppelmann     } else {
5658f75983dSBastian Koppelmann         env->FPU_FS = 0;
5668f75983dSBastian Koppelmann     }
5678f75983dSBastian Koppelmann     return result;
5688f75983dSBastian Koppelmann }
56950788a3fSBastian Koppelmann 
helper_updfl(CPUTriCoreState * env,uint32_t arg)57050788a3fSBastian Koppelmann void helper_updfl(CPUTriCoreState *env, uint32_t arg)
57150788a3fSBastian Koppelmann {
57250788a3fSBastian Koppelmann     env->FPU_FS =  extract32(arg, 7, 1) & extract32(arg, 15, 1);
57350788a3fSBastian Koppelmann     env->FPU_FI = (extract32(arg, 6, 1) & extract32(arg, 14, 1)) << 31;
57450788a3fSBastian Koppelmann     env->FPU_FV = (extract32(arg, 5, 1) & extract32(arg, 13, 1)) << 31;
57550788a3fSBastian Koppelmann     env->FPU_FZ = (extract32(arg, 4, 1) & extract32(arg, 12, 1)) << 31;
57650788a3fSBastian Koppelmann     env->FPU_FU = (extract32(arg, 3, 1) & extract32(arg, 11, 1)) << 31;
57750788a3fSBastian Koppelmann     /* clear FX and RM */
57850788a3fSBastian Koppelmann     env->PSW &= ~(extract32(arg, 10, 1) << 26);
57950788a3fSBastian Koppelmann     env->PSW |= (extract32(arg, 2, 1) & extract32(arg, 10, 1)) << 26;
58050788a3fSBastian Koppelmann 
58150788a3fSBastian Koppelmann     fpu_set_state(env);
58250788a3fSBastian Koppelmann }
583