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"
29 #include "qemu/main-loop.h"
31 #include "exec/helper-proto.h"
32 #include "qemu/host-utils.h"
33 #include "exec/exec-all.h"
34 #include "fpu/softfloat.h"
45 XTENSA_FCR_FLAGS_SHIFT
= 2,
46 XTENSA_FSR_FLAGS_SHIFT
= 7,
50 uint32_t xtensa_fp_flag
;
51 int softfloat_fp_flag
;
52 } xtensa_fp_flag_map
[] = {
53 { XTENSA_FP_I
, float_flag_inexact
, },
54 { XTENSA_FP_U
, float_flag_underflow
, },
55 { XTENSA_FP_O
, float_flag_overflow
, },
56 { XTENSA_FP_Z
, float_flag_divbyzero
, },
57 { XTENSA_FP_V
, float_flag_invalid
, },
60 void HELPER(wur_fpu2k_fcr
)(CPUXtensaState
*env
, uint32_t v
)
62 static const int rounding_mode
[] = {
63 float_round_nearest_even
,
69 env
->uregs
[FCR
] = v
& 0xfffff07f;
70 set_float_rounding_mode(rounding_mode
[v
& 3], &env
->fp_status
);
73 void HELPER(wur_fpu_fcr
)(CPUXtensaState
*env
, uint32_t v
)
75 static const int rounding_mode
[] = {
76 float_round_nearest_even
,
83 qemu_log_mask(LOG_GUEST_ERROR
,
84 "MBZ field of FCR is written non-zero: %08x\n", v
);
86 env
->uregs
[FCR
] = v
& 0x0000007f;
87 set_float_rounding_mode(rounding_mode
[v
& 3], &env
->fp_status
);
90 void HELPER(wur_fpu_fsr
)(CPUXtensaState
*env
, uint32_t v
)
92 uint32_t flags
= v
>> XTENSA_FSR_FLAGS_SHIFT
;
97 qemu_log_mask(LOG_GUEST_ERROR
,
98 "MBZ field of FSR is written non-zero: %08x\n", v
);
100 env
->uregs
[FSR
] = v
& 0x00000f80;
101 for (i
= 0; i
< ARRAY_SIZE(xtensa_fp_flag_map
); ++i
) {
102 if (flags
& xtensa_fp_flag_map
[i
].xtensa_fp_flag
) {
103 fef
|= xtensa_fp_flag_map
[i
].softfloat_fp_flag
;
106 set_float_exception_flags(fef
, &env
->fp_status
);
109 uint32_t HELPER(rur_fpu_fsr
)(CPUXtensaState
*env
)
112 int fef
= get_float_exception_flags(&env
->fp_status
);
115 for (i
= 0; i
< ARRAY_SIZE(xtensa_fp_flag_map
); ++i
) {
116 if (fef
& xtensa_fp_flag_map
[i
].softfloat_fp_flag
) {
117 flags
|= xtensa_fp_flag_map
[i
].xtensa_fp_flag
;
120 env
->uregs
[FSR
] = flags
<< XTENSA_FSR_FLAGS_SHIFT
;
121 return flags
<< XTENSA_FSR_FLAGS_SHIFT
;
124 float64
HELPER(abs_d
)(float64 v
)
126 return float64_abs(v
);
129 float32
HELPER(abs_s
)(float32 v
)
131 return float32_abs(v
);
134 float64
HELPER(neg_d
)(float64 v
)
136 return float64_chs(v
);
139 float32
HELPER(neg_s
)(float32 v
)
141 return float32_chs(v
);
144 float32
HELPER(fpu2k_add_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
146 return float32_add(a
, b
, &env
->fp_status
);
149 float32
HELPER(fpu2k_sub_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
151 return float32_sub(a
, b
, &env
->fp_status
);
154 float32
HELPER(fpu2k_mul_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
156 return float32_mul(a
, b
, &env
->fp_status
);
159 float32
HELPER(fpu2k_madd_s
)(CPUXtensaState
*env
,
160 float32 a
, float32 b
, float32 c
)
162 return float32_muladd(b
, c
, a
, 0, &env
->fp_status
);
165 float32
HELPER(fpu2k_msub_s
)(CPUXtensaState
*env
,
166 float32 a
, float32 b
, float32 c
)
168 return float32_muladd(b
, c
, a
, float_muladd_negate_product
,
172 float64
HELPER(add_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
174 set_use_first_nan(true, &env
->fp_status
);
175 return float64_add(a
, b
, &env
->fp_status
);
178 float32
HELPER(add_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
180 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
181 return float32_add(a
, b
, &env
->fp_status
);
184 float64
HELPER(sub_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
186 set_use_first_nan(true, &env
->fp_status
);
187 return float64_sub(a
, b
, &env
->fp_status
);
190 float32
HELPER(sub_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
192 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
193 return float32_sub(a
, b
, &env
->fp_status
);
196 float64
HELPER(mul_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
198 set_use_first_nan(true, &env
->fp_status
);
199 return float64_mul(a
, b
, &env
->fp_status
);
202 float32
HELPER(mul_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
204 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
205 return float32_mul(a
, b
, &env
->fp_status
);
208 float64
HELPER(madd_d
)(CPUXtensaState
*env
, float64 a
, float64 b
, float64 c
)
210 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
211 return float64_muladd(b
, c
, a
, 0, &env
->fp_status
);
214 float32
HELPER(madd_s
)(CPUXtensaState
*env
, float32 a
, float32 b
, float32 c
)
216 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
217 return float32_muladd(b
, c
, a
, 0, &env
->fp_status
);
220 float64
HELPER(msub_d
)(CPUXtensaState
*env
, float64 a
, float64 b
, float64 c
)
222 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
223 return float64_muladd(b
, c
, a
, float_muladd_negate_product
,
227 float32
HELPER(msub_s
)(CPUXtensaState
*env
, float32 a
, float32 b
, float32 c
)
229 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
230 return float32_muladd(b
, c
, a
, float_muladd_negate_product
,
234 float64
HELPER(mkdadj_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
236 set_use_first_nan(true, &env
->fp_status
);
237 return float64_div(b
, a
, &env
->fp_status
);
240 float32
HELPER(mkdadj_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
242 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
243 return float32_div(b
, a
, &env
->fp_status
);
246 float64
HELPER(mksadj_d
)(CPUXtensaState
*env
, float64 v
)
248 set_use_first_nan(true, &env
->fp_status
);
249 return float64_sqrt(v
, &env
->fp_status
);
252 float32
HELPER(mksadj_s
)(CPUXtensaState
*env
, float32 v
)
254 set_use_first_nan(env
->config
->use_first_nan
, &env
->fp_status
);
255 return float32_sqrt(v
, &env
->fp_status
);
258 uint32_t HELPER(ftoi_d
)(CPUXtensaState
*env
, float64 v
,
259 uint32_t rounding_mode
, uint32_t scale
)
261 float_status fp_status
= env
->fp_status
;
264 set_float_rounding_mode(rounding_mode
, &fp_status
);
265 res
= float64_to_int32(float64_scalbn(v
, scale
, &fp_status
), &fp_status
);
266 set_float_exception_flags(get_float_exception_flags(&fp_status
),
271 uint32_t HELPER(ftoi_s
)(CPUXtensaState
*env
, float32 v
,
272 uint32_t rounding_mode
, uint32_t scale
)
274 float_status fp_status
= env
->fp_status
;
277 set_float_rounding_mode(rounding_mode
, &fp_status
);
278 res
= float32_to_int32(float32_scalbn(v
, scale
, &fp_status
), &fp_status
);
279 set_float_exception_flags(get_float_exception_flags(&fp_status
),
284 uint32_t HELPER(ftoui_d
)(CPUXtensaState
*env
, float64 v
,
285 uint32_t rounding_mode
, uint32_t scale
)
287 float_status fp_status
= env
->fp_status
;
291 set_float_rounding_mode(rounding_mode
, &fp_status
);
293 res
= float64_scalbn(v
, scale
, &fp_status
);
295 if (float64_is_neg(v
) && !float64_is_any_nan(v
)) {
296 set_float_exception_flags(float_flag_invalid
, &fp_status
);
297 rv
= float64_to_int32(res
, &fp_status
);
299 rv
= float64_to_uint32(res
, &fp_status
);
301 set_float_exception_flags(get_float_exception_flags(&fp_status
),
306 uint32_t HELPER(ftoui_s
)(CPUXtensaState
*env
, float32 v
,
307 uint32_t rounding_mode
, uint32_t scale
)
309 float_status fp_status
= env
->fp_status
;
313 set_float_rounding_mode(rounding_mode
, &fp_status
);
315 res
= float32_scalbn(v
, scale
, &fp_status
);
317 if (float32_is_neg(v
) && !float32_is_any_nan(v
)) {
318 rv
= float32_to_int32(res
, &fp_status
);
320 set_float_exception_flags(float_flag_invalid
, &fp_status
);
323 rv
= float32_to_uint32(res
, &fp_status
);
325 set_float_exception_flags(get_float_exception_flags(&fp_status
),
330 float64
HELPER(itof_d
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
332 return float64_scalbn(int32_to_float64(v
, &env
->fp_status
),
333 (int32_t)scale
, &env
->fp_status
);
336 float32
HELPER(itof_s
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
338 return float32_scalbn(int32_to_float32(v
, &env
->fp_status
),
339 (int32_t)scale
, &env
->fp_status
);
342 float64
HELPER(uitof_d
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
344 return float64_scalbn(uint32_to_float64(v
, &env
->fp_status
),
345 (int32_t)scale
, &env
->fp_status
);
348 float32
HELPER(uitof_s
)(CPUXtensaState
*env
, uint32_t v
, uint32_t scale
)
350 return float32_scalbn(uint32_to_float32(v
, &env
->fp_status
),
351 (int32_t)scale
, &env
->fp_status
);
354 float64
HELPER(cvtd_s
)(CPUXtensaState
*env
, float32 v
)
356 return float32_to_float64(v
, &env
->fp_status
);
359 float32
HELPER(cvts_d
)(CPUXtensaState
*env
, float64 v
)
361 return float64_to_float32(v
, &env
->fp_status
);
364 uint32_t HELPER(un_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
366 return float64_unordered_quiet(a
, b
, &env
->fp_status
);
369 uint32_t HELPER(un_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
371 return float32_unordered_quiet(a
, b
, &env
->fp_status
);
374 uint32_t HELPER(oeq_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
376 return float64_eq_quiet(a
, b
, &env
->fp_status
);
379 uint32_t HELPER(oeq_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
381 return float32_eq_quiet(a
, b
, &env
->fp_status
);
384 uint32_t HELPER(ueq_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
386 FloatRelation v
= float64_compare_quiet(a
, b
, &env
->fp_status
);
388 return v
== float_relation_equal
||
389 v
== float_relation_unordered
;
392 uint32_t HELPER(ueq_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
394 FloatRelation v
= float32_compare_quiet(a
, b
, &env
->fp_status
);
396 return v
== float_relation_equal
||
397 v
== float_relation_unordered
;
400 uint32_t HELPER(olt_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
402 return float64_lt(a
, b
, &env
->fp_status
);
405 uint32_t HELPER(olt_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
407 return float32_lt(a
, b
, &env
->fp_status
);
410 uint32_t HELPER(ult_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
412 FloatRelation v
= float64_compare_quiet(a
, b
, &env
->fp_status
);
414 return v
== float_relation_less
||
415 v
== float_relation_unordered
;
418 uint32_t HELPER(ult_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
420 FloatRelation v
= float32_compare_quiet(a
, b
, &env
->fp_status
);
422 return v
== float_relation_less
||
423 v
== float_relation_unordered
;
426 uint32_t HELPER(ole_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
428 return float64_le(a
, b
, &env
->fp_status
);
431 uint32_t HELPER(ole_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
433 return float32_le(a
, b
, &env
->fp_status
);
436 uint32_t HELPER(ule_d
)(CPUXtensaState
*env
, float64 a
, float64 b
)
438 FloatRelation v
= float64_compare_quiet(a
, b
, &env
->fp_status
);
440 return v
!= float_relation_greater
;
443 uint32_t HELPER(ule_s
)(CPUXtensaState
*env
, float32 a
, float32 b
)
445 FloatRelation v
= float32_compare_quiet(a
, b
, &env
->fp_status
);
447 return v
!= float_relation_greater
;