2 * Copyright(c) 2019-2021 Qualcomm Innovation Center, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 #include "qemu/osdep.h"
19 #include "fpu/softfloat.h"
27 #define SF_MANTBITS 23
28 #define float32_nan make_float32(0xffffffff)
30 #define BITS_MASK_8 0x5555555555555555ULL
31 #define PAIR_MASK_8 0x3333333333333333ULL
32 #define NYBL_MASK_8 0x0f0f0f0f0f0f0f0fULL
33 #define BYTE_MASK_8 0x00ff00ff00ff00ffULL
34 #define HALF_MASK_8 0x0000ffff0000ffffULL
35 #define WORD_MASK_8 0x00000000ffffffffULL
37 uint64_t interleave(uint32_t odd
, uint32_t even
)
39 /* Convert to long long */
41 uint64_t myeven
= even
;
42 /* First, spread bits out */
43 myodd
= (myodd
| (myodd
<< 16)) & HALF_MASK_8
;
44 myeven
= (myeven
| (myeven
<< 16)) & HALF_MASK_8
;
45 myodd
= (myodd
| (myodd
<< 8)) & BYTE_MASK_8
;
46 myeven
= (myeven
| (myeven
<< 8)) & BYTE_MASK_8
;
47 myodd
= (myodd
| (myodd
<< 4)) & NYBL_MASK_8
;
48 myeven
= (myeven
| (myeven
<< 4)) & NYBL_MASK_8
;
49 myodd
= (myodd
| (myodd
<< 2)) & PAIR_MASK_8
;
50 myeven
= (myeven
| (myeven
<< 2)) & PAIR_MASK_8
;
51 myodd
= (myodd
| (myodd
<< 1)) & BITS_MASK_8
;
52 myeven
= (myeven
| (myeven
<< 1)) & BITS_MASK_8
;
54 return myeven
| (myodd
<< 1);
57 uint64_t deinterleave(uint64_t src
)
59 /* Get odd and even bits */
60 uint64_t myodd
= ((src
>> 1) & BITS_MASK_8
);
61 uint64_t myeven
= (src
& BITS_MASK_8
);
64 myeven
= (myeven
| (myeven
>> 1)) & PAIR_MASK_8
;
65 myodd
= (myodd
| (myodd
>> 1)) & PAIR_MASK_8
;
66 myeven
= (myeven
| (myeven
>> 2)) & NYBL_MASK_8
;
67 myodd
= (myodd
| (myodd
>> 2)) & NYBL_MASK_8
;
68 myeven
= (myeven
| (myeven
>> 4)) & BYTE_MASK_8
;
69 myodd
= (myodd
| (myodd
>> 4)) & BYTE_MASK_8
;
70 myeven
= (myeven
| (myeven
>> 8)) & HALF_MASK_8
;
71 myodd
= (myodd
| (myodd
>> 8)) & HALF_MASK_8
;
72 myeven
= (myeven
| (myeven
>> 16)) & WORD_MASK_8
;
73 myodd
= (myodd
| (myodd
>> 16)) & WORD_MASK_8
;
75 /* Return odd bits in upper half */
76 return myeven
| (myodd
<< 32);
79 uint32_t carry_from_add64(uint64_t a
, uint64_t b
, uint32_t c
)
81 uint64_t tmpa
, tmpb
, tmpc
;
82 tmpa
= fGETUWORD(0, a
);
83 tmpb
= fGETUWORD(0, b
);
84 tmpc
= tmpa
+ tmpb
+ c
;
85 tmpa
= fGETUWORD(1, a
);
86 tmpb
= fGETUWORD(1, b
);
87 tmpc
= tmpa
+ tmpb
+ fGETUWORD(1, tmpc
);
88 tmpc
= fGETUWORD(1, tmpc
);
92 int32_t conv_round(int32_t a
, int n
)
98 } else if ((a
& ((1 << (n
- 1)) - 1)) == 0) { /* N-1..0 all zero? */
99 /* Add LSB from int part */
100 val
= ((fSE32_64(a
)) + (int64_t) (((uint32_t) ((1 << n
) & a
)) >> 1));
102 val
= ((fSE32_64(a
)) + (1 << (n
- 1)));
109 /* Floating Point Stuff */
111 static const int softfloat_roundingmodes
[] = {
112 float_round_nearest_even
,
118 void arch_fpop_start(CPUHexagonState
*env
)
120 set_float_exception_flags(0, &env
->fp_status
);
121 set_float_rounding_mode(
122 softfloat_roundingmodes
[fREAD_REG_FIELD(USR
, USR_FPRND
)],
126 #ifdef CONFIG_USER_ONLY
128 * Hexagon Linux kernel only sets the relevant bits in USR (user status
129 * register). The exception isn't raised to user mode, so we don't
130 * model it in qemu user mode.
132 #define RAISE_FP_EXCEPTION do {} while (0)
135 #define SOFTFLOAT_TEST_FLAG(FLAG, MYF, MYE) \
137 if (flags & FLAG) { \
138 if (GET_USR_FIELD(USR_##MYF) == 0) { \
139 SET_USR_FIELD(USR_##MYF, 1); \
140 if (GET_USR_FIELD(USR_##MYE)) { \
141 RAISE_FP_EXCEPTION; \
147 void arch_fpop_end(CPUHexagonState
*env
)
149 int flags
= get_float_exception_flags(&env
->fp_status
);
151 SOFTFLOAT_TEST_FLAG(float_flag_inexact
, FPINPF
, FPINPE
);
152 SOFTFLOAT_TEST_FLAG(float_flag_divbyzero
, FPDBZF
, FPDBZE
);
153 SOFTFLOAT_TEST_FLAG(float_flag_invalid
, FPINVF
, FPINVE
);
154 SOFTFLOAT_TEST_FLAG(float_flag_overflow
, FPOVFF
, FPOVFE
);
155 SOFTFLOAT_TEST_FLAG(float_flag_underflow
, FPUNFF
, FPUNFE
);
159 static float32
float32_mul_pow2(float32 a
, uint32_t p
, float_status
*fp_status
)
161 float32 b
= make_float32((SF_BIAS
+ p
) << SF_MANTBITS
);
162 return float32_mul(a
, b
, fp_status
);
165 int arch_sf_recip_common(float32
*Rs
, float32
*Rt
, float32
*Rd
, int *adjust
,
166 float_status
*fp_status
)
171 float32 RsV
, RtV
, RdV
;
175 if (float32_is_any_nan(RsV
) && float32_is_any_nan(RtV
)) {
176 if (extract32(RsV
& RtV
, 22, 1) == 0) {
177 float_raise(float_flag_invalid
, fp_status
);
179 RdV
= RsV
= RtV
= float32_nan
;
180 } else if (float32_is_any_nan(RsV
)) {
181 if (extract32(RsV
, 22, 1) == 0) {
182 float_raise(float_flag_invalid
, fp_status
);
184 RdV
= RsV
= RtV
= float32_nan
;
185 } else if (float32_is_any_nan(RtV
)) {
186 /* or put NaN in num/den fixup? */
187 if (extract32(RtV
, 22, 1) == 0) {
188 float_raise(float_flag_invalid
, fp_status
);
190 RdV
= RsV
= RtV
= float32_nan
;
191 } else if (float32_is_infinity(RsV
) && float32_is_infinity(RtV
)) {
192 /* or put Inf in num fixup? */
193 RdV
= RsV
= RtV
= float32_nan
;
194 float_raise(float_flag_invalid
, fp_status
);
195 } else if (float32_is_zero(RsV
) && float32_is_zero(RtV
)) {
196 /* or put zero in num fixup? */
197 RdV
= RsV
= RtV
= float32_nan
;
198 float_raise(float_flag_invalid
, fp_status
);
199 } else if (float32_is_zero(RtV
)) {
200 /* or put Inf in num fixup? */
201 uint8_t RsV_sign
= float32_is_neg(RsV
);
202 uint8_t RtV_sign
= float32_is_neg(RtV
);
203 RsV
= infinite_float32(RsV_sign
^ RtV_sign
);
206 if (float32_is_infinity(RsV
)) {
207 float_raise(float_flag_divbyzero
, fp_status
);
209 } else if (float32_is_infinity(RtV
)) {
210 RsV
= make_float32(0x80000000 & (RsV
^ RtV
));
213 } else if (float32_is_zero(RsV
)) {
214 /* Does this just work itself out? */
215 /* No, 0/Inf causes problems. */
216 RsV
= make_float32(0x80000000 & (RsV
^ RtV
));
219 } else if (float32_is_infinity(RsV
)) {
220 uint8_t RsV_sign
= float32_is_neg(RsV
);
221 uint8_t RtV_sign
= float32_is_neg(RtV
);
222 RsV
= infinite_float32(RsV_sign
^ RtV_sign
);
227 /* Basic checks passed */
228 n_exp
= float32_getexp(RsV
);
229 d_exp
= float32_getexp(RtV
);
230 if ((n_exp
- d_exp
+ SF_BIAS
) <= SF_MANTBITS
) {
231 /* Near quotient underflow / inexact Q */
233 RtV
= float32_mul_pow2(RtV
, -64, fp_status
);
234 RsV
= float32_mul_pow2(RsV
, 64, fp_status
);
235 } else if ((n_exp
- d_exp
+ SF_BIAS
) > (SF_MAXEXP
- 24)) {
236 /* Near quotient overflow */
238 RtV
= float32_mul_pow2(RtV
, 32, fp_status
);
239 RsV
= float32_mul_pow2(RsV
, -32, fp_status
);
240 } else if (n_exp
<= SF_MANTBITS
+ 2) {
241 RtV
= float32_mul_pow2(RtV
, 64, fp_status
);
242 RsV
= float32_mul_pow2(RsV
, 64, fp_status
);
243 } else if (d_exp
<= 1) {
244 RtV
= float32_mul_pow2(RtV
, 32, fp_status
);
245 RsV
= float32_mul_pow2(RsV
, 32, fp_status
);
246 } else if (d_exp
> 252) {
247 RtV
= float32_mul_pow2(RtV
, -32, fp_status
);
248 RsV
= float32_mul_pow2(RsV
, -32, fp_status
);
260 int arch_sf_invsqrt_common(float32
*Rs
, float32
*Rd
, int *adjust
,
261 float_status
*fp_status
)
268 if (float32_is_infinity(RsV
)) {
269 if (extract32(RsV
, 22, 1) == 0) {
270 float_raise(float_flag_invalid
, fp_status
);
272 RdV
= RsV
= float32_nan
;
273 } else if (float32_lt(RsV
, float32_zero
, fp_status
)) {
274 /* Negative nonzero values are NaN */
275 float_raise(float_flag_invalid
, fp_status
);
278 } else if (float32_is_infinity(RsV
)) {
279 /* or put Inf in num fixup? */
280 RsV
= infinite_float32(1);
281 RdV
= infinite_float32(1);
282 } else if (float32_is_zero(RsV
)) {
283 /* or put zero in num fixup? */
287 /* Basic checks passed */
288 r_exp
= float32_getexp(RsV
);
290 RsV
= float32_mul_pow2(RsV
, 64, fp_status
);