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