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