master
c 464 lines 13.3 KB
Raw
1 /*
2 * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab.
3 * All rights reserved.
4 *
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.
15 *
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.
26 */
27
28 #include "qemu/osdep.h"
29 #include "qemu/log.h"
30 #include "cpu.h"
31 #include "exec/helper-proto.h"
32 #include "qemu/host-utils.h"
33 #include "fpu/softfloat.h"
34
35 enum {
36 XTENSA_FP_I = 0x1,
37 XTENSA_FP_U = 0x2,
38 XTENSA_FP_O = 0x4,
39 XTENSA_FP_Z = 0x8,
40 XTENSA_FP_V = 0x10,
41 };
42
43 enum {
44 XTENSA_FCR_FLAGS_SHIFT = 2,
45 XTENSA_FSR_FLAGS_SHIFT = 7,
46 };
47
48 static const struct {
49 uint32_t xtensa_fp_flag;
50 int softfloat_fp_flag;
51 } xtensa_fp_flag_map[] = {
52 { XTENSA_FP_I, float_flag_inexact, },
53 { XTENSA_FP_U, float_flag_underflow, },
54 { XTENSA_FP_O, float_flag_overflow, },
55 { XTENSA_FP_Z, float_flag_divbyzero, },
56 { XTENSA_FP_V, float_flag_invalid, },
57 };
58
59 void xtensa_use_first_nan(CPUXtensaState *env, bool use_first)
60 {
61 set_float_2nan_prop_rule(use_first ? float_2nan_prop_ab : float_2nan_prop_ba,
62 &env->fp_status);
63 set_float_3nan_prop_rule(use_first ? float_3nan_prop_abc : float_3nan_prop_cba,
64 &env->fp_status);
65 }
66
67 uint32_t cpu_get_fsr(CPUXtensaState *env)
68 {
69 uint32_t flags = 0;
70 int fef = get_float_exception_flags(&env->fp_status);
71 unsigned i;
72
73 for (i = 0; i < ARRAY_SIZE(xtensa_fp_flag_map); ++i) {
74 if (fef & xtensa_fp_flag_map[i].softfloat_fp_flag) {
75 flags |= xtensa_fp_flag_map[i].xtensa_fp_flag;
76 }
77 }
78 return flags << XTENSA_FSR_FLAGS_SHIFT;
79 }
80
81 void cpu_set_fcr(CPUXtensaState *env, uint32_t v)
82 {
83 static const FloatRoundMode rounding_mode[] = {
84 float_round_nearest_even,
85 float_round_to_zero,
86 float_round_up,
87 float_round_down,
88 };
89
90 env->uregs[FCR] = v & 0xfffff07f;
91 set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status);
92 }
93
94 void cpu_set_fsr(CPUXtensaState *env, uint32_t v)
95 {
96 uint32_t flags = v >> XTENSA_FSR_FLAGS_SHIFT;
97 int fef = 0;
98 unsigned i;
99
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;
104 }
105 }
106 set_float_exception_flags(fef, &env->fp_status);
107 }
108
109 void HELPER(wur_fpu2k_fcr)(CPUXtensaState *env, uint32_t v)
110 {
111 cpu_set_fcr(env, v);
112 }
113
114 void HELPER(wur_fpu_fcr)(CPUXtensaState *env, uint32_t v)
115 {
116 if (v & 0xfffff000) {
117 qemu_log_mask(LOG_GUEST_ERROR,
118 "MBZ field of FCR is written non-zero: %08x\n", v);
119 }
120 cpu_set_fcr(env, v & 0x0000007f);
121 }
122
123 void HELPER(wur_fpu_fsr)(CPUXtensaState *env, uint32_t v)
124 {
125 if (v & 0xfffff000) {
126 qemu_log_mask(LOG_GUEST_ERROR,
127 "MBZ field of FSR is written non-zero: %08x\n", v);
128 }
129 cpu_set_fsr(env, v);
130 }
131
132 uint32_t HELPER(rur_fpu_fsr)(CPUXtensaState *env)
133 {
134 uint32_t fsr = cpu_get_fsr(env);
135
136 env->uregs[FSR] = fsr;
137 return fsr;
138 }
139
140 float64 HELPER(abs_d)(float64 v)
141 {
142 return float64_abs(v);
143 }
144
145 float32 HELPER(abs_s)(float32 v)
146 {
147 return float32_abs(v);
148 }
149
150 float64 HELPER(neg_d)(float64 v)
151 {
152 return float64_chs(v);
153 }
154
155 float32 HELPER(neg_s)(float32 v)
156 {
157 return float32_chs(v);
158 }
159
160 float32 HELPER(fpu2k_add_s)(CPUXtensaState *env, float32 a, float32 b)
161 {
162 return float32_add(a, b, &env->fp_status);
163 }
164
165 float32 HELPER(fpu2k_sub_s)(CPUXtensaState *env, float32 a, float32 b)
166 {
167 return float32_sub(a, b, &env->fp_status);
168 }
169
170 float32 HELPER(fpu2k_mul_s)(CPUXtensaState *env, float32 a, float32 b)
171 {
172 return float32_mul(a, b, &env->fp_status);
173 }
174
175 float32 HELPER(fpu2k_madd_s)(CPUXtensaState *env,
176 float32 a, float32 b, float32 c)
177 {
178 return float32_muladd(b, c, a, 0, &env->fp_status);
179 }
180
181 float32 HELPER(fpu2k_msub_s)(CPUXtensaState *env,
182 float32 a, float32 b, float32 c)
183 {
184 return float32_muladd(b, c, a, float_muladd_negate_product,
185 &env->fp_status);
186 }
187
188 float64 HELPER(add_d)(CPUXtensaState *env, float64 a, float64 b)
189 {
190 xtensa_use_first_nan(env, true);
191 return float64_add(a, b, &env->fp_status);
192 }
193
194 float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b)
195 {
196 xtensa_use_first_nan(env, env->config->use_first_nan);
197 return float32_add(a, b, &env->fp_status);
198 }
199
200 float64 HELPER(sub_d)(CPUXtensaState *env, float64 a, float64 b)
201 {
202 xtensa_use_first_nan(env, true);
203 return float64_sub(a, b, &env->fp_status);
204 }
205
206 float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b)
207 {
208 xtensa_use_first_nan(env, env->config->use_first_nan);
209 return float32_sub(a, b, &env->fp_status);
210 }
211
212 float64 HELPER(mul_d)(CPUXtensaState *env, float64 a, float64 b)
213 {
214 xtensa_use_first_nan(env, true);
215 return float64_mul(a, b, &env->fp_status);
216 }
217
218 float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b)
219 {
220 xtensa_use_first_nan(env, env->config->use_first_nan);
221 return float32_mul(a, b, &env->fp_status);
222 }
223
224 float64 HELPER(madd_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
225 {
226 xtensa_use_first_nan(env, env->config->use_first_nan);
227 return float64_muladd(b, c, a, 0, &env->fp_status);
228 }
229
230 float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
231 {
232 xtensa_use_first_nan(env, env->config->use_first_nan);
233 return float32_muladd(b, c, a, 0, &env->fp_status);
234 }
235
236 float64 HELPER(msub_d)(CPUXtensaState *env, float64 a, float64 b, float64 c)
237 {
238 xtensa_use_first_nan(env, env->config->use_first_nan);
239 return float64_muladd(b, c, a, float_muladd_negate_product,
240 &env->fp_status);
241 }
242
243 float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c)
244 {
245 xtensa_use_first_nan(env, env->config->use_first_nan);
246 return float32_muladd(b, c, a, float_muladd_negate_product,
247 &env->fp_status);
248 }
249
250 float64 HELPER(mkdadj_d)(CPUXtensaState *env, float64 a, float64 b)
251 {
252 xtensa_use_first_nan(env, true);
253 return float64_div(b, a, &env->fp_status);
254 }
255
256 float32 HELPER(mkdadj_s)(CPUXtensaState *env, float32 a, float32 b)
257 {
258 xtensa_use_first_nan(env, env->config->use_first_nan);
259 return float32_div(b, a, &env->fp_status);
260 }
261
262 float64 HELPER(mksadj_d)(CPUXtensaState *env, float64 v)
263 {
264 xtensa_use_first_nan(env, true);
265 return float64_sqrt(v, &env->fp_status);
266 }
267
268 float32 HELPER(mksadj_s)(CPUXtensaState *env, float32 v)
269 {
270 xtensa_use_first_nan(env, env->config->use_first_nan);
271 return float32_sqrt(v, &env->fp_status);
272 }
273
274 uint32_t HELPER(ftoi_d)(CPUXtensaState *env, float64 v,
275 uint32_t rounding_mode, uint32_t scale)
276 {
277 float_status fp_status = env->fp_status;
278 uint32_t res;
279
280 set_float_rounding_mode(rounding_mode, &fp_status);
281 res = float64_to_int32(float64_scalbn(v, scale, &fp_status), &fp_status);
282 set_float_exception_flags(get_float_exception_flags(&fp_status),
283 &env->fp_status);
284 return res;
285 }
286
287 uint32_t HELPER(ftoi_s)(CPUXtensaState *env, float32 v,
288 uint32_t rounding_mode, uint32_t scale)
289 {
290 float_status fp_status = env->fp_status;
291 uint32_t res;
292
293 set_float_rounding_mode(rounding_mode, &fp_status);
294 res = float32_to_int32(float32_scalbn(v, scale, &fp_status), &fp_status);
295 set_float_exception_flags(get_float_exception_flags(&fp_status),
296 &env->fp_status);
297 return res;
298 }
299
300 uint32_t HELPER(ftoui_d)(CPUXtensaState *env, float64 v,
301 uint32_t rounding_mode, uint32_t scale)
302 {
303 float_status fp_status = env->fp_status;
304 float64 res;
305 uint32_t rv;
306
307 set_float_rounding_mode(rounding_mode, &fp_status);
308
309 res = float64_scalbn(v, scale, &fp_status);
310
311 if (float64_is_neg(v) && !float64_is_any_nan(v)) {
312 set_float_exception_flags(float_flag_invalid, &fp_status);
313 rv = float64_to_int32(res, &fp_status);
314 } else {
315 rv = float64_to_uint32(res, &fp_status);
316 }
317 set_float_exception_flags(get_float_exception_flags(&fp_status),
318 &env->fp_status);
319 return rv;
320 }
321
322 uint32_t HELPER(ftoui_s)(CPUXtensaState *env, float32 v,
323 uint32_t rounding_mode, uint32_t scale)
324 {
325 float_status fp_status = env->fp_status;
326 float32 res;
327 uint32_t rv;
328
329 set_float_rounding_mode(rounding_mode, &fp_status);
330
331 res = float32_scalbn(v, scale, &fp_status);
332
333 if (float32_is_neg(v) && !float32_is_any_nan(v)) {
334 rv = float32_to_int32(res, &fp_status);
335 if (rv) {
336 set_float_exception_flags(float_flag_invalid, &fp_status);
337 }
338 } else {
339 rv = float32_to_uint32(res, &fp_status);
340 }
341 set_float_exception_flags(get_float_exception_flags(&fp_status),
342 &env->fp_status);
343 return rv;
344 }
345
346 float64 HELPER(itof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
347 {
348 return float64_scalbn(int32_to_float64(v, &env->fp_status),
349 (int32_t)scale, &env->fp_status);
350 }
351
352 float32 HELPER(itof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
353 {
354 return float32_scalbn(int32_to_float32(v, &env->fp_status),
355 (int32_t)scale, &env->fp_status);
356 }
357
358 float64 HELPER(uitof_d)(CPUXtensaState *env, uint32_t v, uint32_t scale)
359 {
360 return float64_scalbn(uint32_to_float64(v, &env->fp_status),
361 (int32_t)scale, &env->fp_status);
362 }
363
364 float32 HELPER(uitof_s)(CPUXtensaState *env, uint32_t v, uint32_t scale)
365 {
366 return float32_scalbn(uint32_to_float32(v, &env->fp_status),
367 (int32_t)scale, &env->fp_status);
368 }
369
370 float64 HELPER(cvtd_s)(CPUXtensaState *env, float32 v)
371 {
372 return float32_to_float64(v, &env->fp_status);
373 }
374
375 float32 HELPER(cvts_d)(CPUXtensaState *env, float64 v)
376 {
377 return float64_to_float32(v, &env->fp_status);
378 }
379
380 uint32_t HELPER(un_d)(CPUXtensaState *env, float64 a, float64 b)
381 {
382 return float64_unordered_quiet(a, b, &env->fp_status);
383 }
384
385 uint32_t HELPER(un_s)(CPUXtensaState *env, float32 a, float32 b)
386 {
387 return float32_unordered_quiet(a, b, &env->fp_status);
388 }
389
390 uint32_t HELPER(oeq_d)(CPUXtensaState *env, float64 a, float64 b)
391 {
392 return float64_eq_quiet(a, b, &env->fp_status);
393 }
394
395 uint32_t HELPER(oeq_s)(CPUXtensaState *env, float32 a, float32 b)
396 {
397 return float32_eq_quiet(a, b, &env->fp_status);
398 }
399
400 uint32_t HELPER(ueq_d)(CPUXtensaState *env, float64 a, float64 b)
401 {
402 FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
403
404 return v == float_relation_equal ||
405 v == float_relation_unordered;
406 }
407
408 uint32_t HELPER(ueq_s)(CPUXtensaState *env, float32 a, float32 b)
409 {
410 FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
411
412 return v == float_relation_equal ||
413 v == float_relation_unordered;
414 }
415
416 uint32_t HELPER(olt_d)(CPUXtensaState *env, float64 a, float64 b)
417 {
418 return float64_lt(a, b, &env->fp_status);
419 }
420
421 uint32_t HELPER(olt_s)(CPUXtensaState *env, float32 a, float32 b)
422 {
423 return float32_lt(a, b, &env->fp_status);
424 }
425
426 uint32_t HELPER(ult_d)(CPUXtensaState *env, float64 a, float64 b)
427 {
428 FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
429
430 return v == float_relation_less ||
431 v == float_relation_unordered;
432 }
433
434 uint32_t HELPER(ult_s)(CPUXtensaState *env, float32 a, float32 b)
435 {
436 FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
437
438 return v == float_relation_less ||
439 v == float_relation_unordered;
440 }
441
442 uint32_t HELPER(ole_d)(CPUXtensaState *env, float64 a, float64 b)
443 {
444 return float64_le(a, b, &env->fp_status);
445 }
446
447 uint32_t HELPER(ole_s)(CPUXtensaState *env, float32 a, float32 b)
448 {
449 return float32_le(a, b, &env->fp_status);
450 }
451
452 uint32_t HELPER(ule_d)(CPUXtensaState *env, float64 a, float64 b)
453 {
454 FloatRelation v = float64_compare_quiet(a, b, &env->fp_status);
455
456 return v != float_relation_greater;
457 }
458
459 uint32_t HELPER(ule_s)(CPUXtensaState *env, float32 a, float32 b)
460 {
461 FloatRelation v = float32_compare_quiet(a, b, &env->fp_status);
462
463 return v != float_relation_greater;
464 }