]>
Commit | Line | Data |
---|---|---|
4a58aedf RH |
1 | /* |
2 | * Helpers for floating point instructions. | |
3 | * | |
4 | * Copyright (c) 2007 Jocelyn Mayer | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "cpu.h" | |
2ef6175a | 21 | #include "exec/helper-proto.h" |
6b4c305c | 22 | #include "fpu/softfloat.h" |
4a58aedf RH |
23 | |
24 | #define FP_STATUS (env->fp_status) | |
25 | ||
26 | ||
27 | void helper_setroundmode(CPUAlphaState *env, uint32_t val) | |
28 | { | |
29 | set_float_rounding_mode(val, &FP_STATUS); | |
30 | } | |
31 | ||
32 | void helper_setflushzero(CPUAlphaState *env, uint32_t val) | |
33 | { | |
34 | set_flush_to_zero(val, &FP_STATUS); | |
35 | } | |
36 | ||
f3d3aad4 RH |
37 | #define CONVERT_BIT(X, SRC, DST) \ |
38 | (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) | |
4a58aedf | 39 | |
f3d3aad4 | 40 | static uint32_t soft_to_fpcr_exc(CPUAlphaState *env) |
4a58aedf | 41 | { |
f3d3aad4 RH |
42 | uint8_t exc = get_float_exception_flags(&FP_STATUS); |
43 | uint32_t ret = 0; | |
44 | ||
45 | if (unlikely(exc)) { | |
46 | set_float_exception_flags(0, &FP_STATUS); | |
47 | ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV); | |
48 | ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE); | |
49 | ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF); | |
50 | ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF); | |
51 | ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE); | |
52 | } | |
53 | ||
54 | return ret; | |
4a58aedf RH |
55 | } |
56 | ||
f3d3aad4 | 57 | static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr, |
f6b6b7b8 | 58 | uint32_t exc, uint32_t regno, uint32_t hw_exc) |
4a58aedf | 59 | { |
471d4930 RH |
60 | hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV); |
61 | hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE); | |
62 | hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV); | |
63 | hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF); | |
64 | hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE); | |
65 | hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV); | |
4a58aedf | 66 | |
471d4930 | 67 | arith_excp(env, retaddr, hw_exc, 1ull << regno); |
4a58aedf RH |
68 | } |
69 | ||
70 | /* Raise exceptions for ieee fp insns without software completion. | |
71 | In that case there are no exceptions that don't trap; the mask | |
72 | doesn't apply. */ | |
f3d3aad4 | 73 | void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno) |
4a58aedf | 74 | { |
471d4930 RH |
75 | uint32_t exc = env->error_code; |
76 | if (exc) { | |
77 | env->fpcr |= exc; | |
78 | exc &= ~ignore; | |
79 | if (exc) { | |
f6b6b7b8 | 80 | fp_exc_raise1(env, GETPC(), exc, regno, 0); |
471d4930 RH |
81 | } |
82 | } | |
4a58aedf RH |
83 | } |
84 | ||
85 | /* Raise exceptions for ieee fp insns with software completion. */ | |
f3d3aad4 | 86 | void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno) |
4a58aedf | 87 | { |
f3d3aad4 | 88 | uint32_t exc = env->error_code & ~ignore; |
4a58aedf | 89 | if (exc) { |
f3d3aad4 | 90 | env->fpcr |= exc; |
471d4930 RH |
91 | exc &= ~ignore; |
92 | if (exc) { | |
93 | exc &= env->fpcr_exc_enable; | |
f6b6b7b8 | 94 | fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC); |
471d4930 | 95 | } |
4a58aedf RH |
96 | } |
97 | } | |
98 | ||
74343409 RH |
99 | /* Input handing without software completion. Trap for all |
100 | non-finite numbers. */ | |
101 | void helper_ieee_input(CPUAlphaState *env, uint64_t val) | |
4a58aedf RH |
102 | { |
103 | uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; | |
104 | uint64_t frac = val & 0xfffffffffffffull; | |
105 | ||
106 | if (exp == 0) { | |
b99e8069 RH |
107 | /* Denormals without /S raise an exception. */ |
108 | if (frac != 0) { | |
109 | arith_excp(env, GETPC(), EXC_M_INV, 0); | |
4a58aedf RH |
110 | } |
111 | } else if (exp == 0x7ff) { | |
112 | /* Infinity or NaN. */ | |
b99e8069 RH |
113 | env->fpcr |= FPCR_INV; |
114 | arith_excp(env, GETPC(), EXC_M_INV, 0); | |
4a58aedf | 115 | } |
4a58aedf RH |
116 | } |
117 | ||
118 | /* Similar, but does not trap for infinities. Used for comparisons. */ | |
74343409 | 119 | void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) |
4a58aedf RH |
120 | { |
121 | uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; | |
122 | uint64_t frac = val & 0xfffffffffffffull; | |
123 | ||
124 | if (exp == 0) { | |
b99e8069 RH |
125 | /* Denormals without /S raise an exception. */ |
126 | if (frac != 0) { | |
127 | arith_excp(env, GETPC(), EXC_M_INV, 0); | |
4a58aedf RH |
128 | } |
129 | } else if (exp == 0x7ff && frac) { | |
130 | /* NaN. */ | |
b99e8069 | 131 | env->fpcr |= FPCR_INV; |
4a58aedf RH |
132 | arith_excp(env, GETPC(), EXC_M_INV, 0); |
133 | } | |
4a58aedf RH |
134 | } |
135 | ||
b99e8069 RH |
136 | /* Input handing with software completion. Trap for denorms, unless DNZ |
137 | is set. If we try to support DNOD (which none of the produced hardware | |
138 | did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set; | |
139 | then the code downstream of that will need to cope with denorms sans | |
140 | flush_input_to_zero. Most of it should work sanely, but there's | |
141 | nothing to compare with. */ | |
142 | void helper_ieee_input_s(CPUAlphaState *env, uint64_t val) | |
143 | { | |
144 | if (unlikely(2 * val - 1 < 0x1fffffffffffffull) | |
145 | && !env->fp_status.flush_inputs_to_zero) { | |
146 | arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); | |
147 | } | |
148 | } | |
4a58aedf RH |
149 | |
150 | /* S floating (single) */ | |
151 | ||
152 | /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ | |
153 | static inline uint64_t float32_to_s_int(uint32_t fi) | |
154 | { | |
155 | uint32_t frac = fi & 0x7fffff; | |
156 | uint32_t sign = fi >> 31; | |
157 | uint32_t exp_msb = (fi >> 30) & 1; | |
158 | uint32_t exp_low = (fi >> 23) & 0x7f; | |
159 | uint32_t exp; | |
160 | ||
161 | exp = (exp_msb << 10) | exp_low; | |
162 | if (exp_msb) { | |
163 | if (exp_low == 0x7f) { | |
164 | exp = 0x7ff; | |
165 | } | |
166 | } else { | |
167 | if (exp_low != 0x00) { | |
168 | exp |= 0x380; | |
169 | } | |
170 | } | |
171 | ||
172 | return (((uint64_t)sign << 63) | |
173 | | ((uint64_t)exp << 52) | |
174 | | ((uint64_t)frac << 29)); | |
175 | } | |
176 | ||
177 | static inline uint64_t float32_to_s(float32 fa) | |
178 | { | |
179 | CPU_FloatU a; | |
180 | a.f = fa; | |
181 | return float32_to_s_int(a.l); | |
182 | } | |
183 | ||
184 | static inline uint32_t s_to_float32_int(uint64_t a) | |
185 | { | |
186 | return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); | |
187 | } | |
188 | ||
189 | static inline float32 s_to_float32(uint64_t a) | |
190 | { | |
191 | CPU_FloatU r; | |
192 | r.l = s_to_float32_int(a); | |
193 | return r.f; | |
194 | } | |
195 | ||
196 | uint32_t helper_s_to_memory(uint64_t a) | |
197 | { | |
198 | return s_to_float32_int(a); | |
199 | } | |
200 | ||
201 | uint64_t helper_memory_to_s(uint32_t a) | |
202 | { | |
203 | return float32_to_s_int(a); | |
204 | } | |
205 | ||
206 | uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) | |
207 | { | |
208 | float32 fa, fb, fr; | |
209 | ||
210 | fa = s_to_float32(a); | |
211 | fb = s_to_float32(b); | |
212 | fr = float32_add(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
213 | env->error_code = soft_to_fpcr_exc(env); |
214 | ||
4a58aedf RH |
215 | return float32_to_s(fr); |
216 | } | |
217 | ||
218 | uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) | |
219 | { | |
220 | float32 fa, fb, fr; | |
221 | ||
222 | fa = s_to_float32(a); | |
223 | fb = s_to_float32(b); | |
224 | fr = float32_sub(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
225 | env->error_code = soft_to_fpcr_exc(env); |
226 | ||
4a58aedf RH |
227 | return float32_to_s(fr); |
228 | } | |
229 | ||
230 | uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) | |
231 | { | |
232 | float32 fa, fb, fr; | |
233 | ||
234 | fa = s_to_float32(a); | |
235 | fb = s_to_float32(b); | |
236 | fr = float32_mul(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
237 | env->error_code = soft_to_fpcr_exc(env); |
238 | ||
4a58aedf RH |
239 | return float32_to_s(fr); |
240 | } | |
241 | ||
242 | uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) | |
243 | { | |
244 | float32 fa, fb, fr; | |
245 | ||
246 | fa = s_to_float32(a); | |
247 | fb = s_to_float32(b); | |
248 | fr = float32_div(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
249 | env->error_code = soft_to_fpcr_exc(env); |
250 | ||
4a58aedf RH |
251 | return float32_to_s(fr); |
252 | } | |
253 | ||
254 | uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) | |
255 | { | |
256 | float32 fa, fr; | |
257 | ||
258 | fa = s_to_float32(a); | |
259 | fr = float32_sqrt(fa, &FP_STATUS); | |
f3d3aad4 RH |
260 | env->error_code = soft_to_fpcr_exc(env); |
261 | ||
4a58aedf RH |
262 | return float32_to_s(fr); |
263 | } | |
264 | ||
265 | ||
266 | /* T floating (double) */ | |
267 | static inline float64 t_to_float64(uint64_t a) | |
268 | { | |
269 | /* Memory format is the same as float64 */ | |
270 | CPU_DoubleU r; | |
271 | r.ll = a; | |
272 | return r.d; | |
273 | } | |
274 | ||
275 | static inline uint64_t float64_to_t(float64 fa) | |
276 | { | |
277 | /* Memory format is the same as float64 */ | |
278 | CPU_DoubleU r; | |
279 | r.d = fa; | |
280 | return r.ll; | |
281 | } | |
282 | ||
283 | uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
284 | { | |
285 | float64 fa, fb, fr; | |
286 | ||
287 | fa = t_to_float64(a); | |
288 | fb = t_to_float64(b); | |
289 | fr = float64_add(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
290 | env->error_code = soft_to_fpcr_exc(env); |
291 | ||
4a58aedf RH |
292 | return float64_to_t(fr); |
293 | } | |
294 | ||
295 | uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
296 | { | |
297 | float64 fa, fb, fr; | |
298 | ||
299 | fa = t_to_float64(a); | |
300 | fb = t_to_float64(b); | |
301 | fr = float64_sub(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
302 | env->error_code = soft_to_fpcr_exc(env); |
303 | ||
4a58aedf RH |
304 | return float64_to_t(fr); |
305 | } | |
306 | ||
307 | uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) | |
308 | { | |
309 | float64 fa, fb, fr; | |
310 | ||
311 | fa = t_to_float64(a); | |
312 | fb = t_to_float64(b); | |
313 | fr = float64_mul(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
314 | env->error_code = soft_to_fpcr_exc(env); |
315 | ||
4a58aedf RH |
316 | return float64_to_t(fr); |
317 | } | |
318 | ||
319 | uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
320 | { | |
321 | float64 fa, fb, fr; | |
322 | ||
323 | fa = t_to_float64(a); | |
324 | fb = t_to_float64(b); | |
325 | fr = float64_div(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
326 | env->error_code = soft_to_fpcr_exc(env); |
327 | ||
4a58aedf RH |
328 | return float64_to_t(fr); |
329 | } | |
330 | ||
331 | uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) | |
332 | { | |
333 | float64 fa, fr; | |
334 | ||
335 | fa = t_to_float64(a); | |
336 | fr = float64_sqrt(fa, &FP_STATUS); | |
f3d3aad4 RH |
337 | env->error_code = soft_to_fpcr_exc(env); |
338 | ||
4a58aedf RH |
339 | return float64_to_t(fr); |
340 | } | |
341 | ||
342 | /* Comparisons */ | |
343 | uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) | |
344 | { | |
345 | float64 fa, fb; | |
f3d3aad4 | 346 | uint64_t ret = 0; |
4a58aedf RH |
347 | |
348 | fa = t_to_float64(a); | |
349 | fb = t_to_float64(b); | |
350 | ||
351 | if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 352 | ret = 0x4000000000000000ULL; |
4a58aedf | 353 | } |
f3d3aad4 RH |
354 | env->error_code = soft_to_fpcr_exc(env); |
355 | ||
356 | return ret; | |
4a58aedf RH |
357 | } |
358 | ||
359 | uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) | |
360 | { | |
361 | float64 fa, fb; | |
f3d3aad4 | 362 | uint64_t ret = 0; |
4a58aedf RH |
363 | |
364 | fa = t_to_float64(a); | |
365 | fb = t_to_float64(b); | |
366 | ||
367 | if (float64_eq_quiet(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 368 | ret = 0x4000000000000000ULL; |
4a58aedf | 369 | } |
f3d3aad4 RH |
370 | env->error_code = soft_to_fpcr_exc(env); |
371 | ||
372 | return ret; | |
4a58aedf RH |
373 | } |
374 | ||
375 | uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) | |
376 | { | |
377 | float64 fa, fb; | |
f3d3aad4 | 378 | uint64_t ret = 0; |
4a58aedf RH |
379 | |
380 | fa = t_to_float64(a); | |
381 | fb = t_to_float64(b); | |
382 | ||
383 | if (float64_le(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 384 | ret = 0x4000000000000000ULL; |
4a58aedf | 385 | } |
f3d3aad4 RH |
386 | env->error_code = soft_to_fpcr_exc(env); |
387 | ||
388 | return ret; | |
4a58aedf RH |
389 | } |
390 | ||
391 | uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
392 | { | |
393 | float64 fa, fb; | |
f3d3aad4 | 394 | uint64_t ret = 0; |
4a58aedf RH |
395 | |
396 | fa = t_to_float64(a); | |
397 | fb = t_to_float64(b); | |
398 | ||
399 | if (float64_lt(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 400 | ret = 0x4000000000000000ULL; |
4a58aedf | 401 | } |
f3d3aad4 RH |
402 | env->error_code = soft_to_fpcr_exc(env); |
403 | ||
404 | return ret; | |
4a58aedf RH |
405 | } |
406 | ||
4a58aedf RH |
407 | /* Floating point format conversion */ |
408 | uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) | |
409 | { | |
410 | float64 fa; | |
411 | float32 fr; | |
412 | ||
413 | fa = t_to_float64(a); | |
414 | fr = float64_to_float32(fa, &FP_STATUS); | |
f3d3aad4 RH |
415 | env->error_code = soft_to_fpcr_exc(env); |
416 | ||
4a58aedf RH |
417 | return float32_to_s(fr); |
418 | } | |
419 | ||
420 | uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) | |
421 | { | |
422 | float32 fa; | |
423 | float64 fr; | |
424 | ||
425 | fa = s_to_float32(a); | |
426 | fr = float32_to_float64(fa, &FP_STATUS); | |
f3d3aad4 RH |
427 | env->error_code = soft_to_fpcr_exc(env); |
428 | ||
4a58aedf RH |
429 | return float64_to_t(fr); |
430 | } | |
431 | ||
432 | uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) | |
433 | { | |
434 | float32 fr = int64_to_float32(a, &FP_STATUS); | |
f3d3aad4 RH |
435 | env->error_code = soft_to_fpcr_exc(env); |
436 | ||
4a58aedf RH |
437 | return float32_to_s(fr); |
438 | } | |
439 | ||
440 | /* Implement float64 to uint64 conversion without saturation -- we must | |
441 | supply the truncated result. This behaviour is used by the compiler | |
c24a8a0b | 442 | to get unsigned conversion for free with the same instruction. */ |
4a58aedf | 443 | |
c24a8a0b | 444 | static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) |
4a58aedf RH |
445 | { |
446 | uint64_t frac, ret = 0; | |
447 | uint32_t exp, sign, exc = 0; | |
448 | int shift; | |
449 | ||
450 | sign = (a >> 63); | |
451 | exp = (uint32_t)(a >> 52) & 0x7ff; | |
452 | frac = a & 0xfffffffffffffull; | |
453 | ||
454 | if (exp == 0) { | |
4ed069ab | 455 | if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { |
4a58aedf RH |
456 | goto do_underflow; |
457 | } | |
458 | } else if (exp == 0x7ff) { | |
7b4dde83 | 459 | exc = FPCR_INV; |
4a58aedf RH |
460 | } else { |
461 | /* Restore implicit bit. */ | |
462 | frac |= 0x10000000000000ull; | |
463 | ||
464 | shift = exp - 1023 - 52; | |
465 | if (shift >= 0) { | |
466 | /* In this case the number is so large that we must shift | |
467 | the fraction left. There is no rounding to do. */ | |
7f2e4002 | 468 | if (shift < 64) { |
4a58aedf | 469 | ret = frac << shift; |
7f2e4002 RH |
470 | } |
471 | /* Check for overflow. Note the special case of -0x1p63. */ | |
472 | if (shift >= 11 && a != 0xC3E0000000000000ull) { | |
473 | exc = FPCR_IOV | FPCR_INE; | |
4a58aedf RH |
474 | } |
475 | } else { | |
476 | uint64_t round; | |
477 | ||
478 | /* In this case the number is smaller than the fraction as | |
479 | represented by the 52 bit number. Here we must think | |
480 | about rounding the result. Handle this by shifting the | |
481 | fractional part of the number into the high bits of ROUND. | |
482 | This will let us efficiently handle round-to-nearest. */ | |
483 | shift = -shift; | |
484 | if (shift < 63) { | |
485 | ret = frac >> shift; | |
486 | round = frac << (64 - shift); | |
487 | } else { | |
488 | /* The exponent is so small we shift out everything. | |
489 | Leave a sticky bit for proper rounding below. */ | |
490 | do_underflow: | |
491 | round = 1; | |
492 | } | |
493 | ||
494 | if (round) { | |
c24a8a0b | 495 | exc = FPCR_INE; |
4a58aedf RH |
496 | switch (roundmode) { |
497 | case float_round_nearest_even: | |
498 | if (round == (1ull << 63)) { | |
499 | /* Fraction is exactly 0.5; round to even. */ | |
500 | ret += (ret & 1); | |
501 | } else if (round > (1ull << 63)) { | |
502 | ret += 1; | |
503 | } | |
504 | break; | |
505 | case float_round_to_zero: | |
506 | break; | |
507 | case float_round_up: | |
508 | ret += 1 - sign; | |
509 | break; | |
510 | case float_round_down: | |
511 | ret += sign; | |
512 | break; | |
513 | } | |
514 | } | |
515 | } | |
516 | if (sign) { | |
517 | ret = -ret; | |
518 | } | |
519 | } | |
f3d3aad4 | 520 | env->error_code = exc; |
4a58aedf RH |
521 | |
522 | return ret; | |
523 | } | |
524 | ||
525 | uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) | |
526 | { | |
c24a8a0b | 527 | return do_cvttq(env, a, FP_STATUS.float_rounding_mode); |
4a58aedf RH |
528 | } |
529 | ||
530 | uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) | |
531 | { | |
c24a8a0b | 532 | return do_cvttq(env, a, float_round_to_zero); |
4a58aedf RH |
533 | } |
534 | ||
535 | uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) | |
536 | { | |
537 | float64 fr = int64_to_float64(a, &FP_STATUS); | |
f3d3aad4 | 538 | env->error_code = soft_to_fpcr_exc(env); |
4a58aedf RH |
539 | return float64_to_t(fr); |
540 | } | |
541 | ||
57a808b6 | 542 | uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val) |
e8d8fef4 | 543 | { |
57a808b6 | 544 | uint32_t exc = 0; |
e8d8fef4 | 545 | if (val != (int32_t)val) { |
57a808b6 | 546 | exc = FPCR_IOV | FPCR_INE; |
e8d8fef4 | 547 | } |
57a808b6 RH |
548 | env->error_code = exc; |
549 | ||
550 | return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29); | |
e8d8fef4 | 551 | } |