Annotation of tme/ic/sparc/sparc-fpu.c, revision 1.1.1.2

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.