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