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