|
|
1.1 root 1: /* $Id: sparc-fpu.c,v 1.3 2007/01/14 16:32:16 fredette Exp $ */
2:
3: /* ic/sparc/sparc-fpu.c - SPARC floating-point unit implementation */
4:
5: /*
6: * Copyright (c) 2005 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: sparc-fpu.c,v 1.3 2007/01/14 16:32:16 fredette Exp $");
38:
39: /* includes: */
40: #include "sparc-impl.h"
41:
42: /* macros: */
43:
44: /* these invoke an IEEE 754 operation: */
45: #define _TME_SPARC_FPU_BEGIN \
46: do { \
47: /* at this point, the only possible trap must be \
48: TME_SPARC_FSR_FTT_IEEE754_exception, so we can \
49: clear CEXC: */ \
50: ic->tme_sparc_fpu_fsr &= ~TME_SPARC_FSR_CEXC; \
51: } while (/* CONSTCOND */ 0)
52: #define _TME_SPARC_FPU_OP(func, x) \
53: do { \
54: if (__tme_predict_false((func) == NULL)) { \
55: if (ic->tme_sparc_fpu_incomplete_abort) { \
56: abort(); \
57: } \
58: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_unimplemented_FPop);\
59: } \
60: _TME_SPARC_FPU_BEGIN; \
61: (*(func)) x; \
62: } while (/* CONSTCOND */ 0)
63: #define _TME_SPARC_FPU_OP_MONADIC(func, src, dst) \
64: _TME_SPARC_FPU_OP(ic->tme_sparc_fpu_ieee754_ops->func, (&ic->tme_sparc_fpu_ieee754_ctl, src, dst))
65: #define _TME_SPARC_FPU_OP_DYADIC(func, src0, src1, dst) \
66: _TME_SPARC_FPU_OP(ic->tme_sparc_fpu_ieee754_ops->func, (&ic->tme_sparc_fpu_ieee754_ctl, src0, src1, dst))
67:
68: /* globals: */
69:
70: /* the floating-point condition codes->conditions mapping. this
71: array is indexed by the fcc value: */
72: const tme_uint8_t _tme_sparc_conds_fcc[4] = {
73:
74: /* E: */
75: (0),
76:
77: /* L: */
78: (TME_BIT(1) /* fbne */
79: | TME_BIT(2) /* fblg */
80: | TME_BIT(3) /* fbul */
81: | TME_BIT(4)), /* fbl */
82:
83: /* G: */
84: (TME_BIT(1) /* fbne */
85: | TME_BIT(2) /* fblg */
86: | TME_BIT(5) /* fbug */
87: | TME_BIT(6)), /* fbg */
88:
89: /* U: */
90: (TME_BIT(1) /* fbne */
91: | TME_BIT(3) /* fbul */
92: | TME_BIT(5) /* fbug */
93: | TME_BIT(7)) /* fbu */
94: };
95:
96: /* this resets the FPU: */
97: void
98: tme_sparc_fpu_reset(struct tme_sparc *ic)
99: {
100: unsigned int fp_i;
101:
102: /* put nonsignaling NaNs in the floating-point data registers: */
103: for (fp_i = 0;
104: fp_i < TME_ARRAY_ELS(ic->tme_sparc_fpu_fpregs);
105: fp_i++) {
106: ic->tme_sparc_fpu_fpregs[fp_i].tme_float_format = TME_FLOAT_FORMAT_IEEE754_SINGLE;
107: ic->tme_sparc_fpu_fpregs[fp_i].tme_float_value_ieee754_single = ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_default_nan_single;
108: ic->tme_sparc_fpu_fpreg_sizes[fp_i] = sizeof(tme_uint32_t) / sizeof(tme_uint32_t);
109: }
110:
111: /* zero the FSR, except for the version field: */
112: ic->tme_sparc_fpu_fsr &= TME_SPARC_FSR_VER;
113:
114: /* use the strict compliance operations: */
115: ic->tme_sparc_fpu_ieee754_ops = ic->tme_sparc_fpu_ieee754_ops_strict;
116:
117: /* the FPU is in execute mode: */
118: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXECUTE;
119: }
120:
121: /* this enables or disables FPU strict compliance: */
122: void
123: tme_sparc_fpu_strict(struct tme_sparc_bus_connection *conn_sparc, unsigned int strict)
124: {
125: struct tme_sparc *ic;
126:
127: /* recover our IC: */
128: ic = conn_sparc->tme_sparc_bus_connection.tme_bus_connection.tme_connection_element->tme_element_private;
129:
130: ic->tme_sparc_fpu_ieee754_ops
131: = (strict
132: ? ic->tme_sparc_fpu_ieee754_ops_strict
133: : ic->tme_sparc_fpu_ieee754_ops_user);
134: }
135:
136: /* this handles a sparc FPU exception: */
137: void
138: tme_sparc_fpu_exception(struct tme_sparc *ic, tme_uint32_t ftt)
139: {
140:
141: /* the FPU must be in execute mode, and the FQ must be empty: */
142: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXECUTE
143: && (ic->tme_sparc_fpu_fsr & TME_SPARC_FSR_QNE) == 0);
144:
145: /* put the trapping instruction in the FQ: */
146: ic->tme_sparc_fpu_fq[0].tme_sparc_trapqueue_address
147: = (TME_SPARC_VERSION(ic) < 9
148: ? ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC)
149: : ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC));
150: ic->tme_sparc_fpu_fq[0].tme_sparc_trapqueue_insn
151: = TME_SPARC_INSN;
152:
153: /* set QNE and the FTT field in the FSR: */
154: ic->tme_sparc_fpu_fsr
155: = ((ic->tme_sparc_fpu_fsr & ~TME_SPARC_FSR_FTT)
156: | TME_SPARC_FSR_QNE
157: | ftt);
158:
159: /* enter pending exception mode and redispatch to run the next
160: instruction: */
161: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXCEPTION_PENDING;
162: tme_sparc_redispatch(ic);
163: }
164:
165: /* this checks for a pending sparc FPU trap: */
166: void
167: tme_sparc_fpu_exception_check(struct tme_sparc *ic)
168: {
169:
170: /* if the FPU is in pending exception mode: */
171: if (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXCEPTION_PENDING) {
172:
173: /* enter exception mode and start IU trap processing: */
174: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXCEPTION;
175: TME_SPARC_INSN_TRAP(TME_SPARC_TRAP_fp_exception);
176: }
177:
178: /* otherwise, the FPU must be in exception mode: */
179: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXCEPTION);
180:
181: /* "If an FPop, floating-point load instruction, or floating-point
182: branch instruction is executed while the FPU is in fp_exception
183: state, the FPU returns to fp_exception_pending state and also
184: sets the FSR ftt field to sequence_error. The instruction that
185: caused the sequence_error is not entered into the FQ." */
186: /* XXX FIXME - apparently such an instruction does not trap
187: immediately, but since it can't run either, I interpret this to
188: mean that the instruction is simply ignored: */
189: ic->tme_sparc_fpu_fsr = (ic->tme_sparc_fpu_fsr & ~TME_SPARC_FSR_FTT) | TME_SPARC_FSR_FTT_sequence_error;
190: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXCEPTION;
191: tme_sparc_redispatch(ic);
192: }
193:
194: /* the IEEE 754 exception handler: */
195: static void
196: _tme_sparc_fpu_exception_ieee754(struct tme_ieee754_ctl *ctl, tme_int8_t exception_ieee754)
197: {
198: struct tme_sparc *ic;
199: tme_uint32_t exception_cexc;
200:
201: /* map the IEEE754 exception(s) to CEXC bit(s): */
202: exception_cexc = 0;
203: #define _TME_SPARC_FPU_EXCEPTION_MAP(e_ieee754, e_sparc) \
204: if (((tme_uint8_t) exception_ieee754) & (e_ieee754)) \
205: exception_cexc |= (e_sparc)
206: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_INVALID, TME_SPARC_FSR_CEXC_NVC);
207: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_DIVBYZERO, TME_SPARC_FSR_CEXC_DZC);
208: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_OVERFLOW, TME_SPARC_FSR_CEXC_OFC);
209: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_UNDERFLOW, TME_SPARC_FSR_CEXC_UFC);
210: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_INEXACT, TME_SPARC_FSR_CEXC_NXC);
211: if (exception_cexc == 0) {
212: abort();
213: }
214:
215: /* recover our data structure: */
216: ic = (struct tme_sparc *) ctl->tme_ieee754_ctl_private;
217:
218: /* set the CEXC field in the FSR. "When a floating-point trap
219: occurs ... The value of aexc is unchanged", which is why we don't
220: update it until we're sure a trap is not going to occur: */
221: TME_FIELD_MASK_DEPOSITU(ic->tme_sparc_fpu_fsr, TME_SPARC_FSR_CEXC, exception_cexc);
222:
223: /* if any of the new exceptions are unmasked, take the exception: */
224: if (TME_FIELD_MASK_EXTRACTU(ic->tme_sparc_fpu_fsr, TME_SPARC_FSR_TEM) & exception_cexc) {
225:
226: /* unlock any lock: */
227: if (ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock != NULL) {
228: (*ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock)();
229: ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock = NULL;
230: }
231:
232: /* take the exception: */
233: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_IEEE754_exception);
234: }
235:
236: /* now that we're sure a trap isn't going to happen, update the AEXC
237: field in the FSR: */
238: ic->tme_sparc_fpu_fsr |= exception_cexc * (TME_SPARC_FSR_AEXC / TME_SPARC_FSR_CEXC);
239: }
240:
241: TME_SPARC_FORMAT3(tme_sparc32_stdfq, tme_uint32_t)
242: {
243: TME_SPARC_INSN_PRIV;
244: TME_SPARC_INSN_FPU_STORE(sizeof(tme_uint32_t) * 2);
245:
246: /* "An attempt to execute STDFQ on an implementation without a
247: floating-point queue causes an fp_exception trap with FSR.ftt set
248: to 4 (sequence_error). On an implementation with a floating-point
249: queue, an attempt to execute STDFQ when the FQ is empty (FSR.qne
250: = 0) should cause an fp_exception trap with FSR.ftt set to 4
251: (sequence_error)." */
252: if ((ic->tme_sparc_fpu_fsr & TME_SPARC_FSR_QNE) == 0) {
253: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXECUTE);
254: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_sequence_error);
255: }
256: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXCEPTION);
257:
258: /* store the FQ entry: */
259: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX + 0)
260: = ic->tme_sparc_fpu_fq[0].tme_sparc_trapqueue_address;
261: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX + 1)
262: = ic->tme_sparc_fpu_fq[0].tme_sparc_trapqueue_insn;
263: tme_sparc32_std(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX));
264:
265: /* clear the QNE bit and return to execute mode: */
266: ic->tme_sparc_fpu_fsr &= ~TME_SPARC_FSR_QNE;
267: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXECUTE;
268:
269: TME_SPARC_INSN_OK;
270: }
271:
272: /* this checks that the given floating point register number is aligned
273: for a certain format: */
274: int
275: tme_sparc_fpu_fpreg_aligned(struct tme_sparc *ic,
276: unsigned int fpreg_number,
277: unsigned int fpreg_format)
278: {
279:
280: /* if the register number is misaligned for the format: */
281: #if (TME_IEEE754_FPREG_FORMAT_SINGLE != 1 || TME_IEEE754_FPREG_FORMAT_DOUBLE != 2 || TME_IEEE754_FPREG_FORMAT_QUAD != 4)
282: #error "bad TME_IEEE754_FPREG_FORMAT_ macros"
283: #endif
284: if (fpreg_number & ((fpreg_format & ~TME_IEEE754_FPREG_FORMAT_BUILTIN) - 1)) {
285: if (!(ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_OK_REG_MISALIGNED)) {
286: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_invalid_fp_register);
287: }
288: return (FALSE);
289: }
290: return (TRUE);
291: }
292:
293: /* this forces the given floating point register to assume the given
294: format (width, really) in the register file: */
295: void
296: tme_sparc_fpu_fpreg_format(struct tme_sparc *ic,
297: unsigned int fpreg_number,
298: unsigned int fpreg_format)
299: {
300:
301: /* make sure the register is aligned: */
302: if (!tme_sparc_fpu_fpreg_aligned(ic, fpreg_number, fpreg_format)) {
303: abort();
304: }
305:
306: /* make sure the register is in the given format: */
307: tme_ieee754_fpreg_format(ic->tme_sparc_fpu_fpregs,
308: ic->tme_sparc_fpu_fpreg_sizes,
309: fpreg_number,
310: (fpreg_format
311: | TME_IEEE754_FPREG_FORMAT_ENDIAN_BIG));
312: }
313:
314: /* this forces the given floating point register to assume the given
315: format (width, really) in the register file, then returns a pointer
316: to the register: */
317: static const struct tme_float *
318: tme_sparc_fpu_fpreg_read(struct tme_sparc *ic,
319: tme_uint32_t fpreg_number_mask,
320: unsigned int fpreg_format)
321: {
322: unsigned int fpreg_number;
323:
324: /* extract the register number: */
325: fpreg_number = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, fpreg_number_mask);
326:
327: /* make sure the register is in the given format: */
328: tme_sparc_fpu_fpreg_format(ic, fpreg_number, fpreg_format);
329:
330: /* return a pointer to the register: */
331: return (&ic->tme_sparc_fpu_fpregs[fpreg_number]);
332: }
333:
334: /* include the automatically generated code: */
335: #include "sparc-fpu-auto.c"
336:
337: /* this checks for an FPU argument: */
338: int
339: tme_sparc_fpu_new(struct tme_sparc *ic, const char * const *args, int *_arg_i, int *_usage, char **_output)
340: {
341: int arg_i;
342: const char *compliance;
343: int complete;
344: struct tme_ieee754_ctl *ctl;
345: tme_uint32_t ver;
346:
347: /* get the argument index: */
348: arg_i = *_arg_i;
349:
350: /* if this is not an FPU type, this is not an sparc FPU argument: */
351: if (!TME_ARG_IS(args[arg_i + 0], "fpu-type")) {
352: return (FALSE);
353: }
354:
355: /* you can't specify more than one FPU type: */
356: if ((ic->tme_sparc_fpu_fsr & TME_SPARC_FSR_VER) != TME_SPARC_FSR_VER_missing) {
357: tme_output_append_error(_output,
358: "%s fpu-type %s",
359: _("multiple"),
360: _("unexpected"));
361: *_usage = TRUE;
362: return (TRUE);
363: }
364:
365: /* get the FPU type: */
366: if (args[arg_i + 1] == NULL) {
367: *_usage = TRUE;
368: return (TRUE);
369: }
370: ver = (*ic->_tme_sparc_fpu_ver)(ic, args[arg_i + 1], NULL);
371: if (ver == TME_SPARC_FSR_VER_missing) {
372: tme_output_append_error(_output,
373: "%s fpu-type %s",
374: _("bad"),
375: args[arg_i + 1]);
376: *_usage = TRUE;
377: return (TRUE);
378: }
379: ic->tme_sparc_fpu_fsr = (ic->tme_sparc_fpu_fsr & ~TME_SPARC_FSR_VER) | ver;
380: arg_i += 2;
381:
382: /* the next argument must be a compliance level: */
383: compliance = args[arg_i + 1];
384: if (!TME_ARG_IS(args[arg_i + 0], "fpu-compliance")
385: || compliance == NULL) {
386: *_usage = TRUE;
387: return (TRUE);
388: }
389: ic->tme_sparc_fpu_ieee754_ops_user = tme_ieee754_ops_lookup(compliance);
390: if (ic->tme_sparc_fpu_ieee754_ops_user == NULL) {
391: tme_output_append_error(_output,
392: "%s fpu-compliance %s",
393: _("bad"),
394: compliance);
395: *_usage = TRUE;
396: return (TRUE);
397: }
398: arg_i += 2;
399:
400: /* see if the operations for this compliance level are complete: */
401: #define _TME_SPARC_FPU_OP_CHECK(func) (ic->tme_sparc_fpu_ieee754_ops_user->func != NULL)
402: complete
403: = (_TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_add)
404: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_div)
405: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_from_double)
406: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_mul)
407: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_mul)
408: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sub)
409: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sub)
410: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sub)
411: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_add)
412: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_div)
413: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_single)
414: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_single)
415: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_single)
416: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_mul)
417: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sub)
418: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sub)
419: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sub)
420: && ((ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_NO_FSQRT) != 0
421: || (_TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sqrt)
422: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sqrt)
423: && ((ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_NO_QUAD) != 0
424: || _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sqrt))))
425: && ((ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_NO_QUAD) != 0
426: || (_TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_quad)
427: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_add)
428: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_div)
429: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_double)
430: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_double)
431: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_double)
432: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_single)
433: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_mul)
434: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_mul)
435: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sub)
436: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sub)
437: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sub)
438: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_from_quad))));
439: #undef _TME_SPARC_FPU_OP_CHECK
440:
441: /* if the next argument is an incomplete disposition: */
442: if (TME_ARG_IS(args[arg_i + 0], "fpu-incomplete")) {
443:
444: if (TME_ARG_IS(args[arg_i + 1], "abort")) {
445: ic->tme_sparc_fpu_incomplete_abort = TRUE;
446: }
447: else if (TME_ARG_IS(args[arg_i + 1], "trap")) {
448: ic->tme_sparc_fpu_incomplete_abort = FALSE;
449: }
450: else {
451: tme_output_append_error(_output,
452: "%s fpu-incomplete %s",
453: _("bad"),
454: args[arg_i + 1]);
455: *_usage = TRUE;
456: return (TRUE);
457: }
458: arg_i += 2;
459: }
460:
461: /* otherwise, no incomplete disposition is given. if this
462: compliance is incomplete: */
463: else if (!complete) {
464: tme_output_append_error(_output,
465: "%s %s %s fpu-incomplete",
466: _("compliance"),
467: compliance,
468: _("is incomplete, needs"));
469: *_usage = TRUE;
470: return (TRUE);
471: }
472:
473: /* initialize the IEEE 754 control: */
474: ctl = &ic->tme_sparc_fpu_ieee754_ctl;
475:
476: /* a private data structure: */
477: ctl->tme_ieee754_ctl_private = ic;
478:
479: /* the underflow tininess-detection mode. Appendix N.5 of my V8
480: manual says that this is the mode used on the SPARC: */
481: ctl->tme_ieee754_ctl_detect_tininess = TME_IEEE754_CTL_DETECT_TININESS_BEFORE_ROUNDING;
482:
483: /* the exception function: */
484: ctl->tme_ieee754_ctl_exception = _tme_sparc_fpu_exception_ieee754;
485:
486: /* we do check whether or not a value is a sNaN when converting it
487: from one precision to another: */
488: ctl->tme_ieee754_ctl_check_snan_on_conversion = TRUE;
489:
490: /* the default generated NaN patterns: */
491: ctl->tme_ieee754_ctl_default_nan_single = 0x7fffffff;
492: ctl->tme_ieee754_ctl_default_nan_double.tme_value64_uint32_hi = 0x7fffffff;
493: ctl->tme_ieee754_ctl_default_nan_double.tme_value64_uint32_lo = 0xffffffff;
494: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_hi = 0x7fffffff;
495: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_lo = 0xffffffff;
496: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_lo.tme_value64_uint32_hi = 0xffffffff;
497: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_lo.tme_value64_uint32_lo = 0xffffffff;
498:
499: /* NaN tests: */
500: ctl->tme_ieee754_ctl_is_snan_single = _tme_sparc_fpu_is_snan_single;
501: ctl->tme_ieee754_ctl_is_snan_double = _tme_sparc_fpu_is_snan_double;
502: ctl->tme_ieee754_ctl_is_snan_quad = _tme_sparc_fpu_is_snan_quad;
503:
504: /* NaN canonicalization: */
505: ctl->tme_ieee754_ctl_nan_single_to_common = tme_ieee754_default_nan_single_to_common;
506: ctl->tme_ieee754_ctl_nan_common_to_single = tme_ieee754_default_nan_common_to_single;
507: ctl->tme_ieee754_ctl_nan_double_to_common = tme_ieee754_default_nan_double_to_common;
508: ctl->tme_ieee754_ctl_nan_common_to_double = tme_ieee754_default_nan_common_to_double;
509: ctl->tme_ieee754_ctl_nan_quad_to_common = tme_ieee754_default_nan_quad_to_common;
510: ctl->tme_ieee754_ctl_nan_common_to_quad = tme_ieee754_default_nan_common_to_quad;
511:
512: /* NaN propagation: */
513: ctl->tme_ieee754_ctl_nan_from_nans_single = _tme_sparc_fpu_nan_from_nans_single;
514: ctl->tme_ieee754_ctl_nan_from_nans_double = _tme_sparc_fpu_nan_from_nans_double;
515: ctl->tme_ieee754_ctl_nan_from_nans_quad = _tme_sparc_fpu_nan_from_nans_quad;
516:
517: /* look up the strict compliance operations: */
518: ic->tme_sparc_fpu_ieee754_ops_strict = tme_ieee754_ops_lookup("strict");
519: assert (ic->tme_sparc_fpu_ieee754_ops_strict != NULL);
520:
521: /* done: */
522: *_arg_i = arg_i;
523: return (TRUE);
524: }
525:
526: /* this returns the FPU usage: */
527: void
528: tme_sparc_fpu_usage(struct tme_sparc *ic, char **_output)
529: {
530: tme_output_append_error(_output,
531: "[ fpu-type ");
532: (*ic->_tme_sparc_fpu_ver)(ic, NULL, _output);
533: tme_output_append_error(_output,
534: " ] fpu-compliance %s [ fpu-incomplete { abort | trap } ] ]",
535: tme_ieee754_compliance_options);
536: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.