|
|
1.1 root 1: /*
2: * FPU op helpers
3: *
4: * Copyright (c) 2003-2005 Fabrice Bellard
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"
21: #include "helper.h"
22:
23: #define QT0 (env->qt0)
24: #define QT1 (env->qt1)
25:
26: static void check_ieee_exceptions(CPUState *env)
27: {
28: target_ulong status;
29:
30: status = get_float_exception_flags(&env->fp_status);
31: if (status) {
32: /* Copy IEEE 754 flags into FSR */
33: if (status & float_flag_invalid) {
34: env->fsr |= FSR_NVC;
35: }
36: if (status & float_flag_overflow) {
37: env->fsr |= FSR_OFC;
38: }
39: if (status & float_flag_underflow) {
40: env->fsr |= FSR_UFC;
41: }
42: if (status & float_flag_divbyzero) {
43: env->fsr |= FSR_DZC;
44: }
45: if (status & float_flag_inexact) {
46: env->fsr |= FSR_NXC;
47: }
48:
49: if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
50: /* Unmasked exception, generate a trap */
51: env->fsr |= FSR_FTT_IEEE_EXCP;
52: helper_raise_exception(env, TT_FP_EXCP);
53: } else {
54: /* Accumulate exceptions */
55: env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
56: }
57: }
58: }
59:
60: static inline void clear_float_exceptions(CPUState *env)
61: {
62: set_float_exception_flags(0, &env->fp_status);
63: }
64:
65: #define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
66:
67: #define F_BINOP(name) \
68: float32 helper_f ## name ## s (CPUState *env, float32 src1, \
69: float32 src2) \
70: { \
71: float32 ret; \
72: clear_float_exceptions(env); \
73: ret = float32_ ## name (src1, src2, &env->fp_status); \
74: check_ieee_exceptions(env); \
75: return ret; \
76: } \
77: float64 helper_f ## name ## d (CPUState * env, float64 src1,\
78: float64 src2) \
79: { \
80: float64 ret; \
81: clear_float_exceptions(env); \
82: ret = float64_ ## name (src1, src2, &env->fp_status); \
83: check_ieee_exceptions(env); \
84: return ret; \
85: } \
86: F_HELPER(name, q) \
87: { \
88: clear_float_exceptions(env); \
89: QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
90: check_ieee_exceptions(env); \
91: }
92:
93: F_BINOP(add);
94: F_BINOP(sub);
95: F_BINOP(mul);
96: F_BINOP(div);
97: #undef F_BINOP
98:
99: float64 helper_fsmuld(CPUState *env, float32 src1, float32 src2)
100: {
101: float64 ret;
102: clear_float_exceptions(env);
103: ret = float64_mul(float32_to_float64(src1, &env->fp_status),
104: float32_to_float64(src2, &env->fp_status),
105: &env->fp_status);
106: check_ieee_exceptions(env);
107: return ret;
108: }
109:
110: void helper_fdmulq(CPUState *env, float64 src1, float64 src2)
111: {
112: clear_float_exceptions(env);
113: QT0 = float128_mul(float64_to_float128(src1, &env->fp_status),
114: float64_to_float128(src2, &env->fp_status),
115: &env->fp_status);
116: check_ieee_exceptions(env);
117: }
118:
119: float32 helper_fnegs(float32 src)
120: {
121: return float32_chs(src);
122: }
123:
124: #ifdef TARGET_SPARC64
125: float64 helper_fnegd(float64 src)
126: {
127: return float64_chs(src);
128: }
129:
130: F_HELPER(neg, q)
131: {
132: QT0 = float128_chs(QT1);
133: }
134: #endif
135:
136: /* Integer to float conversion. */
137: float32 helper_fitos(CPUState *env, int32_t src)
138: {
139: /* Inexact error possible converting int to float. */
140: float32 ret;
141: clear_float_exceptions(env);
142: ret = int32_to_float32(src, &env->fp_status);
143: check_ieee_exceptions(env);
144: return ret;
145: }
146:
147: float64 helper_fitod(CPUState *env, int32_t src)
148: {
149: /* No possible exceptions converting int to double. */
150: return int32_to_float64(src, &env->fp_status);
151: }
152:
153: void helper_fitoq(CPUState *env, int32_t src)
154: {
155: /* No possible exceptions converting int to long double. */
156: QT0 = int32_to_float128(src, &env->fp_status);
157: }
158:
159: #ifdef TARGET_SPARC64
160: float32 helper_fxtos(CPUState *env, int64_t src)
161: {
162: float32 ret;
163: clear_float_exceptions(env);
164: ret = int64_to_float32(src, &env->fp_status);
165: check_ieee_exceptions(env);
166: return ret;
167: }
168:
169: float64 helper_fxtod(CPUState *env, int64_t src)
170: {
171: float64 ret;
172: clear_float_exceptions(env);
173: ret = int64_to_float64(src, &env->fp_status);
174: check_ieee_exceptions(env);
175: return ret;
176: }
177:
178: void helper_fxtoq(CPUState *env, int64_t src)
179: {
180: /* No possible exceptions converting long long to long double. */
181: QT0 = int64_to_float128(src, &env->fp_status);
182: }
183: #endif
184: #undef F_HELPER
185:
186: /* floating point conversion */
187: float32 helper_fdtos(CPUState *env, float64 src)
188: {
189: float32 ret;
190: clear_float_exceptions(env);
191: ret = float64_to_float32(src, &env->fp_status);
192: check_ieee_exceptions(env);
193: return ret;
194: }
195:
196: float64 helper_fstod(CPUState *env, float32 src)
197: {
198: float64 ret;
199: clear_float_exceptions(env);
200: ret = float32_to_float64(src, &env->fp_status);
201: check_ieee_exceptions(env);
202: return ret;
203: }
204:
205: float32 helper_fqtos(CPUState *env)
206: {
207: float32 ret;
208: clear_float_exceptions(env);
209: ret = float128_to_float32(QT1, &env->fp_status);
210: check_ieee_exceptions(env);
211: return ret;
212: }
213:
214: void helper_fstoq(CPUState *env, float32 src)
215: {
216: clear_float_exceptions(env);
217: QT0 = float32_to_float128(src, &env->fp_status);
218: check_ieee_exceptions(env);
219: }
220:
221: float64 helper_fqtod(CPUState *env)
222: {
223: float64 ret;
224: clear_float_exceptions(env);
225: ret = float128_to_float64(QT1, &env->fp_status);
226: check_ieee_exceptions(env);
227: return ret;
228: }
229:
230: void helper_fdtoq(CPUState *env, float64 src)
231: {
232: clear_float_exceptions(env);
233: QT0 = float64_to_float128(src, &env->fp_status);
234: check_ieee_exceptions(env);
235: }
236:
237: /* Float to integer conversion. */
238: int32_t helper_fstoi(CPUState *env, float32 src)
239: {
240: int32_t ret;
241: clear_float_exceptions(env);
242: ret = float32_to_int32_round_to_zero(src, &env->fp_status);
243: check_ieee_exceptions(env);
244: return ret;
245: }
246:
247: int32_t helper_fdtoi(CPUState *env, float64 src)
248: {
249: int32_t ret;
250: clear_float_exceptions(env);
251: ret = float64_to_int32_round_to_zero(src, &env->fp_status);
252: check_ieee_exceptions(env);
253: return ret;
254: }
255:
256: int32_t helper_fqtoi(CPUState *env)
257: {
258: int32_t ret;
259: clear_float_exceptions(env);
260: ret = float128_to_int32_round_to_zero(QT1, &env->fp_status);
261: check_ieee_exceptions(env);
262: return ret;
263: }
264:
265: #ifdef TARGET_SPARC64
266: int64_t helper_fstox(CPUState *env, float32 src)
267: {
268: int64_t ret;
269: clear_float_exceptions(env);
270: ret = float32_to_int64_round_to_zero(src, &env->fp_status);
271: check_ieee_exceptions(env);
272: return ret;
273: }
274:
275: int64_t helper_fdtox(CPUState *env, float64 src)
276: {
277: int64_t ret;
278: clear_float_exceptions(env);
279: ret = float64_to_int64_round_to_zero(src, &env->fp_status);
280: check_ieee_exceptions(env);
281: return ret;
282: }
283:
284: int64_t helper_fqtox(CPUState *env)
285: {
286: int64_t ret;
287: clear_float_exceptions(env);
288: ret = float128_to_int64_round_to_zero(QT1, &env->fp_status);
289: check_ieee_exceptions(env);
290: return ret;
291: }
292: #endif
293:
294: float32 helper_fabss(float32 src)
295: {
296: return float32_abs(src);
297: }
298:
299: #ifdef TARGET_SPARC64
300: float64 helper_fabsd(float64 src)
301: {
302: return float64_abs(src);
303: }
304:
305: void helper_fabsq(CPUState *env)
306: {
307: QT0 = float128_abs(QT1);
308: }
309: #endif
310:
311: float32 helper_fsqrts(CPUState *env, float32 src)
312: {
313: float32 ret;
314: clear_float_exceptions(env);
315: ret = float32_sqrt(src, &env->fp_status);
316: check_ieee_exceptions(env);
317: return ret;
318: }
319:
320: float64 helper_fsqrtd(CPUState *env, float64 src)
321: {
322: float64 ret;
323: clear_float_exceptions(env);
324: ret = float64_sqrt(src, &env->fp_status);
325: check_ieee_exceptions(env);
326: return ret;
327: }
328:
329: void helper_fsqrtq(CPUState *env)
330: {
331: clear_float_exceptions(env);
332: QT0 = float128_sqrt(QT1, &env->fp_status);
333: check_ieee_exceptions(env);
334: }
335:
336: #define GEN_FCMP(name, size, reg1, reg2, FS, E) \
337: void glue(helper_, name) (CPUState *env) \
338: { \
339: env->fsr &= FSR_FTT_NMASK; \
340: if (E && (glue(size, _is_any_nan)(reg1) || \
341: glue(size, _is_any_nan)(reg2)) && \
342: (env->fsr & FSR_NVM)) { \
343: env->fsr |= FSR_NVC; \
344: env->fsr |= FSR_FTT_IEEE_EXCP; \
345: helper_raise_exception(env, TT_FP_EXCP); \
346: } \
347: switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
348: case float_relation_unordered: \
349: if ((env->fsr & FSR_NVM)) { \
350: env->fsr |= FSR_NVC; \
351: env->fsr |= FSR_FTT_IEEE_EXCP; \
352: helper_raise_exception(env, TT_FP_EXCP); \
353: } else { \
354: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
355: env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
356: env->fsr |= FSR_NVA; \
357: } \
358: break; \
359: case float_relation_less: \
360: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
361: env->fsr |= FSR_FCC0 << FS; \
362: break; \
363: case float_relation_greater: \
364: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
365: env->fsr |= FSR_FCC1 << FS; \
366: break; \
367: default: \
368: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
369: break; \
370: } \
371: }
372: #define GEN_FCMP_T(name, size, FS, E) \
373: void glue(helper_, name)(CPUState *env, size src1, size src2) \
374: { \
375: env->fsr &= FSR_FTT_NMASK; \
376: if (E && (glue(size, _is_any_nan)(src1) || \
377: glue(size, _is_any_nan)(src2)) && \
378: (env->fsr & FSR_NVM)) { \
379: env->fsr |= FSR_NVC; \
380: env->fsr |= FSR_FTT_IEEE_EXCP; \
381: helper_raise_exception(env, TT_FP_EXCP); \
382: } \
383: switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
384: case float_relation_unordered: \
385: if ((env->fsr & FSR_NVM)) { \
386: env->fsr |= FSR_NVC; \
387: env->fsr |= FSR_FTT_IEEE_EXCP; \
388: helper_raise_exception(env, TT_FP_EXCP); \
389: } else { \
390: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
391: env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
392: env->fsr |= FSR_NVA; \
393: } \
394: break; \
395: case float_relation_less: \
396: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
397: env->fsr |= FSR_FCC0 << FS; \
398: break; \
399: case float_relation_greater: \
400: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
401: env->fsr |= FSR_FCC1 << FS; \
402: break; \
403: default: \
404: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
405: break; \
406: } \
407: }
408:
409: GEN_FCMP_T(fcmps, float32, 0, 0);
410: GEN_FCMP_T(fcmpd, float64, 0, 0);
411:
412: GEN_FCMP_T(fcmpes, float32, 0, 1);
413: GEN_FCMP_T(fcmped, float64, 0, 1);
414:
415: GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
416: GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
417:
418: #ifdef TARGET_SPARC64
419: GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
420: GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
421: GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
422:
423: GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
424: GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
425: GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
426:
427: GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
428: GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
429: GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
430:
431: GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
432: GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
433: GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
434:
435: GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
436: GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
437: GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
438:
439: GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
440: GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
441: GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
442: #endif
443: #undef GEN_FCMP_T
444: #undef GEN_FCMP
445:
446: static inline void set_fsr(CPUState *env)
447: {
448: int rnd_mode;
449:
450: switch (env->fsr & FSR_RD_MASK) {
451: case FSR_RD_NEAREST:
452: rnd_mode = float_round_nearest_even;
453: break;
454: default:
455: case FSR_RD_ZERO:
456: rnd_mode = float_round_to_zero;
457: break;
458: case FSR_RD_POS:
459: rnd_mode = float_round_up;
460: break;
461: case FSR_RD_NEG:
462: rnd_mode = float_round_down;
463: break;
464: }
465: set_float_rounding_mode(rnd_mode, &env->fp_status);
466: }
467:
468: void helper_ldfsr(CPUState *env, uint32_t new_fsr)
469: {
470: env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
471: set_fsr(env);
472: }
473:
474: #ifdef TARGET_SPARC64
475: void helper_ldxfsr(CPUState *env, uint64_t new_fsr)
476: {
477: env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
478: set_fsr(env);
479: }
480: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.