4 * Copyright (c) 2003-2005 Fabrice Bellard
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.
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.
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/>.
20 #include "qemu/osdep.h"
22 #include "exec/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
26 static inline float128
f128_in(Int128 i
)
37 static inline Int128
f128_ret(float128 f
)
48 static void check_ieee_exceptions(CPUSPARCState
*env
, uintptr_t ra
)
50 target_ulong status
= get_float_exception_flags(&env
->fp_status
);
53 if (unlikely(status
)) {
54 /* Keep exception flags clear for next time. */
55 set_float_exception_flags(0, &env
->fp_status
);
57 /* Copy IEEE 754 flags into FSR */
58 if (status
& float_flag_invalid
) {
61 if (status
& float_flag_overflow
) {
64 if (status
& float_flag_underflow
) {
67 if (status
& float_flag_divbyzero
) {
70 if (status
& float_flag_inexact
) {
74 if (cexc
& (env
->fsr
>> FSR_TEM_SHIFT
)) {
75 /* Unmasked exception, generate an IEEE trap. */
76 env
->fsr_cexc_ftt
= cexc
| FSR_FTT_IEEE_EXCP
;
77 cpu_raise_exception_ra(env
, TT_FP_EXCP
, ra
);
80 /* Accumulate exceptions */
81 env
->fsr
|= cexc
<< FSR_AEXC_SHIFT
;
84 /* No trap, so FTT is cleared. */
85 env
->fsr_cexc_ftt
= cexc
;
88 float32
helper_fadds(CPUSPARCState
*env
, float32 src1
, float32 src2
)
90 float32 ret
= float32_add(src1
, src2
, &env
->fp_status
);
91 check_ieee_exceptions(env
, GETPC());
95 float32
helper_fsubs(CPUSPARCState
*env
, float32 src1
, float32 src2
)
97 float32 ret
= float32_sub(src1
, src2
, &env
->fp_status
);
98 check_ieee_exceptions(env
, GETPC());
102 float32
helper_fmuls(CPUSPARCState
*env
, float32 src1
, float32 src2
)
104 float32 ret
= float32_mul(src1
, src2
, &env
->fp_status
);
105 check_ieee_exceptions(env
, GETPC());
109 float32
helper_fdivs(CPUSPARCState
*env
, float32 src1
, float32 src2
)
111 float32 ret
= float32_div(src1
, src2
, &env
->fp_status
);
112 check_ieee_exceptions(env
, GETPC());
116 float64
helper_faddd(CPUSPARCState
*env
, float64 src1
, float64 src2
)
118 float64 ret
= float64_add(src1
, src2
, &env
->fp_status
);
119 check_ieee_exceptions(env
, GETPC());
123 float64
helper_fsubd(CPUSPARCState
*env
, float64 src1
, float64 src2
)
125 float64 ret
= float64_sub(src1
, src2
, &env
->fp_status
);
126 check_ieee_exceptions(env
, GETPC());
130 float64
helper_fmuld(CPUSPARCState
*env
, float64 src1
, float64 src2
)
132 float64 ret
= float64_mul(src1
, src2
, &env
->fp_status
);
133 check_ieee_exceptions(env
, GETPC());
137 float64
helper_fdivd(CPUSPARCState
*env
, float64 src1
, float64 src2
)
139 float64 ret
= float64_div(src1
, src2
, &env
->fp_status
);
140 check_ieee_exceptions(env
, GETPC());
144 Int128
helper_faddq(CPUSPARCState
*env
, Int128 src1
, Int128 src2
)
146 float128 ret
= float128_add(f128_in(src1
), f128_in(src2
), &env
->fp_status
);
147 check_ieee_exceptions(env
, GETPC());
148 return f128_ret(ret
);
151 Int128
helper_fsubq(CPUSPARCState
*env
, Int128 src1
, Int128 src2
)
153 float128 ret
= float128_sub(f128_in(src1
), f128_in(src2
), &env
->fp_status
);
154 check_ieee_exceptions(env
, GETPC());
155 return f128_ret(ret
);
158 Int128
helper_fmulq(CPUSPARCState
*env
, Int128 src1
, Int128 src2
)
160 float128 ret
= float128_mul(f128_in(src1
), f128_in(src2
), &env
->fp_status
);
161 check_ieee_exceptions(env
, GETPC());
162 return f128_ret(ret
);
165 Int128
helper_fdivq(CPUSPARCState
*env
, Int128 src1
, Int128 src2
)
167 float128 ret
= float128_div(f128_in(src1
), f128_in(src2
), &env
->fp_status
);
168 check_ieee_exceptions(env
, GETPC());
169 return f128_ret(ret
);
172 float64
helper_fsmuld(CPUSPARCState
*env
, float32 src1
, float32 src2
)
174 float64 ret
= float64_mul(float32_to_float64(src1
, &env
->fp_status
),
175 float32_to_float64(src2
, &env
->fp_status
),
177 check_ieee_exceptions(env
, GETPC());
181 Int128
helper_fdmulq(CPUSPARCState
*env
, float64 src1
, float64 src2
)
183 float128 ret
= float128_mul(float64_to_float128(src1
, &env
->fp_status
),
184 float64_to_float128(src2
, &env
->fp_status
),
186 check_ieee_exceptions(env
, GETPC());
187 return f128_ret(ret
);
190 /* Integer to float conversion. */
191 float32
helper_fitos(CPUSPARCState
*env
, int32_t src
)
193 float32 ret
= int32_to_float32(src
, &env
->fp_status
);
194 check_ieee_exceptions(env
, GETPC());
198 float64
helper_fitod(CPUSPARCState
*env
, int32_t src
)
200 float64 ret
= int32_to_float64(src
, &env
->fp_status
);
201 check_ieee_exceptions(env
, GETPC());
205 Int128
helper_fitoq(CPUSPARCState
*env
, int32_t src
)
207 float128 ret
= int32_to_float128(src
, &env
->fp_status
);
208 check_ieee_exceptions(env
, GETPC());
209 return f128_ret(ret
);
212 #ifdef TARGET_SPARC64
213 float32
helper_fxtos(CPUSPARCState
*env
, int64_t src
)
215 float32 ret
= int64_to_float32(src
, &env
->fp_status
);
216 check_ieee_exceptions(env
, GETPC());
220 float64
helper_fxtod(CPUSPARCState
*env
, int64_t src
)
222 float64 ret
= int64_to_float64(src
, &env
->fp_status
);
223 check_ieee_exceptions(env
, GETPC());
227 Int128
helper_fxtoq(CPUSPARCState
*env
, int64_t src
)
229 float128 ret
= int64_to_float128(src
, &env
->fp_status
);
230 check_ieee_exceptions(env
, GETPC());
231 return f128_ret(ret
);
235 /* floating point conversion */
236 float32
helper_fdtos(CPUSPARCState
*env
, float64 src
)
238 float32 ret
= float64_to_float32(src
, &env
->fp_status
);
239 check_ieee_exceptions(env
, GETPC());
243 float64
helper_fstod(CPUSPARCState
*env
, float32 src
)
245 float64 ret
= float32_to_float64(src
, &env
->fp_status
);
246 check_ieee_exceptions(env
, GETPC());
250 float32
helper_fqtos(CPUSPARCState
*env
, Int128 src
)
252 float32 ret
= float128_to_float32(f128_in(src
), &env
->fp_status
);
253 check_ieee_exceptions(env
, GETPC());
257 Int128
helper_fstoq(CPUSPARCState
*env
, float32 src
)
259 float128 ret
= float32_to_float128(src
, &env
->fp_status
);
260 check_ieee_exceptions(env
, GETPC());
261 return f128_ret(ret
);
264 float64
helper_fqtod(CPUSPARCState
*env
, Int128 src
)
266 float64 ret
= float128_to_float64(f128_in(src
), &env
->fp_status
);
267 check_ieee_exceptions(env
, GETPC());
271 Int128
helper_fdtoq(CPUSPARCState
*env
, float64 src
)
273 float128 ret
= float64_to_float128(src
, &env
->fp_status
);
274 check_ieee_exceptions(env
, GETPC());
275 return f128_ret(ret
);
278 /* Float to integer conversion. */
279 int32_t helper_fstoi(CPUSPARCState
*env
, float32 src
)
281 int32_t ret
= float32_to_int32_round_to_zero(src
, &env
->fp_status
);
282 check_ieee_exceptions(env
, GETPC());
286 int32_t helper_fdtoi(CPUSPARCState
*env
, float64 src
)
288 int32_t ret
= float64_to_int32_round_to_zero(src
, &env
->fp_status
);
289 check_ieee_exceptions(env
, GETPC());
293 int32_t helper_fqtoi(CPUSPARCState
*env
, Int128 src
)
295 int32_t ret
= float128_to_int32_round_to_zero(f128_in(src
),
297 check_ieee_exceptions(env
, GETPC());
301 #ifdef TARGET_SPARC64
302 int64_t helper_fstox(CPUSPARCState
*env
, float32 src
)
304 int64_t ret
= float32_to_int64_round_to_zero(src
, &env
->fp_status
);
305 check_ieee_exceptions(env
, GETPC());
309 int64_t helper_fdtox(CPUSPARCState
*env
, float64 src
)
311 int64_t ret
= float64_to_int64_round_to_zero(src
, &env
->fp_status
);
312 check_ieee_exceptions(env
, GETPC());
316 int64_t helper_fqtox(CPUSPARCState
*env
, Int128 src
)
318 int64_t ret
= float128_to_int64_round_to_zero(f128_in(src
),
320 check_ieee_exceptions(env
, GETPC());
325 float32
helper_fsqrts(CPUSPARCState
*env
, float32 src
)
327 float32 ret
= float32_sqrt(src
, &env
->fp_status
);
328 check_ieee_exceptions(env
, GETPC());
332 float64
helper_fsqrtd(CPUSPARCState
*env
, float64 src
)
334 float64 ret
= float64_sqrt(src
, &env
->fp_status
);
335 check_ieee_exceptions(env
, GETPC());
339 Int128
helper_fsqrtq(CPUSPARCState
*env
, Int128 src
)
341 float128 ret
= float128_sqrt(f128_in(src
), &env
->fp_status
);
342 check_ieee_exceptions(env
, GETPC());
343 return f128_ret(ret
);
346 float32
helper_fmadds(CPUSPARCState
*env
, float32 s1
,
347 float32 s2
, float32 s3
, uint32_t op
)
349 float32 ret
= float32_muladd(s1
, s2
, s3
, op
, &env
->fp_status
);
350 check_ieee_exceptions(env
, GETPC());
354 float64
helper_fmaddd(CPUSPARCState
*env
, float64 s1
,
355 float64 s2
, float64 s3
, uint32_t op
)
357 float64 ret
= float64_muladd(s1
, s2
, s3
, op
, &env
->fp_status
);
358 check_ieee_exceptions(env
, GETPC());
362 float32
helper_fnadds(CPUSPARCState
*env
, float32 src1
, float32 src2
)
364 float32 ret
= float32_add(src1
, src2
, &env
->fp_status
);
367 * NaN inputs or result do not get a sign change.
368 * Nor, apparently, does zero: on hardware, -(x + -x) yields +0.
370 if (!float32_is_any_nan(ret
) && !float32_is_zero(ret
)) {
371 ret
= float32_chs(ret
);
373 check_ieee_exceptions(env
, GETPC());
377 float32
helper_fnmuls(CPUSPARCState
*env
, float32 src1
, float32 src2
)
379 float32 ret
= float32_mul(src1
, src2
, &env
->fp_status
);
381 /* NaN inputs or result do not get a sign change. */
382 if (!float32_is_any_nan(ret
)) {
383 ret
= float32_chs(ret
);
385 check_ieee_exceptions(env
, GETPC());
389 float64
helper_fnaddd(CPUSPARCState
*env
, float64 src1
, float64 src2
)
391 float64 ret
= float64_add(src1
, src2
, &env
->fp_status
);
394 * NaN inputs or result do not get a sign change.
395 * Nor, apparently, does zero: on hardware, -(x + -x) yields +0.
397 if (!float64_is_any_nan(ret
) && !float64_is_zero(ret
)) {
398 ret
= float64_chs(ret
);
400 check_ieee_exceptions(env
, GETPC());
404 float64
helper_fnmuld(CPUSPARCState
*env
, float64 src1
, float64 src2
)
406 float64 ret
= float64_mul(src1
, src2
, &env
->fp_status
);
408 /* NaN inputs or result do not get a sign change. */
409 if (!float64_is_any_nan(ret
)) {
410 ret
= float64_chs(ret
);
412 check_ieee_exceptions(env
, GETPC());
416 float64
helper_fnsmuld(CPUSPARCState
*env
, float32 src1
, float32 src2
)
418 float64 ret
= float64_mul(float32_to_float64(src1
, &env
->fp_status
),
419 float32_to_float64(src2
, &env
->fp_status
),
422 /* NaN inputs or result do not get a sign change. */
423 if (!float64_is_any_nan(ret
)) {
424 ret
= float64_chs(ret
);
426 check_ieee_exceptions(env
, GETPC());
430 static uint32_t finish_fcmp(CPUSPARCState
*env
, FloatRelation r
, uintptr_t ra
)
432 check_ieee_exceptions(env
, ra
);
442 case float_relation_equal
:
444 case float_relation_less
:
446 case float_relation_greater
:
448 case float_relation_unordered
:
452 g_assert_not_reached();
455 uint32_t helper_fcmps(CPUSPARCState
*env
, float32 src1
, float32 src2
)
457 FloatRelation r
= float32_compare_quiet(src1
, src2
, &env
->fp_status
);
458 return finish_fcmp(env
, r
, GETPC());
461 uint32_t helper_fcmpes(CPUSPARCState
*env
, float32 src1
, float32 src2
)
463 FloatRelation r
= float32_compare(src1
, src2
, &env
->fp_status
);
464 return finish_fcmp(env
, r
, GETPC());
467 uint32_t helper_fcmpd(CPUSPARCState
*env
, float64 src1
, float64 src2
)
469 FloatRelation r
= float64_compare_quiet(src1
, src2
, &env
->fp_status
);
470 return finish_fcmp(env
, r
, GETPC());
473 uint32_t helper_fcmped(CPUSPARCState
*env
, float64 src1
, float64 src2
)
475 FloatRelation r
= float64_compare(src1
, src2
, &env
->fp_status
);
476 return finish_fcmp(env
, r
, GETPC());
479 uint32_t helper_fcmpq(CPUSPARCState
*env
, Int128 src1
, Int128 src2
)
481 FloatRelation r
= float128_compare_quiet(f128_in(src1
), f128_in(src2
),
483 return finish_fcmp(env
, r
, GETPC());
486 uint32_t helper_fcmpeq(CPUSPARCState
*env
, Int128 src1
, Int128 src2
)
488 FloatRelation r
= float128_compare(f128_in(src1
), f128_in(src2
),
490 return finish_fcmp(env
, r
, GETPC());
493 uint32_t helper_flcmps(float32 src1
, float32 src2
)
496 * FLCMP never raises an exception nor modifies any FSR fields.
497 * Perform the comparison with a dummy fp environment.
499 float_status discard
= { };
500 FloatRelation r
= float32_compare_quiet(src1
, src2
, &discard
);
503 case float_relation_equal
:
504 if (src2
== float32_zero
&& src1
!= float32_zero
) {
505 return 1; /* -0.0 < +0.0 */
508 case float_relation_less
:
510 case float_relation_greater
:
512 case float_relation_unordered
:
513 return float32_is_any_nan(src2
) ? 3 : 2;
515 g_assert_not_reached();
518 uint32_t helper_flcmpd(float64 src1
, float64 src2
)
520 float_status discard
= { };
521 FloatRelation r
= float64_compare_quiet(src1
, src2
, &discard
);
524 case float_relation_equal
:
525 if (src2
== float64_zero
&& src1
!= float64_zero
) {
526 return 1; /* -0.0 < +0.0 */
529 case float_relation_less
:
531 case float_relation_greater
:
533 case float_relation_unordered
:
534 return float64_is_any_nan(src2
) ? 3 : 2;
536 g_assert_not_reached();
539 target_ulong
cpu_get_fsr(CPUSPARCState
*env
)
541 target_ulong fsr
= env
->fsr
| env
->fsr_cexc_ftt
;
543 fsr
|= env
->fcc
[0] << FSR_FCC0_SHIFT
;
544 #ifdef TARGET_SPARC64
545 fsr
|= (uint64_t)env
->fcc
[1] << FSR_FCC1_SHIFT
;
546 fsr
|= (uint64_t)env
->fcc
[2] << FSR_FCC2_SHIFT
;
547 fsr
|= (uint64_t)env
->fcc
[3] << FSR_FCC3_SHIFT
;
550 /* VER is kept completely separate until re-assembly. */
551 fsr
|= env
->def
.fpu_version
;
556 target_ulong
helper_get_fsr(CPUSPARCState
*env
)
558 return cpu_get_fsr(env
);
561 static void set_fsr_nonsplit(CPUSPARCState
*env
, target_ulong fsr
)
565 env
->fsr
= fsr
& (FSR_RD_MASK
| FSR_TEM_MASK
| FSR_AEXC_MASK
);
567 switch (fsr
& FSR_RD_MASK
) {
569 rnd_mode
= float_round_nearest_even
;
573 rnd_mode
= float_round_to_zero
;
576 rnd_mode
= float_round_up
;
579 rnd_mode
= float_round_down
;
582 set_float_rounding_mode(rnd_mode
, &env
->fp_status
);
585 void cpu_put_fsr(CPUSPARCState
*env
, target_ulong fsr
)
587 env
->fsr_cexc_ftt
= fsr
& (FSR_CEXC_MASK
| FSR_FTT_MASK
);
589 env
->fcc
[0] = extract32(fsr
, FSR_FCC0_SHIFT
, 2);
590 #ifdef TARGET_SPARC64
591 env
->fcc
[1] = extract64(fsr
, FSR_FCC1_SHIFT
, 2);
592 env
->fcc
[2] = extract64(fsr
, FSR_FCC2_SHIFT
, 2);
593 env
->fcc
[3] = extract64(fsr
, FSR_FCC3_SHIFT
, 2);
596 set_fsr_nonsplit(env
, fsr
);
599 void helper_set_fsr_nofcc_noftt(CPUSPARCState
*env
, uint32_t fsr
)
601 env
->fsr_cexc_ftt
&= FSR_FTT_MASK
;
602 env
->fsr_cexc_ftt
|= fsr
& FSR_CEXC_MASK
;
603 set_fsr_nonsplit(env
, fsr
);
606 void helper_set_fsr_nofcc(CPUSPARCState
*env
, uint32_t fsr
)
608 env
->fsr_cexc_ftt
= fsr
& (FSR_CEXC_MASK
| FSR_FTT_MASK
);
609 set_fsr_nonsplit(env
, fsr
);