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