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 int32_t conv_round(int32_t a
, int n
)
85 } else if ((a
& ((1 << (n
- 1)) - 1)) == 0) { /* N-1..0 all zero? */
86 /* Add LSB from int part */
87 val
= ((fSE32_64(a
)) + (int64_t) (((uint32_t) ((1 << n
) & a
)) >> 1));
89 val
= ((fSE32_64(a
)) + (1 << (n
- 1)));
96 /* Floating Point Stuff */
98 static const FloatRoundMode softfloat_roundingmodes
[] = {
99 float_round_nearest_even
,
105 void arch_fpop_start(CPUHexagonState
*env
)
107 set_float_exception_flags(0, &env
->fp_status
);
108 set_float_rounding_mode(
109 softfloat_roundingmodes
[fREAD_REG_FIELD(USR
, USR_FPRND
)],
113 #ifdef CONFIG_USER_ONLY
115 * Hexagon Linux kernel only sets the relevant bits in USR (user status
116 * register). The exception isn't raised to user mode, so we don't
117 * model it in qemu user mode.
119 #define RAISE_FP_EXCEPTION do {} while (0)
122 #define SOFTFLOAT_TEST_FLAG(FLAG, MYF, MYE) \
124 if (flags & FLAG) { \
125 if (GET_USR_FIELD(USR_##MYF) == 0) { \
126 SET_USR_FIELD(USR_##MYF, 1); \
127 if (GET_USR_FIELD(USR_##MYE)) { \
128 RAISE_FP_EXCEPTION; \
134 void arch_fpop_end(CPUHexagonState
*env
)
136 int flags
= get_float_exception_flags(&env
->fp_status
);
138 SOFTFLOAT_TEST_FLAG(float_flag_inexact
, FPINPF
, FPINPE
);
139 SOFTFLOAT_TEST_FLAG(float_flag_divbyzero
, FPDBZF
, FPDBZE
);
140 SOFTFLOAT_TEST_FLAG(float_flag_invalid
, FPINVF
, FPINVE
);
141 SOFTFLOAT_TEST_FLAG(float_flag_overflow
, FPOVFF
, FPOVFE
);
142 SOFTFLOAT_TEST_FLAG(float_flag_underflow
, FPUNFF
, FPUNFE
);
146 int arch_sf_recip_common(float32
*Rs
, float32
*Rt
, float32
*Rd
, int *adjust
,
147 float_status
*fp_status
)
152 float32 RsV
, RtV
, RdV
;
156 if (float32_is_any_nan(RsV
) && float32_is_any_nan(RtV
)) {
157 if (extract32(RsV
& RtV
, 22, 1) == 0) {
158 float_raise(float_flag_invalid
, fp_status
);
160 RdV
= RsV
= RtV
= float32_nan
;
161 } else if (float32_is_any_nan(RsV
)) {
162 if (extract32(RsV
, 22, 1) == 0) {
163 float_raise(float_flag_invalid
, fp_status
);
165 RdV
= RsV
= RtV
= float32_nan
;
166 } else if (float32_is_any_nan(RtV
)) {
167 /* or put NaN in num/den fixup? */
168 if (extract32(RtV
, 22, 1) == 0) {
169 float_raise(float_flag_invalid
, fp_status
);
171 RdV
= RsV
= RtV
= float32_nan
;
172 } else if (float32_is_infinity(RsV
) && float32_is_infinity(RtV
)) {
173 /* or put Inf in num fixup? */
174 RdV
= RsV
= RtV
= float32_nan
;
175 float_raise(float_flag_invalid
, fp_status
);
176 } else if (float32_is_zero(RsV
) && float32_is_zero(RtV
)) {
177 /* or put zero in num fixup? */
178 RdV
= RsV
= RtV
= float32_nan
;
179 float_raise(float_flag_invalid
, fp_status
);
180 } else if (float32_is_zero(RtV
)) {
181 /* or put Inf in num fixup? */
182 uint8_t RsV_sign
= float32_is_neg(RsV
);
183 uint8_t RtV_sign
= float32_is_neg(RtV
);
184 RsV
= infinite_float32(RsV_sign
^ RtV_sign
);
187 if (float32_is_infinity(RsV
)) {
188 float_raise(float_flag_divbyzero
, fp_status
);
190 } else if (float32_is_infinity(RtV
)) {
191 RsV
= make_float32(0x80000000 & (RsV
^ RtV
));
194 } else if (float32_is_zero(RsV
)) {
195 /* Does this just work itself out? */
196 /* No, 0/Inf causes problems. */
197 RsV
= make_float32(0x80000000 & (RsV
^ RtV
));
200 } else if (float32_is_infinity(RsV
)) {
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
);
208 /* Basic checks passed */
209 n_exp
= float32_getexp(RsV
);
210 d_exp
= float32_getexp(RtV
);
211 if ((n_exp
- d_exp
+ SF_BIAS
) <= SF_MANTBITS
) {
212 /* Near quotient underflow / inexact Q */
214 RtV
= float32_scalbn(RtV
, -64, fp_status
);
215 RsV
= float32_scalbn(RsV
, 64, fp_status
);
216 } else if ((n_exp
- d_exp
+ SF_BIAS
) > (SF_MAXEXP
- 24)) {
217 /* Near quotient overflow */
219 RtV
= float32_scalbn(RtV
, 32, fp_status
);
220 RsV
= float32_scalbn(RsV
, -32, fp_status
);
221 } else if (n_exp
<= SF_MANTBITS
+ 2) {
222 RtV
= float32_scalbn(RtV
, 64, fp_status
);
223 RsV
= float32_scalbn(RsV
, 64, fp_status
);
224 } else if (d_exp
<= 1) {
225 RtV
= float32_scalbn(RtV
, 32, fp_status
);
226 RsV
= float32_scalbn(RsV
, 32, fp_status
);
227 } else if (d_exp
> 252) {
228 RtV
= float32_scalbn(RtV
, -32, fp_status
);
229 RsV
= float32_scalbn(RsV
, -32, fp_status
);
241 int arch_sf_invsqrt_common(float32
*Rs
, float32
*Rd
, int *adjust
,
242 float_status
*fp_status
)
249 if (float32_is_infinity(RsV
)) {
250 if (extract32(RsV
, 22, 1) == 0) {
251 float_raise(float_flag_invalid
, fp_status
);
253 RdV
= RsV
= float32_nan
;
254 } else if (float32_lt(RsV
, float32_zero
, fp_status
)) {
255 /* Negative nonzero values are NaN */
256 float_raise(float_flag_invalid
, fp_status
);
259 } else if (float32_is_infinity(RsV
)) {
260 /* or put Inf in num fixup? */
261 RsV
= infinite_float32(1);
262 RdV
= infinite_float32(1);
263 } else if (float32_is_zero(RsV
)) {
264 /* or put zero in num fixup? */
268 /* Basic checks passed */
269 r_exp
= float32_getexp(RsV
);
271 RsV
= float32_scalbn(RsV
, 64, fp_status
);