1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "cpu.h"
22#include "exec/exec-all.h"
23#include "exec/helper-proto.h"
24#include "fpu/softfloat.h"
25
26#define FP_STATUS (env->fp_status)
27
28
29void helper_setroundmode(CPUAlphaState *env, uint32_t val)
30{
31 set_float_rounding_mode(val, &FP_STATUS);
32}
33
34void helper_setflushzero(CPUAlphaState *env, uint32_t val)
35{
36 set_flush_to_zero(val, &FP_STATUS);
37}
38
39#define CONVERT_BIT(X, SRC, DST) \
40 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
41
42static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
43{
44 uint8_t exc = get_float_exception_flags(&FP_STATUS);
45 uint32_t ret = 0;
46
47 if (unlikely(exc)) {
48 set_float_exception_flags(0, &FP_STATUS);
49 ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
50 ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
51 ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
52 ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
53 ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
54 }
55
56 return ret;
57}
58
59static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
60 uint32_t exc, uint32_t regno, uint32_t hw_exc)
61{
62 hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
63 hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
64 hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
65 hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
66 hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
67 hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
68
69 arith_excp(env, retaddr, hw_exc, 1ull << regno);
70}
71
72
73
74
75void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
76{
77 uint32_t exc = env->error_code;
78 if (exc) {
79 env->fpcr |= exc;
80 exc &= ~ignore;
81 if (exc) {
82 fp_exc_raise1(env, GETPC(), exc, regno, 0);
83 }
84 }
85}
86
87
88void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
89{
90 uint32_t exc = env->error_code & ~ignore;
91 if (exc) {
92 env->fpcr |= exc;
93 exc &= ~ignore;
94#ifdef CONFIG_USER_ONLY
95
96
97
98
99 if (!(exc & env->fpcr_exc_enable)) {
100 return;
101 }
102#else
103
104
105
106
107 if (!exc) {
108 return;
109 }
110#endif
111 exc &= env->fpcr_exc_enable;
112 fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
113 }
114}
115
116
117
118void helper_ieee_input(CPUAlphaState *env, uint64_t val)
119{
120 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
121 uint64_t frac = val & 0xfffffffffffffull;
122
123 if (exp == 0) {
124
125 if (frac != 0) {
126 arith_excp(env, GETPC(), EXC_M_INV, 0);
127 }
128 } else if (exp == 0x7ff) {
129
130 env->fpcr |= FPCR_INV;
131 arith_excp(env, GETPC(), EXC_M_INV, 0);
132 }
133}
134
135
136void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
137{
138 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
139 uint64_t frac = val & 0xfffffffffffffull;
140
141 if (exp == 0) {
142
143 if (frac != 0) {
144 arith_excp(env, GETPC(), EXC_M_INV, 0);
145 }
146 } else if (exp == 0x7ff && frac) {
147
148 env->fpcr |= FPCR_INV;
149 arith_excp(env, GETPC(), EXC_M_INV, 0);
150 }
151}
152
153
154
155
156
157
158
159void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
160{
161 if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
162 && !env->fp_status.flush_inputs_to_zero) {
163 arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
164 }
165}
166
167
168
169
170static inline uint64_t float32_to_s_int(uint32_t fi)
171{
172 uint32_t frac = fi & 0x7fffff;
173 uint32_t sign = fi >> 31;
174 uint32_t exp_msb = (fi >> 30) & 1;
175 uint32_t exp_low = (fi >> 23) & 0x7f;
176 uint32_t exp;
177
178 exp = (exp_msb << 10) | exp_low;
179 if (exp_msb) {
180 if (exp_low == 0x7f) {
181 exp = 0x7ff;
182 }
183 } else {
184 if (exp_low != 0x00) {
185 exp |= 0x380;
186 }
187 }
188
189 return (((uint64_t)sign << 63)
190 | ((uint64_t)exp << 52)
191 | ((uint64_t)frac << 29));
192}
193
194static inline uint64_t float32_to_s(float32 fa)
195{
196 CPU_FloatU a;
197 a.f = fa;
198 return float32_to_s_int(a.l);
199}
200
201static inline uint32_t s_to_float32_int(uint64_t a)
202{
203 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
204}
205
206static inline float32 s_to_float32(uint64_t a)
207{
208 CPU_FloatU r;
209 r.l = s_to_float32_int(a);
210 return r.f;
211}
212
213uint32_t helper_s_to_memory(uint64_t a)
214{
215 return s_to_float32_int(a);
216}
217
218uint64_t helper_memory_to_s(uint32_t a)
219{
220 return float32_to_s_int(a);
221}
222
223uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
224{
225 float32 fa, fb, fr;
226
227 fa = s_to_float32(a);
228 fb = s_to_float32(b);
229 fr = float32_add(fa, fb, &FP_STATUS);
230 env->error_code = soft_to_fpcr_exc(env);
231
232 return float32_to_s(fr);
233}
234
235uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
236{
237 float32 fa, fb, fr;
238
239 fa = s_to_float32(a);
240 fb = s_to_float32(b);
241 fr = float32_sub(fa, fb, &FP_STATUS);
242 env->error_code = soft_to_fpcr_exc(env);
243
244 return float32_to_s(fr);
245}
246
247uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
248{
249 float32 fa, fb, fr;
250
251 fa = s_to_float32(a);
252 fb = s_to_float32(b);
253 fr = float32_mul(fa, fb, &FP_STATUS);
254 env->error_code = soft_to_fpcr_exc(env);
255
256 return float32_to_s(fr);
257}
258
259uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
260{
261 float32 fa, fb, fr;
262
263 fa = s_to_float32(a);
264 fb = s_to_float32(b);
265 fr = float32_div(fa, fb, &FP_STATUS);
266 env->error_code = soft_to_fpcr_exc(env);
267
268 return float32_to_s(fr);
269}
270
271uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
272{
273 float32 fa, fr;
274
275 fa = s_to_float32(a);
276 fr = float32_sqrt(fa, &FP_STATUS);
277 env->error_code = soft_to_fpcr_exc(env);
278
279 return float32_to_s(fr);
280}
281
282
283
284static inline float64 t_to_float64(uint64_t a)
285{
286
287 CPU_DoubleU r;
288 r.ll = a;
289 return r.d;
290}
291
292static inline uint64_t float64_to_t(float64 fa)
293{
294
295 CPU_DoubleU r;
296 r.d = fa;
297 return r.ll;
298}
299
300uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
301{
302 float64 fa, fb, fr;
303
304 fa = t_to_float64(a);
305 fb = t_to_float64(b);
306 fr = float64_add(fa, fb, &FP_STATUS);
307 env->error_code = soft_to_fpcr_exc(env);
308
309 return float64_to_t(fr);
310}
311
312uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
313{
314 float64 fa, fb, fr;
315
316 fa = t_to_float64(a);
317 fb = t_to_float64(b);
318 fr = float64_sub(fa, fb, &FP_STATUS);
319 env->error_code = soft_to_fpcr_exc(env);
320
321 return float64_to_t(fr);
322}
323
324uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
325{
326 float64 fa, fb, fr;
327
328 fa = t_to_float64(a);
329 fb = t_to_float64(b);
330 fr = float64_mul(fa, fb, &FP_STATUS);
331 env->error_code = soft_to_fpcr_exc(env);
332
333 return float64_to_t(fr);
334}
335
336uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
337{
338 float64 fa, fb, fr;
339
340 fa = t_to_float64(a);
341 fb = t_to_float64(b);
342 fr = float64_div(fa, fb, &FP_STATUS);
343 env->error_code = soft_to_fpcr_exc(env);
344
345 return float64_to_t(fr);
346}
347
348uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
349{
350 float64 fa, fr;
351
352 fa = t_to_float64(a);
353 fr = float64_sqrt(fa, &FP_STATUS);
354 env->error_code = soft_to_fpcr_exc(env);
355
356 return float64_to_t(fr);
357}
358
359
360uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
361{
362 float64 fa, fb;
363 uint64_t ret = 0;
364
365 fa = t_to_float64(a);
366 fb = t_to_float64(b);
367
368 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
369 ret = 0x4000000000000000ULL;
370 }
371 env->error_code = soft_to_fpcr_exc(env);
372
373 return ret;
374}
375
376uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
377{
378 float64 fa, fb;
379 uint64_t ret = 0;
380
381 fa = t_to_float64(a);
382 fb = t_to_float64(b);
383
384 if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
385 ret = 0x4000000000000000ULL;
386 }
387 env->error_code = soft_to_fpcr_exc(env);
388
389 return ret;
390}
391
392uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
393{
394 float64 fa, fb;
395 uint64_t ret = 0;
396
397 fa = t_to_float64(a);
398 fb = t_to_float64(b);
399
400 if (float64_le(fa, fb, &FP_STATUS)) {
401 ret = 0x4000000000000000ULL;
402 }
403 env->error_code = soft_to_fpcr_exc(env);
404
405 return ret;
406}
407
408uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
409{
410 float64 fa, fb;
411 uint64_t ret = 0;
412
413 fa = t_to_float64(a);
414 fb = t_to_float64(b);
415
416 if (float64_lt(fa, fb, &FP_STATUS)) {
417 ret = 0x4000000000000000ULL;
418 }
419 env->error_code = soft_to_fpcr_exc(env);
420
421 return ret;
422}
423
424
425uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
426{
427 float64 fa;
428 float32 fr;
429
430 fa = t_to_float64(a);
431 fr = float64_to_float32(fa, &FP_STATUS);
432 env->error_code = soft_to_fpcr_exc(env);
433
434 return float32_to_s(fr);
435}
436
437uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
438{
439 float32 fa;
440 float64 fr;
441
442 fa = s_to_float32(a);
443 fr = float32_to_float64(fa, &FP_STATUS);
444 env->error_code = soft_to_fpcr_exc(env);
445
446 return float64_to_t(fr);
447}
448
449uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
450{
451 float32 fr = int64_to_float32(a, &FP_STATUS);
452 env->error_code = soft_to_fpcr_exc(env);
453
454 return float32_to_s(fr);
455}
456
457
458
459
460
461static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
462{
463 uint64_t frac, ret = 0;
464 uint32_t exp, sign, exc = 0;
465 int shift;
466
467 sign = (a >> 63);
468 exp = (uint32_t)(a >> 52) & 0x7ff;
469 frac = a & 0xfffffffffffffull;
470
471 if (exp == 0) {
472 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
473 goto do_underflow;
474 }
475 } else if (exp == 0x7ff) {
476 exc = FPCR_INV;
477 } else {
478
479 frac |= 0x10000000000000ull;
480
481 shift = exp - 1023 - 52;
482 if (shift >= 0) {
483
484
485 if (shift < 64) {
486 ret = frac << shift;
487 }
488
489 if (shift >= 11 && a != 0xC3E0000000000000ull) {
490 exc = FPCR_IOV | FPCR_INE;
491 }
492 } else {
493 uint64_t round;
494
495
496
497
498
499
500 shift = -shift;
501 if (shift < 63) {
502 ret = frac >> shift;
503 round = frac << (64 - shift);
504 } else {
505
506
507 do_underflow:
508 round = 1;
509 }
510
511 if (round) {
512 exc = FPCR_INE;
513 switch (roundmode) {
514 case float_round_nearest_even:
515 if (round == (1ull << 63)) {
516
517 ret += (ret & 1);
518 } else if (round > (1ull << 63)) {
519 ret += 1;
520 }
521 break;
522 case float_round_to_zero:
523 break;
524 case float_round_up:
525 ret += 1 - sign;
526 break;
527 case float_round_down:
528 ret += sign;
529 break;
530 }
531 }
532 }
533 if (sign) {
534 ret = -ret;
535 }
536 }
537 env->error_code = exc;
538
539 return ret;
540}
541
542uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
543{
544 return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
545}
546
547uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
548{
549 return do_cvttq(env, a, float_round_to_zero);
550}
551
552uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
553{
554 float64 fr = int64_to_float64(a, &FP_STATUS);
555 env->error_code = soft_to_fpcr_exc(env);
556 return float64_to_t(fr);
557}
558
559uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
560{
561 uint32_t exc = 0;
562 if (val != (int32_t)val) {
563 exc = FPCR_IOV | FPCR_INE;
564 }
565 env->error_code = exc;
566
567 return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);
568}
569