xref: /openbmc/qemu/target/sparc/fop_helper.c (revision db71391123dccccc2c8632a6f5ad451369a35391)
1 /*
2  * FPU op helpers
3  *
4  *  Copyright (c) 2003-2005 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
25 
26 static inline float128 f128_in(Int128 i)
27 {
28     union {
29         Int128 i;
30         float128 f;
31     } u;
32 
33     u.i = i;
34     return u.f;
35 }
36 
37 static inline Int128 f128_ret(float128 f)
38 {
39     union {
40         Int128 i;
41         float128 f;
42     } u;
43 
44     u.f = f;
45     return u.i;
46 }
47 
48 static void check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra)
49 {
50     target_ulong status = get_float_exception_flags(&env->fp_status);
51     target_ulong fsr = env->fsr;
52 
53     fsr &= FSR_FTT_CEXC_NMASK;
54 
55     if (unlikely(status)) {
56         /* Keep exception flags clear for next time.  */
57         set_float_exception_flags(0, &env->fp_status);
58 
59         /* Copy IEEE 754 flags into FSR */
60         if (status & float_flag_invalid) {
61             fsr |= FSR_NVC;
62         }
63         if (status & float_flag_overflow) {
64             fsr |= FSR_OFC;
65         }
66         if (status & float_flag_underflow) {
67             fsr |= FSR_UFC;
68         }
69         if (status & float_flag_divbyzero) {
70             fsr |= FSR_DZC;
71         }
72         if (status & float_flag_inexact) {
73             fsr |= FSR_NXC;
74         }
75 
76         if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) {
77             CPUState *cs = env_cpu(env);
78 
79             /* Unmasked exception, generate a trap.  Note that while
80                the helper is marked as NO_WG, we can get away with
81                writing to cpu state along the exception path, since
82                TCG generated code will never see the write.  */
83             env->fsr = fsr | FSR_FTT_IEEE_EXCP;
84             cs->exception_index = TT_FP_EXCP;
85             cpu_loop_exit_restore(cs, ra);
86         } else {
87             /* Accumulate exceptions */
88             fsr |= (fsr & FSR_CEXC_MASK) << 5;
89         }
90     }
91 
92     env->fsr = fsr;
93 }
94 
95 float32 helper_fadds(CPUSPARCState *env, float32 src1, float32 src2)
96 {
97     float32 ret = float32_add(src1, src2, &env->fp_status);
98     check_ieee_exceptions(env, GETPC());
99     return ret;
100 }
101 
102 float32 helper_fsubs(CPUSPARCState *env, float32 src1, float32 src2)
103 {
104     float32 ret = float32_sub(src1, src2, &env->fp_status);
105     check_ieee_exceptions(env, GETPC());
106     return ret;
107 }
108 
109 float32 helper_fmuls(CPUSPARCState *env, float32 src1, float32 src2)
110 {
111     float32 ret = float32_mul(src1, src2, &env->fp_status);
112     check_ieee_exceptions(env, GETPC());
113     return ret;
114 }
115 
116 float32 helper_fdivs(CPUSPARCState *env, float32 src1, float32 src2)
117 {
118     float32 ret = float32_div(src1, src2, &env->fp_status);
119     check_ieee_exceptions(env, GETPC());
120     return ret;
121 }
122 
123 float64 helper_faddd(CPUSPARCState *env, float64 src1, float64 src2)
124 {
125     float64 ret = float64_add(src1, src2, &env->fp_status);
126     check_ieee_exceptions(env, GETPC());
127     return ret;
128 }
129 
130 float64 helper_fsubd(CPUSPARCState *env, float64 src1, float64 src2)
131 {
132     float64 ret = float64_sub(src1, src2, &env->fp_status);
133     check_ieee_exceptions(env, GETPC());
134     return ret;
135 }
136 
137 float64 helper_fmuld(CPUSPARCState *env, float64 src1, float64 src2)
138 {
139     float64 ret = float64_mul(src1, src2, &env->fp_status);
140     check_ieee_exceptions(env, GETPC());
141     return ret;
142 }
143 
144 float64 helper_fdivd(CPUSPARCState *env, float64 src1, float64 src2)
145 {
146     float64 ret = float64_div(src1, src2, &env->fp_status);
147     check_ieee_exceptions(env, GETPC());
148     return ret;
149 }
150 
151 Int128 helper_faddq(CPUSPARCState *env, Int128 src1, Int128 src2)
152 {
153     float128 ret = float128_add(f128_in(src1), f128_in(src2), &env->fp_status);
154     check_ieee_exceptions(env, GETPC());
155     return f128_ret(ret);
156 }
157 
158 Int128 helper_fsubq(CPUSPARCState *env, Int128 src1, Int128 src2)
159 {
160     float128 ret = float128_sub(f128_in(src1), f128_in(src2), &env->fp_status);
161     check_ieee_exceptions(env, GETPC());
162     return f128_ret(ret);
163 }
164 
165 Int128 helper_fmulq(CPUSPARCState *env, Int128 src1, Int128 src2)
166 {
167     float128 ret = float128_mul(f128_in(src1), f128_in(src2), &env->fp_status);
168     check_ieee_exceptions(env, GETPC());
169     return f128_ret(ret);
170 }
171 
172 Int128 helper_fdivq(CPUSPARCState *env, Int128 src1, Int128 src2)
173 {
174     float128 ret = float128_div(f128_in(src1), f128_in(src2), &env->fp_status);
175     check_ieee_exceptions(env, GETPC());
176     return f128_ret(ret);
177 }
178 
179 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
180 {
181     float64 ret = float64_mul(float32_to_float64(src1, &env->fp_status),
182                               float32_to_float64(src2, &env->fp_status),
183                               &env->fp_status);
184     check_ieee_exceptions(env, GETPC());
185     return ret;
186 }
187 
188 Int128 helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2)
189 {
190     float128 ret = float128_mul(float64_to_float128(src1, &env->fp_status),
191                                 float64_to_float128(src2, &env->fp_status),
192                                 &env->fp_status);
193     check_ieee_exceptions(env, GETPC());
194     return f128_ret(ret);
195 }
196 
197 /* Integer to float conversion.  */
198 float32 helper_fitos(CPUSPARCState *env, int32_t src)
199 {
200     float32 ret = int32_to_float32(src, &env->fp_status);
201     check_ieee_exceptions(env, GETPC());
202     return ret;
203 }
204 
205 float64 helper_fitod(CPUSPARCState *env, int32_t src)
206 {
207     float64 ret = int32_to_float64(src, &env->fp_status);
208     check_ieee_exceptions(env, GETPC());
209     return ret;
210 }
211 
212 Int128 helper_fitoq(CPUSPARCState *env, int32_t src)
213 {
214     float128 ret = int32_to_float128(src, &env->fp_status);
215     check_ieee_exceptions(env, GETPC());
216     return f128_ret(ret);
217 }
218 
219 #ifdef TARGET_SPARC64
220 float32 helper_fxtos(CPUSPARCState *env, int64_t src)
221 {
222     float32 ret = int64_to_float32(src, &env->fp_status);
223     check_ieee_exceptions(env, GETPC());
224     return ret;
225 }
226 
227 float64 helper_fxtod(CPUSPARCState *env, int64_t src)
228 {
229     float64 ret = int64_to_float64(src, &env->fp_status);
230     check_ieee_exceptions(env, GETPC());
231     return ret;
232 }
233 
234 Int128 helper_fxtoq(CPUSPARCState *env, int64_t src)
235 {
236     float128 ret = int64_to_float128(src, &env->fp_status);
237     check_ieee_exceptions(env, GETPC());
238     return f128_ret(ret);
239 }
240 #endif
241 
242 /* floating point conversion */
243 float32 helper_fdtos(CPUSPARCState *env, float64 src)
244 {
245     float32 ret = float64_to_float32(src, &env->fp_status);
246     check_ieee_exceptions(env, GETPC());
247     return ret;
248 }
249 
250 float64 helper_fstod(CPUSPARCState *env, float32 src)
251 {
252     float64 ret = float32_to_float64(src, &env->fp_status);
253     check_ieee_exceptions(env, GETPC());
254     return ret;
255 }
256 
257 float32 helper_fqtos(CPUSPARCState *env, Int128 src)
258 {
259     float32 ret = float128_to_float32(f128_in(src), &env->fp_status);
260     check_ieee_exceptions(env, GETPC());
261     return ret;
262 }
263 
264 Int128 helper_fstoq(CPUSPARCState *env, float32 src)
265 {
266     float128 ret = float32_to_float128(src, &env->fp_status);
267     check_ieee_exceptions(env, GETPC());
268     return f128_ret(ret);
269 }
270 
271 float64 helper_fqtod(CPUSPARCState *env, Int128 src)
272 {
273     float64 ret = float128_to_float64(f128_in(src), &env->fp_status);
274     check_ieee_exceptions(env, GETPC());
275     return ret;
276 }
277 
278 Int128 helper_fdtoq(CPUSPARCState *env, float64 src)
279 {
280     float128 ret = float64_to_float128(src, &env->fp_status);
281     check_ieee_exceptions(env, GETPC());
282     return f128_ret(ret);
283 }
284 
285 /* Float to integer conversion.  */
286 int32_t helper_fstoi(CPUSPARCState *env, float32 src)
287 {
288     int32_t ret = float32_to_int32_round_to_zero(src, &env->fp_status);
289     check_ieee_exceptions(env, GETPC());
290     return ret;
291 }
292 
293 int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
294 {
295     int32_t ret = float64_to_int32_round_to_zero(src, &env->fp_status);
296     check_ieee_exceptions(env, GETPC());
297     return ret;
298 }
299 
300 int32_t helper_fqtoi(CPUSPARCState *env, Int128 src)
301 {
302     int32_t ret = float128_to_int32_round_to_zero(f128_in(src),
303                                                   &env->fp_status);
304     check_ieee_exceptions(env, GETPC());
305     return ret;
306 }
307 
308 #ifdef TARGET_SPARC64
309 int64_t helper_fstox(CPUSPARCState *env, float32 src)
310 {
311     int64_t ret = float32_to_int64_round_to_zero(src, &env->fp_status);
312     check_ieee_exceptions(env, GETPC());
313     return ret;
314 }
315 
316 int64_t helper_fdtox(CPUSPARCState *env, float64 src)
317 {
318     int64_t ret = float64_to_int64_round_to_zero(src, &env->fp_status);
319     check_ieee_exceptions(env, GETPC());
320     return ret;
321 }
322 
323 int64_t helper_fqtox(CPUSPARCState *env, Int128 src)
324 {
325     int64_t ret = float128_to_int64_round_to_zero(f128_in(src),
326                                                   &env->fp_status);
327     check_ieee_exceptions(env, GETPC());
328     return ret;
329 }
330 #endif
331 
332 float32 helper_fsqrts(CPUSPARCState *env, float32 src)
333 {
334     float32 ret = float32_sqrt(src, &env->fp_status);
335     check_ieee_exceptions(env, GETPC());
336     return ret;
337 }
338 
339 float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
340 {
341     float64 ret = float64_sqrt(src, &env->fp_status);
342     check_ieee_exceptions(env, GETPC());
343     return ret;
344 }
345 
346 Int128 helper_fsqrtq(CPUSPARCState *env, Int128 src)
347 {
348     float128 ret = float128_sqrt(f128_in(src), &env->fp_status);
349     check_ieee_exceptions(env, GETPC());
350     return f128_ret(ret);
351 }
352 
353 #define GEN_FCMP(name, size, FS, E)                                     \
354     target_ulong glue(helper_, name) (CPUSPARCState *env,               \
355                                       Int128 src1, Int128 src2)         \
356     {                                                                   \
357         float128 reg1 = f128_in(src1);                                  \
358         float128 reg2 = f128_in(src2);                                  \
359         FloatRelation ret;                                              \
360         target_ulong fsr;                                               \
361         if (E) {                                                        \
362             ret = glue(size, _compare)(reg1, reg2, &env->fp_status);    \
363         } else {                                                        \
364             ret = glue(size, _compare_quiet)(reg1, reg2,                \
365                                              &env->fp_status);          \
366         }                                                               \
367         check_ieee_exceptions(env, GETPC());                            \
368         fsr = env->fsr;                                                 \
369         switch (ret) {                                                  \
370         case float_relation_unordered:                                  \
371             fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
372             fsr |= FSR_NVA;                                             \
373             break;                                                      \
374         case float_relation_less:                                       \
375             fsr &= ~(FSR_FCC1) << FS;                                   \
376             fsr |= FSR_FCC0 << FS;                                      \
377             break;                                                      \
378         case float_relation_greater:                                    \
379             fsr &= ~(FSR_FCC0) << FS;                                   \
380             fsr |= FSR_FCC1 << FS;                                      \
381             break;                                                      \
382         default:                                                        \
383             fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                      \
384             break;                                                      \
385         }                                                               \
386         return fsr;                                                     \
387     }
388 #define GEN_FCMP_T(name, size, FS, E)                                   \
389     target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\
390     {                                                                   \
391         FloatRelation ret;                                              \
392         target_ulong fsr;                                               \
393         if (E) {                                                        \
394             ret = glue(size, _compare)(src1, src2, &env->fp_status);    \
395         } else {                                                        \
396             ret = glue(size, _compare_quiet)(src1, src2,                \
397                                              &env->fp_status);          \
398         }                                                               \
399         check_ieee_exceptions(env, GETPC());                            \
400         fsr = env->fsr;                                                 \
401         switch (ret) {                                                  \
402         case float_relation_unordered:                                  \
403             fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                         \
404             break;                                                      \
405         case float_relation_less:                                       \
406             fsr &= ~(FSR_FCC1 << FS);                                   \
407             fsr |= FSR_FCC0 << FS;                                      \
408             break;                                                      \
409         case float_relation_greater:                                    \
410             fsr &= ~(FSR_FCC0 << FS);                                   \
411             fsr |= FSR_FCC1 << FS;                                      \
412             break;                                                      \
413         default:                                                        \
414             fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                      \
415             break;                                                      \
416         }                                                               \
417         return fsr;                                                     \
418     }
419 
420 GEN_FCMP_T(fcmps, float32, 0, 0);
421 GEN_FCMP_T(fcmpd, float64, 0, 0);
422 
423 GEN_FCMP_T(fcmpes, float32, 0, 1);
424 GEN_FCMP_T(fcmped, float64, 0, 1);
425 
426 GEN_FCMP(fcmpq, float128, 0, 0);
427 GEN_FCMP(fcmpeq, float128, 0, 1);
428 
429 #ifdef TARGET_SPARC64
430 GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
431 GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
432 GEN_FCMP(fcmpq_fcc1, float128, 22, 0);
433 
434 GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
435 GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
436 GEN_FCMP(fcmpq_fcc2, float128, 24, 0);
437 
438 GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
439 GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
440 GEN_FCMP(fcmpq_fcc3, float128, 26, 0);
441 
442 GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
443 GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
444 GEN_FCMP(fcmpeq_fcc1, float128, 22, 1);
445 
446 GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
447 GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
448 GEN_FCMP(fcmpeq_fcc2, float128, 24, 1);
449 
450 GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
451 GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
452 GEN_FCMP(fcmpeq_fcc3, float128, 26, 1);
453 #endif
454 #undef GEN_FCMP_T
455 #undef GEN_FCMP
456 
457 target_ulong cpu_get_fsr(CPUSPARCState *env)
458 {
459     target_ulong fsr = env->fsr;
460 
461     /* VER is kept completely separate until re-assembly. */
462     fsr |= env->def.fpu_version;
463 
464     return fsr;
465 }
466 
467 target_ulong helper_get_fsr(CPUSPARCState *env)
468 {
469     return cpu_get_fsr(env);
470 }
471 
472 static void set_fsr_nonsplit(CPUSPARCState *env, target_ulong fsr)
473 {
474     int rnd_mode;
475 
476     env->fsr = fsr & ~FSR_VER_MASK;
477 
478     switch (fsr & FSR_RD_MASK) {
479     case FSR_RD_NEAREST:
480         rnd_mode = float_round_nearest_even;
481         break;
482     default:
483     case FSR_RD_ZERO:
484         rnd_mode = float_round_to_zero;
485         break;
486     case FSR_RD_POS:
487         rnd_mode = float_round_up;
488         break;
489     case FSR_RD_NEG:
490         rnd_mode = float_round_down;
491         break;
492     }
493     set_float_rounding_mode(rnd_mode, &env->fp_status);
494 }
495 
496 void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr)
497 {
498     set_fsr_nonsplit(env, fsr);
499 }
500 
501 void helper_set_fsr(CPUSPARCState *env, target_ulong fsr)
502 {
503     set_fsr_nonsplit(env, fsr);
504 }
505