2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the Open Source and Linux Lab nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "qemu/osdep.h"
30 #include "qemu/main-loop.h"
32 #include "exec/helper-proto.h"
33 #include "qemu/host-utils.h"
34 #include "exec/exec-all.h"
35 #include "fpu/softfloat.h"
46 XTENSA_FCR_FLAGS_SHIFT
= 2,
47 XTENSA_FSR_FLAGS_SHIFT
= 7,
51 uint32_t xtensa_fp_flag
;
52 int softfloat_fp_flag
;
53 } xtensa_fp_flag_map
[] = {
54 { XTENSA_FP_I
, float_flag_inexact
, },
55 { XTENSA_FP_U
, float_flag_underflow
, },
56 { XTENSA_FP_O
, float_flag_overflow
, },
57 { XTENSA_FP_Z
, float_flag_divbyzero
, },
58 { XTENSA_FP_V
, float_flag_invalid
, },
61 void HELPER(wur_fpu2k_fcr
)(CPUXtensaState
*env
, uint32_t v
)
63 static const int rounding_mode
[] = {
64 float_round_nearest_even
,
70 env
->uregs
[FCR
] = v
& 0xfffff07f;
71 set_float_rounding_mode(rounding_mode
[v
& 3], &env
->fp_status
);
74 void HELPER(wur_fpu_fcr
)(CPUXtensaState
*env
, uint32_t v
)
76 static const int rounding_mode
[] = {
77 float_round_nearest_even
,
84 qemu_log_mask(LOG_GUEST_ERROR
,
85 "MBZ field of FCR is written non-zero: %08x\n", v
);
87 env
->uregs
[FCR
] = v
& 0x0000007f;
88 set_float_rounding_mode(rounding_mode
[v
& 3], &env
->fp_status
);
91 void HELPER(wur_fpu_fsr
)(CPUXtensaState
*env
, uint32_t v
)
93 uint32_t flags
= v
>> XTENSA_FSR_FLAGS_SHIFT
;
98 qemu_log_mask(LOG_GUEST_ERROR
,
99 "MBZ field of FSR is written non-zero: %08x\n", v
);
101 env
->uregs
[FSR
] = v
& 0x00000f80;
102 for (i
= 0; i
< ARRAY_SIZE(xtensa_fp_flag_map
); ++i
) {
103 if (flags
& xtensa_fp_flag_map
[i
].xtensa_fp_flag
) {
104 fef
|= xtensa_fp_flag_map
[i
].softfloat_fp_flag
;
107 set_float_exception_flags(fef
, &env
->fp_status
);
110 uint32_t HELPER(rur_fpu_fsr
)(CPUXtensaState
*env
)
113 int fef
= get_float_exception_flags(&env
->fp_status
);
116 for (i
= 0; i
< ARRAY_SIZE(xtensa_fp_flag_map
); ++i
) {
117 if (fef
& xtensa_fp_flag_map
[i
].softfloat_fp_flag
) {
118 flags
|= xtensa_fp_flag_map
[i
].xtensa_fp_flag
;
121 env
->uregs
[FSR
] = flags
<< XTENSA_FSR_FLAGS_SHIFT
;
122 return flags
<< XTENSA_FSR_FLAGS_SHIFT
;
125 float64
HELPER(abs_d
)(float64 v
)
127 return float64_abs(v
);
130 float32
HELPER(abs_s
)(float32 v
)
132 return float32_abs(v
);
135 float64
HELPER(neg_d
)(float64 v
)
137 return float64_chs(v
);
140 float32
HELPER(neg_s
)(float32 v
)
142 return float32_chs(v
);
145 float32
HELPER(fpu2k_add_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
147 return float32_add(a
, b
, &env
->fp_status
);
150 float32
HELPER(fpu2k_sub_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
152 return float32_sub(a
, b
, &env
->fp_status
);
155 float32
HELPER(fpu2k_mul_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
157 return float32_mul(a
, b
, &env
->fp_status
);
160 float32
HELPER(fpu2k_madd_s
)(CPUXtensaState
*env
,
161 float32 a
, float32 b
, float32 c
)
163 return float32_muladd(b
, c
, a
, 0, &env
->fp_status
);
166 float32
HELPER(fpu2k_msub_s
)(CPUXtensaState
*env
,
167 float32 a
, float32 b
, float32 c
)
169 return float32_muladd(b
, c
, a
, float_muladd_negate_product
,
173 float64
HELPER(add_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
175 set_use_first_nan(true, &env
->fp_status
);
176 return float64_add(a
, b
, &env
->fp_status
);
179 float32
HELPER(add_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
181 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
182 return float32_add(a
, b
, &env
->fp_status
);
185 float64
HELPER(sub_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
187 set_use_first_nan(true, &env
->fp_status
);
188 return float64_sub(a
, b
, &env
->fp_status
);
191 float32
HELPER(sub_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
193 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
194 return float32_sub(a
, b
, &env
->fp_status
);
197 float64
HELPER(mul_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
199 set_use_first_nan(true, &env
->fp_status
);
200 return float64_mul(a
, b
, &env
->fp_status
);
203 float32
HELPER(mul_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
205 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
206 return float32_mul(a
, b
, &env
->fp_status
);
209 float64
HELPER(madd_d
)(CPUXtensaState
*env
, float64 a
, float64 b
, float64 c
)
211 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
212 return float64_muladd(b
, c
, a
, 0, &env
->fp_status
);
215 float32
HELPER(madd_s
)(CPUXtensaState
*env
, float32 a
, float32 b
, float32 c
)
217 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
218 return float32_muladd(b
, c
, a
, 0, &env
->fp_status
);
221 float64
HELPER(msub_d
)(CPUXtensaState
*env
, float64 a
, float64 b
, float64 c
)
223 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
224 return float64_muladd(b
, c
, a
, float_muladd_negate_product
,
228 float32
HELPER(msub_s
)(CPUXtensaState
*env
, float32 a
, float32 b
, float32 c
)
230 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
231 return float32_muladd(b
, c
, a
, float_muladd_negate_product
,
235 float64
HELPER(mkdadj_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
237 set_use_first_nan(true, &env
->fp_status
);
238 return float64_div(b
, a
, &env
->fp_status
);
241 float32
HELPER(mkdadj_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
243 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
244 return float32_div(b
, a
, &env
->fp_status
);
247 float64
HELPER(mksadj_d
)(CPUXtensaState
*env
, float64 v
)
249 set_use_first_nan(true, &env
->fp_status
);
250 return float64_sqrt(v
, &env
->fp_status
);
253 float32
HELPER(mksadj_s
)(CPUXtensaState
*env
, float32 v
)
255 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
256 return float32_sqrt(v
, &env
->fp_status
);
259 uint32_t HELPER(ftoi_d
)(CPUXtensaState
*env
, float64 v
,
260 uint32_t rounding_mode
, uint32_t scale
)
262 float_status fp_status
= env
->fp_status
;
265 set_float_rounding_mode(rounding_mode
, &fp_status
);
266 res
= float64_to_int32(float64_scalbn(v
, scale
, &fp_status
), &fp_status
);
267 set_float_exception_flags(get_float_exception_flags(&fp_status
),
272 uint32_t HELPER(ftoi_s
)(CPUXtensaState
*env
, float32 v
,
273 uint32_t rounding_mode
, uint32_t scale
)
275 float_status fp_status
= env
->fp_status
;
278 set_float_rounding_mode(rounding_mode
, &fp_status
);
279 res
= float32_to_int32(float32_scalbn(v
, scale
, &fp_status
), &fp_status
);
280 set_float_exception_flags(get_float_exception_flags(&fp_status
),
285 uint32_t HELPER(ftoui_d
)(CPUXtensaState
*env
, float64 v
,
286 uint32_t rounding_mode
, uint32_t scale
)
288 float_status fp_status
= env
->fp_status
;
292 set_float_rounding_mode(rounding_mode
, &fp_status
);
294 res
= float64_scalbn(v
, scale
, &fp_status
);
296 if (float64_is_neg(v
) && !float64_is_any_nan(v
)) {
297 set_float_exception_flags(float_flag_invalid
, &fp_status
);
298 rv
= float64_to_int32(res
, &fp_status
);
300 rv
= float64_to_uint32(res
, &fp_status
);
302 set_float_exception_flags(get_float_exception_flags(&fp_status
),
307 uint32_t HELPER(ftoui_s
)(CPUXtensaState
*env
, float32 v
,
308 uint32_t rounding_mode
, uint32_t scale
)
310 float_status fp_status
= env
->fp_status
;
314 set_float_rounding_mode(rounding_mode
, &fp_status
);
316 res
= float32_scalbn(v
, scale
, &fp_status
);
318 if (float32_is_neg(v
) && !float32_is_any_nan(v
)) {
319 rv
= float32_to_int32(res
, &fp_status
);
321 set_float_exception_flags(float_flag_invalid
, &fp_status
);
324 rv
= float32_to_uint32(res
, &fp_status
);
326 set_float_exception_flags(get_float_exception_flags(&fp_status
),
331 float64
HELPER(itof_d
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
333 return float64_scalbn(int32_to_float64(v
, &env
->fp_status
),
334 (int32_t)scale
, &env
->fp_status
);
337 float32
HELPER(itof_s
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
339 return float32_scalbn(int32_to_float32(v
, &env
->fp_status
),
340 (int32_t)scale
, &env
->fp_status
);
343 float64
HELPER(uitof_d
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
345 return float64_scalbn(uint32_to_float64(v
, &env
->fp_status
),
346 (int32_t)scale
, &env
->fp_status
);
349 float32
HELPER(uitof_s
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
351 return float32_scalbn(uint32_to_float32(v
, &env
->fp_status
),
352 (int32_t)scale
, &env
->fp_status
);
355 float64
HELPER(cvtd_s
)(CPUXtensaState
*env
, float32 v
)
357 return float32_to_float64(v
, &env
->fp_status
);
360 float32
HELPER(cvts_d
)(CPUXtensaState
*env
, float64 v
)
362 return float64_to_float32(v
, &env
->fp_status
);
365 uint32_t HELPER(un_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
367 return float64_unordered_quiet(a
, b
, &env
->fp_status
);
370 uint32_t HELPER(un_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
372 return float32_unordered_quiet(a
, b
, &env
->fp_status
);
375 uint32_t HELPER(oeq_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
377 return float64_eq_quiet(a
, b
, &env
->fp_status
);
380 uint32_t HELPER(oeq_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
382 return float32_eq_quiet(a
, b
, &env
->fp_status
);
385 uint32_t HELPER(ueq_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
387 FloatRelation v
= float64_compare_quiet(a
, b
, &env
->fp_status
);
389 return v
== float_relation_equal
||
390 v
== float_relation_unordered
;
393 uint32_t HELPER(ueq_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
395 FloatRelation v
= float32_compare_quiet(a
, b
, &env
->fp_status
);
397 return v
== float_relation_equal
||
398 v
== float_relation_unordered
;
401 uint32_t HELPER(olt_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
403 return float64_lt(a
, b
, &env
->fp_status
);
406 uint32_t HELPER(olt_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
408 return float32_lt(a
, b
, &env
->fp_status
);
411 uint32_t HELPER(ult_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
413 FloatRelation v
= float64_compare_quiet(a
, b
, &env
->fp_status
);
415 return v
== float_relation_less
||
416 v
== float_relation_unordered
;
419 uint32_t HELPER(ult_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
421 FloatRelation v
= float32_compare_quiet(a
, b
, &env
->fp_status
);
423 return v
== float_relation_less
||
424 v
== float_relation_unordered
;
427 uint32_t HELPER(ole_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
429 return float64_le(a
, b
, &env
->fp_status
);
432 uint32_t HELPER(ole_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
434 return float32_le(a
, b
, &env
->fp_status
);
437 uint32_t HELPER(ule_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
439 FloatRelation v
= float64_compare_quiet(a
, b
, &env
->fp_status
);
441 return v
!= float_relation_greater
;
444 uint32_t HELPER(ule_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
446 FloatRelation v
= float32_compare_quiet(a
, b
, &env
->fp_status
);
448 return v
!= float_relation_greater
;