|
|
1.1.1.2 ! root 1: /* $Id: sparc-fpu.c,v 1.5 2010/06/05 16:08:44 fredette Exp $ */ 1.1 root 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> 1.1.1.2 ! root 37: _TME_RCSID("$Id: sparc-fpu.c,v 1.5 2010/06/05 16:08:44 fredette Exp $"); 1.1 root 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: */ 1.1.1.2 ! root 137: static void 1.1 root 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; 1.1.1.2 ! root 175: TME_SPARC_INSN_TRAP(TME_SPARC_VERSION(ic) < 9 ! 176: ? TME_SPARC32_TRAP_fp_exception ! 177: : (ic->tme_sparc_fpu_fsr & TME_SPARC_FSR_FTT) != TME_SPARC_FSR_FTT_IEEE754_exception ! 178: ? TME_SPARC64_TRAP_fp_exception_other ! 179: : TME_SPARC64_TRAP_fp_exception_ieee_754); 1.1 root 180: } 181: 182: /* otherwise, the FPU must be in exception mode: */ 183: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXCEPTION); 184: 185: /* "If an FPop, floating-point load instruction, or floating-point 186: branch instruction is executed while the FPU is in fp_exception 187: state, the FPU returns to fp_exception_pending state and also 188: sets the FSR ftt field to sequence_error. The instruction that 189: caused the sequence_error is not entered into the FQ." */ 190: /* XXX FIXME - apparently such an instruction does not trap 191: immediately, but since it can't run either, I interpret this to 192: mean that the instruction is simply ignored: */ 193: ic->tme_sparc_fpu_fsr = (ic->tme_sparc_fpu_fsr & ~TME_SPARC_FSR_FTT) | TME_SPARC_FSR_FTT_sequence_error; 194: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXCEPTION; 195: tme_sparc_redispatch(ic); 196: } 197: 198: /* the IEEE 754 exception handler: */ 199: static void 200: _tme_sparc_fpu_exception_ieee754(struct tme_ieee754_ctl *ctl, tme_int8_t exception_ieee754) 201: { 202: struct tme_sparc *ic; 203: tme_uint32_t exception_cexc; 204: 205: /* map the IEEE754 exception(s) to CEXC bit(s): */ 206: exception_cexc = 0; 207: #define _TME_SPARC_FPU_EXCEPTION_MAP(e_ieee754, e_sparc) \ 208: if (((tme_uint8_t) exception_ieee754) & (e_ieee754)) \ 209: exception_cexc |= (e_sparc) 210: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_INVALID, TME_SPARC_FSR_CEXC_NVC); 211: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_DIVBYZERO, TME_SPARC_FSR_CEXC_DZC); 212: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_OVERFLOW, TME_SPARC_FSR_CEXC_OFC); 213: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_UNDERFLOW, TME_SPARC_FSR_CEXC_UFC); 214: _TME_SPARC_FPU_EXCEPTION_MAP(TME_FLOAT_EXCEPTION_INEXACT, TME_SPARC_FSR_CEXC_NXC); 215: if (exception_cexc == 0) { 216: abort(); 217: } 218: 219: /* recover our data structure: */ 220: ic = (struct tme_sparc *) ctl->tme_ieee754_ctl_private; 221: 222: /* set the CEXC field in the FSR. "When a floating-point trap 223: occurs ... The value of aexc is unchanged", which is why we don't 224: update it until we're sure a trap is not going to occur: */ 225: TME_FIELD_MASK_DEPOSITU(ic->tme_sparc_fpu_fsr, TME_SPARC_FSR_CEXC, exception_cexc); 226: 227: /* if any of the new exceptions are unmasked, take the exception: */ 228: if (TME_FIELD_MASK_EXTRACTU(ic->tme_sparc_fpu_fsr, TME_SPARC_FSR_TEM) & exception_cexc) { 229: 230: /* unlock any lock: */ 231: if (ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock != NULL) { 232: (*ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock)(); 233: ic->tme_sparc_fpu_ieee754_ctl.tme_ieee754_ctl_lock_unlock = NULL; 234: } 235: 236: /* take the exception: */ 237: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_IEEE754_exception); 238: } 239: 240: /* now that we're sure a trap isn't going to happen, update the AEXC 241: field in the FSR: */ 242: ic->tme_sparc_fpu_fsr |= exception_cexc * (TME_SPARC_FSR_AEXC / TME_SPARC_FSR_CEXC); 243: } 244: 245: TME_SPARC_FORMAT3(tme_sparc32_stdfq, tme_uint32_t) 246: { 247: TME_SPARC_INSN_PRIV; 1.1.1.2 ! root 248: TME_SPARC_INSN_FPU_ENABLED; 1.1 root 249: 250: /* "An attempt to execute STDFQ on an implementation without a 251: floating-point queue causes an fp_exception trap with FSR.ftt set 252: to 4 (sequence_error). On an implementation with a floating-point 253: queue, an attempt to execute STDFQ when the FQ is empty (FSR.qne 254: = 0) should cause an fp_exception trap with FSR.ftt set to 4 255: (sequence_error)." */ 256: if ((ic->tme_sparc_fpu_fsr & TME_SPARC_FSR_QNE) == 0) { 257: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXECUTE); 258: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_sequence_error); 259: } 260: assert (ic->tme_sparc_fpu_mode == TME_SPARC_FPU_MODE_EXCEPTION); 261: 262: /* store the FQ entry: */ 263: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX + 0) 264: = ic->tme_sparc_fpu_fq[0].tme_sparc_trapqueue_address; 265: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX + 1) 266: = ic->tme_sparc_fpu_fq[0].tme_sparc_trapqueue_insn; 267: tme_sparc32_std(ic, _rs1, _rs2, &ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_FPX)); 268: 269: /* clear the QNE bit and return to execute mode: */ 270: ic->tme_sparc_fpu_fsr &= ~TME_SPARC_FSR_QNE; 271: ic->tme_sparc_fpu_mode = TME_SPARC_FPU_MODE_EXECUTE; 272: 273: TME_SPARC_INSN_OK; 274: } 275: 1.1.1.2 ! root 276: /* this decodes a floating point register number and checks that it is ! 277: aligned for a certain format: */ ! 278: unsigned int ! 279: tme_sparc_fpu_fpreg_decode(struct tme_sparc *ic, ! 280: unsigned int fpreg_number_encoded, ! 281: unsigned int fpreg_format) 1.1 root 282: { 1.1.1.2 ! root 283: unsigned int fpreg_number; ! 284: ! 285: /* assume that the register number and its encoding are the same: */ ! 286: fpreg_number = fpreg_number_encoded; ! 287: ! 288: /* if this is a double or quad-precision register number encoding: */ ! 289: #if (TME_IEEE754_FPREG_FORMAT_SINGLE != 1 || TME_IEEE754_FPREG_FORMAT_DOUBLE != 2 || TME_IEEE754_FPREG_FORMAT_QUAD != 4) ! 290: #error "bad TME_IEEE754_FPREG_FORMAT_ macros" ! 291: #endif ! 292: if (fpreg_format ! 293: & (TME_IEEE754_FPREG_FORMAT_DOUBLE ! 294: | TME_IEEE754_FPREG_FORMAT_QUAD)) { ! 295: ! 296: /* on a v9 CPU, bit zero of a double- or quad-precision register ! 297: number encoding is bit five of the register number: */ ! 298: if (TME_SPARC_VERSION(ic) >= 9) { ! 299: fpreg_number ! 300: = ((fpreg_number_encoded ! 301: + (fpreg_number_encoded * 32)) ! 302: & (64 - 2)); ! 303: } ! 304: } 1.1 root 305: 306: /* if the register number is misaligned for the format: */ 307: #if (TME_IEEE754_FPREG_FORMAT_SINGLE != 1 || TME_IEEE754_FPREG_FORMAT_DOUBLE != 2 || TME_IEEE754_FPREG_FORMAT_QUAD != 4) 308: #error "bad TME_IEEE754_FPREG_FORMAT_ macros" 309: #endif 1.1.1.2 ! root 310: if (__tme_predict_false(fpreg_number ! 311: & ((fpreg_format ! 312: & (TME_IEEE754_FPREG_FORMAT_SINGLE ! 313: | TME_IEEE754_FPREG_FORMAT_DOUBLE ! 314: | TME_IEEE754_FPREG_FORMAT_QUAD)) ! 315: - 1))) { ! 316: ! 317: /* if this CPU allows misaligned register numbers: */ ! 318: if (ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_OK_REG_MISALIGNED) { ! 319: ! 320: /* force the register number to be aligned: */ ! 321: fpreg_number ! 322: &= (0 - (fpreg_format ! 323: & (TME_IEEE754_FPREG_FORMAT_SINGLE ! 324: | TME_IEEE754_FPREG_FORMAT_DOUBLE ! 325: | TME_IEEE754_FPREG_FORMAT_QUAD))); ! 326: } ! 327: ! 328: /* otherwise, this CPU does not allow misaligned register numbers: */ ! 329: else { 1.1 root 330: tme_sparc_fpu_exception(ic, TME_SPARC_FSR_FTT_invalid_fp_register); 331: } 332: } 1.1.1.2 ! root 333: ! 334: return (fpreg_number); 1.1 root 335: } 336: 337: /* this forces the given floating point register to assume the given 338: format (width, really) in the register file: */ 339: void 340: tme_sparc_fpu_fpreg_format(struct tme_sparc *ic, 341: unsigned int fpreg_number, 342: unsigned int fpreg_format) 343: { 344: 345: /* make sure the register is in the given format: */ 346: tme_ieee754_fpreg_format(ic->tme_sparc_fpu_fpregs, 347: ic->tme_sparc_fpu_fpreg_sizes, 348: fpreg_number, 349: (fpreg_format 350: | TME_IEEE754_FPREG_FORMAT_ENDIAN_BIG)); 351: } 352: 353: /* this forces the given floating point register to assume the given 354: format (width, really) in the register file, then returns a pointer 355: to the register: */ 356: static const struct tme_float * 357: tme_sparc_fpu_fpreg_read(struct tme_sparc *ic, 358: tme_uint32_t fpreg_number_mask, 359: unsigned int fpreg_format) 360: { 1.1.1.2 ! root 361: tme_uint32_t fpreg_number_encoded; 1.1 root 362: unsigned int fpreg_number; 363: 1.1.1.2 ! root 364: /* extract and decode the register number: */ ! 365: fpreg_number_encoded = TME_SPARC_INSN; ! 366: #if TME_SPARC_FORMAT3_MASK_RD < TME_SPARC_FORMAT3_MASK_RS1 || TME_SPARC_FORMAT3_MASK_RS1 < TME_SPARC_FORMAT3_MASK_RS2 ! 367: #error "TME_SPARC_FORMAT3_MASK_RS values changed" ! 368: #endif ! 369: assert (fpreg_number_mask == TME_SPARC_FORMAT3_MASK_RD ! 370: || fpreg_number_mask == TME_SPARC_FORMAT3_MASK_RS1 ! 371: || fpreg_number_mask == TME_SPARC_FORMAT3_MASK_RS2); ! 372: if (fpreg_number_mask == TME_SPARC_FORMAT3_MASK_RD) { ! 373: fpreg_number_encoded /= (TME_SPARC_FORMAT3_MASK_RD / TME_SPARC_FORMAT3_MASK_RS2); ! 374: } ! 375: if (fpreg_number_mask == TME_SPARC_FORMAT3_MASK_RS1) { ! 376: fpreg_number_encoded /= (TME_SPARC_FORMAT3_MASK_RS1 / TME_SPARC_FORMAT3_MASK_RS2); ! 377: } ! 378: fpreg_number_encoded = TME_FIELD_MASK_EXTRACTU(fpreg_number_encoded, TME_SPARC_FORMAT3_MASK_RS2); ! 379: fpreg_number ! 380: = tme_sparc_fpu_fpreg_decode(ic, ! 381: fpreg_number_encoded, ! 382: fpreg_format); 1.1 root 383: 384: /* make sure the register is in the given format: */ 385: tme_sparc_fpu_fpreg_format(ic, fpreg_number, fpreg_format); 386: 387: /* return a pointer to the register: */ 388: return (&ic->tme_sparc_fpu_fpregs[fpreg_number]); 389: } 390: 391: /* include the automatically generated code: */ 392: #include "sparc-fpu-auto.c" 1.1.1.2 ! root 393: #ifdef TME_HAVE_INT64_T ! 394: #include "sparc-vis-auto.c" ! 395: #endif /* TME_HAVE_INT64_T */ 1.1 root 396: 397: /* this checks for an FPU argument: */ 398: int 399: tme_sparc_fpu_new(struct tme_sparc *ic, const char * const *args, int *_arg_i, int *_usage, char **_output) 400: { 401: int arg_i; 402: const char *compliance; 403: int complete; 404: struct tme_ieee754_ctl *ctl; 405: tme_uint32_t ver; 406: 407: /* get the argument index: */ 408: arg_i = *_arg_i; 409: 410: /* if this is not an FPU type, this is not an sparc FPU argument: */ 411: if (!TME_ARG_IS(args[arg_i + 0], "fpu-type")) { 412: return (FALSE); 413: } 414: 415: /* you can't specify more than one FPU type: */ 416: if ((ic->tme_sparc_fpu_fsr & TME_SPARC_FSR_VER) != TME_SPARC_FSR_VER_missing) { 417: tme_output_append_error(_output, 418: "%s fpu-type %s", 419: _("multiple"), 420: _("unexpected")); 421: *_usage = TRUE; 422: return (TRUE); 423: } 424: 425: /* get the FPU type: */ 426: if (args[arg_i + 1] == NULL) { 427: *_usage = TRUE; 428: return (TRUE); 429: } 430: ver = (*ic->_tme_sparc_fpu_ver)(ic, args[arg_i + 1], NULL); 431: if (ver == TME_SPARC_FSR_VER_missing) { 432: tme_output_append_error(_output, 433: "%s fpu-type %s", 434: _("bad"), 435: args[arg_i + 1]); 436: *_usage = TRUE; 437: return (TRUE); 438: } 439: ic->tme_sparc_fpu_fsr = (ic->tme_sparc_fpu_fsr & ~TME_SPARC_FSR_VER) | ver; 440: arg_i += 2; 441: 442: /* the next argument must be a compliance level: */ 443: compliance = args[arg_i + 1]; 444: if (!TME_ARG_IS(args[arg_i + 0], "fpu-compliance") 445: || compliance == NULL) { 446: *_usage = TRUE; 447: return (TRUE); 448: } 449: ic->tme_sparc_fpu_ieee754_ops_user = tme_ieee754_ops_lookup(compliance); 450: if (ic->tme_sparc_fpu_ieee754_ops_user == NULL) { 451: tme_output_append_error(_output, 452: "%s fpu-compliance %s", 453: _("bad"), 454: compliance); 455: *_usage = TRUE; 456: return (TRUE); 457: } 458: arg_i += 2; 459: 460: /* see if the operations for this compliance level are complete: */ 461: #define _TME_SPARC_FPU_OP_CHECK(func) (ic->tme_sparc_fpu_ieee754_ops_user->func != NULL) 462: complete 463: = (_TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_add) 464: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_div) 465: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_from_double) 466: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_mul) 467: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_mul) 468: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sub) 469: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sub) 470: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sub) 471: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_add) 472: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_div) 473: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_single) 474: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_single) 475: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_single) 476: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_mul) 477: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sub) 478: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sub) 479: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sub) 480: && ((ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_NO_FSQRT) != 0 481: || (_TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_sqrt) 482: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_sqrt) 483: && ((ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_NO_QUAD) != 0 484: || _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sqrt)))) 485: && ((ic->tme_sparc_fpu_flags & TME_SPARC_FPU_FLAG_NO_QUAD) != 0 486: || (_TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_double_from_quad) 487: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_add) 488: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_div) 489: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_double) 490: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_double) 491: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_double) 492: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_from_single) 493: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_mul) 494: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_mul) 495: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sub) 496: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sub) 497: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_quad_sub) 498: && _TME_SPARC_FPU_OP_CHECK(tme_ieee754_ops_single_from_quad)))); 499: #undef _TME_SPARC_FPU_OP_CHECK 500: 501: /* if the next argument is an incomplete disposition: */ 502: if (TME_ARG_IS(args[arg_i + 0], "fpu-incomplete")) { 503: 504: if (TME_ARG_IS(args[arg_i + 1], "abort")) { 505: ic->tme_sparc_fpu_incomplete_abort = TRUE; 506: } 507: else if (TME_ARG_IS(args[arg_i + 1], "trap")) { 508: ic->tme_sparc_fpu_incomplete_abort = FALSE; 509: } 510: else { 511: tme_output_append_error(_output, 512: "%s fpu-incomplete %s", 513: _("bad"), 514: args[arg_i + 1]); 515: *_usage = TRUE; 516: return (TRUE); 517: } 518: arg_i += 2; 519: } 520: 521: /* otherwise, no incomplete disposition is given. if this 522: compliance is incomplete: */ 523: else if (!complete) { 524: tme_output_append_error(_output, 525: "%s %s %s fpu-incomplete", 526: _("compliance"), 527: compliance, 528: _("is incomplete, needs")); 529: *_usage = TRUE; 530: return (TRUE); 531: } 532: 533: /* initialize the IEEE 754 control: */ 534: ctl = &ic->tme_sparc_fpu_ieee754_ctl; 535: 536: /* a private data structure: */ 537: ctl->tme_ieee754_ctl_private = ic; 538: 539: /* the underflow tininess-detection mode. Appendix N.5 of my V8 540: manual says that this is the mode used on the SPARC: */ 541: ctl->tme_ieee754_ctl_detect_tininess = TME_IEEE754_CTL_DETECT_TININESS_BEFORE_ROUNDING; 542: 543: /* the exception function: */ 544: ctl->tme_ieee754_ctl_exception = _tme_sparc_fpu_exception_ieee754; 545: 546: /* we do check whether or not a value is a sNaN when converting it 547: from one precision to another: */ 548: ctl->tme_ieee754_ctl_check_snan_on_conversion = TRUE; 549: 550: /* the default generated NaN patterns: */ 551: ctl->tme_ieee754_ctl_default_nan_single = 0x7fffffff; 552: ctl->tme_ieee754_ctl_default_nan_double.tme_value64_uint32_hi = 0x7fffffff; 553: ctl->tme_ieee754_ctl_default_nan_double.tme_value64_uint32_lo = 0xffffffff; 554: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_hi = 0x7fffffff; 555: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_hi.tme_value64_uint32_lo = 0xffffffff; 556: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_lo.tme_value64_uint32_hi = 0xffffffff; 557: ctl->tme_ieee754_ctl_default_nan_quad.tme_float_ieee754_quad_lo.tme_value64_uint32_lo = 0xffffffff; 558: 559: /* NaN tests: */ 560: ctl->tme_ieee754_ctl_is_snan_single = _tme_sparc_fpu_is_snan_single; 561: ctl->tme_ieee754_ctl_is_snan_double = _tme_sparc_fpu_is_snan_double; 562: ctl->tme_ieee754_ctl_is_snan_quad = _tme_sparc_fpu_is_snan_quad; 563: 564: /* NaN canonicalization: */ 565: ctl->tme_ieee754_ctl_nan_single_to_common = tme_ieee754_default_nan_single_to_common; 566: ctl->tme_ieee754_ctl_nan_common_to_single = tme_ieee754_default_nan_common_to_single; 567: ctl->tme_ieee754_ctl_nan_double_to_common = tme_ieee754_default_nan_double_to_common; 568: ctl->tme_ieee754_ctl_nan_common_to_double = tme_ieee754_default_nan_common_to_double; 569: ctl->tme_ieee754_ctl_nan_quad_to_common = tme_ieee754_default_nan_quad_to_common; 570: ctl->tme_ieee754_ctl_nan_common_to_quad = tme_ieee754_default_nan_common_to_quad; 571: 572: /* NaN propagation: */ 573: ctl->tme_ieee754_ctl_nan_from_nans_single = _tme_sparc_fpu_nan_from_nans_single; 574: ctl->tme_ieee754_ctl_nan_from_nans_double = _tme_sparc_fpu_nan_from_nans_double; 575: ctl->tme_ieee754_ctl_nan_from_nans_quad = _tme_sparc_fpu_nan_from_nans_quad; 576: 577: /* look up the strict compliance operations: */ 578: ic->tme_sparc_fpu_ieee754_ops_strict = tme_ieee754_ops_lookup("strict"); 579: assert (ic->tme_sparc_fpu_ieee754_ops_strict != NULL); 580: 581: /* done: */ 582: *_arg_i = arg_i; 583: return (TRUE); 584: } 585: 586: /* this returns the FPU usage: */ 587: void 588: tme_sparc_fpu_usage(struct tme_sparc *ic, char **_output) 589: { 590: tme_output_append_error(_output, 591: "[ fpu-type "); 592: (*ic->_tme_sparc_fpu_ver)(ic, NULL, _output); 593: tme_output_append_error(_output, 594: " ] fpu-compliance %s [ fpu-incomplete { abort | trap } ] ]", 595: tme_ieee754_compliance_options); 596: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.