[BACK]Return to fp_complete.c CVS log [TXT][DIR] Up to [local] / sys / arch / alpha / alpha

Annotation of sys/arch/alpha/alpha/fp_complete.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: fp_complete.c,v 1.7 2006/02/25 03:58:56 deraadt Exp $ */
        !             2: /*     $NetBSD: fp_complete.c,v 1.5 2002/01/18 22:15:56 ross Exp $     */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2001 Ross Harvey
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by the NetBSD
        !            19:  *     Foundation, Inc. and its contributors.
        !            20:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            21:  *    contributors may be used to endorse or promote products derived
        !            22:  *    from this software without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            25:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            26:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            27:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            28:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            29:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            30:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            31:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            32:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            33:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            34:  * POSSIBILITY OF SUCH DAMAGE.
        !            35:  */
        !            36:
        !            37: #include <sys/param.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/proc.h>
        !            40:
        !            41: #include <machine/cpu.h>
        !            42: #include <machine/fpu.h>
        !            43: #include <machine/reg.h>
        !            44: #include <machine/cpu.h>
        !            45: #include <alpha/alpha/db_instruction.h>
        !            46:
        !            47: #include <lib/libkern/softfloat.h>
        !            48:
        !            49: #define        TSWINSIZE 4     /* size of trap shadow window in u_int32_t units */
        !            50:
        !            51: /*     Set Name                Opcodes                 AARM C.* Symbols  */
        !            52:
        !            53: #define        CPUREG_CLASS            (0xfUL << 0x10)         /* INT[ALSM]      */
        !            54: #define        FPUREG_CLASS            (0xfUL << 0x14)         /* ITFP, FLT[ILV] */
        !            55: #define        CHECKFUNCTIONCODE       (1UL << 0x18)           /* MISC           */
        !            56: #define        TRAPSHADOWBOUNDARY      (1UL << 0x00 |          /* PAL            */\
        !            57:                                 1UL << 0x19 |          /* \PAL\          */\
        !            58:                                 1UL << 0x1a |          /* JSR            */\
        !            59:                                 1UL << 0x1b |          /* \PAL\          */\
        !            60:                                 1UL << 0x1d |          /* \PAL\          */\
        !            61:                                 1UL << 0x1e |          /* \PAL\          */\
        !            62:                                 1UL << 0x1f |          /* \PAL\          */\
        !            63:                                 0xffffUL << 0x30 |     /* branch ops     */\
        !            64:                                 CHECKFUNCTIONCODE)
        !            65:
        !            66: #define        MAKE_FLOATXX(width, expwidth, sign, exp, msb, rest_of_frac) \
        !            67:        (u_int ## width ## _t)(sign) << ((width) - 1)                   |\
        !            68:        (u_int ## width ## _t)(exp)  << ((width) - 1 - (expwidth))      |\
        !            69:        (u_int ## width ## _t)(msb)  << ((width) - 1 - (expwidth) - 1)  |\
        !            70:        (u_int ## width ## _t)(rest_of_frac)
        !            71:
        !            72: #define        FLOAT32QNAN MAKE_FLOATXX(32, 8, 0, 0xff, 1, 0)
        !            73: #define        FLOAT64QNAN MAKE_FLOATXX(64, 11, 0, 0x7ff, 1, 0)
        !            74:
        !            75: #define IS_SUBNORMAL(v)        ((v)->exp == 0 && (v)->frac != 0)
        !            76:
        !            77: #define        PREFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_DMZ  \
        !            78:                                     && IS_SUBNORMAL(v))                \
        !            79:                                         (v)->frac = 0; else
        !            80:
        !            81: #define        POSTFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_UMZ \
        !            82:                                      && IS_SUBNORMAL(v))               \
        !            83:                                          (v)->frac = 0; else
        !            84:
        !            85:        /* Alpha returns 2.0 for true, all zeroes for false. */
        !            86:
        !            87: #define CMP_RESULT(flag) ((flag) ? 4UL << 60 : 0L)
        !            88:
        !            89:        /* Move bits from sw fp_c to hw fpcr. */
        !            90:
        !            91: #define        CRBLIT(sw, hw, m, offs) (((sw) & ~(m)) | ((hw) >> (offs) & (m)))
        !            92:
        !            93: /*
        !            94:  * Temporary trap shadow instrumentation. The [un]resolved counters
        !            95:  * could be kept permanently, as they provide information on whether
        !            96:  * user code has met AARM trap shadow generation requirements.
        !            97:  */
        !            98:
        !            99: struct alpha_shadow {
        !           100:        u_int64_t resolved;     /* cases trigger pc found */
        !           101:        u_int64_t unresolved;   /* cases it wasn't, code problems? */
        !           102:        u_int64_t scans;                /* trap shadow scans */
        !           103:        u_int64_t len;          /* number of instructions examined */
        !           104:        u_int64_t uop;          /* bit mask of unexpected opcodes */
        !           105:        u_int64_t sqrts;        /* ev6+ square root single count */
        !           106:        u_int64_t sqrtt;        /* ev6+ square root double count */
        !           107:        u_int32_t ufunc;        /* bit mask of unexpected functions */
        !           108:        u_int32_t max;          /* max trap shadow scan */
        !           109:        u_int32_t nilswop;      /* unexpected op codes */
        !           110:        u_int32_t nilswfunc;    /* unexpected function codes */
        !           111:        u_int32_t nilanyop;     /* this "cannot happen" */
        !           112:        u_int32_t vax;          /* sigs from vax fp opcodes */
        !           113: } alpha_shadow, alpha_shadow_zero;
        !           114:
        !           115: static float64 float64_unk(float64, float64);
        !           116: static float64 compare_un(float64, float64);
        !           117: static float64 compare_eq(float64, float64);
        !           118: static float64 compare_lt(float64, float64);
        !           119: static float64 compare_le(float64, float64);
        !           120: static void cvt_qs_ts_st_gf_qf(u_int32_t, struct proc *);
        !           121: static void cvt_gd(u_int32_t, struct proc *);
        !           122: static void cvt_qt_dg_qg(u_int32_t, struct proc *);
        !           123: static void cvt_tq_gq(u_int32_t, struct proc *);
        !           124:
        !           125: static float32 (*swfp_s[])(float32, float32) = {
        !           126:        float32_add, float32_sub, float32_mul, float32_div,
        !           127: };
        !           128:
        !           129: static float64 (*swfp_t[])(float64, float64) = {
        !           130:        float64_add, float64_sub, float64_mul, float64_div,
        !           131:        compare_un,    compare_eq,    compare_lt,    compare_le,
        !           132:        float64_unk, float64_unk, float64_unk, float64_unk
        !           133: };
        !           134:
        !           135: static void (*swfp_cvt[])(u_int32_t, struct proc *) = {
        !           136:        cvt_qs_ts_st_gf_qf, cvt_gd, cvt_qt_dg_qg, cvt_tq_gq
        !           137: };
        !           138:
        !           139: static void
        !           140: this_cannot_happen(int what_cannot_happen, int64_t bits)
        !           141: {
        !           142:        static int total;
        !           143:        alpha_instruction inst;
        !           144:        static u_int64_t reported;
        !           145:
        !           146:        inst.bits = bits;
        !           147:        ++alpha_shadow.nilswfunc;
        !           148:        if (bits != -1)
        !           149:                alpha_shadow.uop |= 1UL << inst.generic_format.opcode;
        !           150:        if (1UL << what_cannot_happen & reported)
        !           151:                return;
        !           152:        reported |= 1UL << what_cannot_happen;
        !           153:        if (total >= 1000)
        !           154:                return; /* right now, this return "cannot happen" */
        !           155:        ++total;
        !           156:        if (bits)
        !           157:                printf("FP instruction %x\n", (unsigned int)bits);
        !           158:        printf("FP event %d/%lx/%lx\n", what_cannot_happen, reported,
        !           159:            alpha_shadow.uop);
        !           160: }
        !           161:
        !           162: static __inline void
        !           163: sts(unsigned int rn, s_float *v, struct proc *p)
        !           164: {
        !           165:        alpha_sts(rn, v);
        !           166:        PREFILTER_SUBNORMAL(p, v);
        !           167: }
        !           168:
        !           169: static __inline void
        !           170: stt(unsigned int rn, t_float *v, struct proc *p)
        !           171: {
        !           172:        alpha_stt(rn, v);
        !           173:        PREFILTER_SUBNORMAL(p, v);
        !           174: }
        !           175:
        !           176: static __inline void
        !           177: lds(unsigned int rn, s_float *v, struct proc *p)
        !           178: {
        !           179:        POSTFILTER_SUBNORMAL(p, v);
        !           180:        alpha_lds(rn, v);
        !           181: }
        !           182:
        !           183: static __inline void
        !           184: ldt(unsigned int rn, t_float *v, struct proc *p)
        !           185: {
        !           186:        POSTFILTER_SUBNORMAL(p, v);
        !           187:        alpha_ldt(rn, v);
        !           188: }
        !           189:
        !           190: static float64
        !           191: compare_lt(float64 a, float64 b)
        !           192: {
        !           193:        return CMP_RESULT(float64_lt(a, b));
        !           194: }
        !           195:
        !           196: static float64
        !           197: compare_le(float64 a, float64 b)
        !           198: {
        !           199:        return CMP_RESULT(float64_le(a, b));
        !           200: }
        !           201:
        !           202: static float64
        !           203: compare_un(float64 a, float64 b)
        !           204: {
        !           205:        if (float64_is_nan(a) | float64_is_nan(b)) {
        !           206:                if (float64_is_signaling_nan(a) | float64_is_signaling_nan(b))
        !           207:                        float_set_invalid();
        !           208:                return CMP_RESULT(1);
        !           209:        }
        !           210:        return CMP_RESULT(0);
        !           211: }
        !           212:
        !           213: static float64
        !           214: compare_eq(float64 a, float64 b)
        !           215: {
        !           216:        return CMP_RESULT(float64_eq(a, b));
        !           217: }
        !           218: /*
        !           219:  * A note regarding the VAX FP ops.
        !           220:  *
        !           221:  * The AARM gives us complete leeway to set or not set status flags on VAX
        !           222:  * ops, but we do any subnorm, NaN and dirty zero fixups anyway, and we set
        !           223:  * flags by IEEE rules.  Many ops are common to d/f/g and s/t source types.
        !           224:  * For the purely vax ones, it's hard to imagine ever running them.
        !           225:  * (Generated VAX fp ops with completion flags? Hmm.)  We are careful never
        !           226:  * to panic, assert, or print unlimited output based on a path through the
        !           227:  * decoder, so weird cases don't become security issues.
        !           228:  */
        !           229: static void
        !           230: cvt_qs_ts_st_gf_qf(u_int32_t inst_bits, struct proc *p)
        !           231: {
        !           232:        t_float tfb, tfc;
        !           233:        s_float sfb, sfc;
        !           234:        alpha_instruction inst;
        !           235:
        !           236:        inst.bits = inst_bits;
        !           237:        /*
        !           238:         * cvtst and cvtts have the same opcode, function, and source.  The
        !           239:         * distinction for cvtst is hidden in the illegal modifier combinations.
        !           240:         * We decode even the non-/s modifier, so that the fix-up-always mode
        !           241:         * works on ev6 and later. The rounding bits are unused and fixed for
        !           242:         * cvtst, so we check those too.
        !           243:         */
        !           244:        switch(inst.float_format.function) {
        !           245:        case op_cvtst:
        !           246:        case op_cvtst_u:
        !           247:                sts(inst.float_detail.fb, &sfb, p);
        !           248:                tfc.i = float32_to_float64(sfb.i);
        !           249:                ldt(inst.float_detail.fc, &tfc, p);
        !           250:                return;
        !           251:        }
        !           252:        if(inst.float_detail.src == 2) {
        !           253:                stt(inst.float_detail.fb, &tfb, p);
        !           254:                sfc.i = float64_to_float32(tfb.i);
        !           255:                lds(inst.float_detail.fc, &sfc, p);
        !           256:                return;
        !           257:        }
        !           258:        /* 0: S/F */
        !           259:        /* 1:  /D */
        !           260:        /* 3: Q/Q */
        !           261:        this_cannot_happen(5, inst.generic_format.opcode);
        !           262:        tfc.i = FLOAT64QNAN;
        !           263:        ldt(inst.float_detail.fc, &tfc, p);
        !           264:        return;
        !           265: }
        !           266:
        !           267: static void
        !           268: cvt_gd(u_int32_t inst_bits, struct proc *p)
        !           269: {
        !           270:        t_float tfb, tfc;
        !           271:        alpha_instruction inst;
        !           272:
        !           273:        inst.bits = inst_bits;
        !           274:        stt(inst.float_detail.fb, &tfb, p);
        !           275:        (void) float64_to_float32(tfb.i);
        !           276:        p->p_md.md_flags &= ~OPENBSD_FLAG_TO_FP_C(FP_X_IMP);
        !           277:        tfc.i = float64_add(tfb.i, (float64)0);
        !           278:        ldt(inst.float_detail.fc, &tfc, p);
        !           279: }
        !           280:
        !           281: static void
        !           282: cvt_qt_dg_qg(u_int32_t inst_bits, struct proc *p)
        !           283: {
        !           284:        t_float tfb, tfc;
        !           285:        alpha_instruction inst;
        !           286:
        !           287:        inst.bits = inst_bits;
        !           288:        switch(inst.float_detail.src) {
        !           289:        case 0: /* S/F */
        !           290:                this_cannot_happen(3, inst.bits);
        !           291:                /* fall thru */
        !           292:        case 1: /* D */
        !           293:                /* VAX dirty 0's and reserved ops => UNPREDICTABLE */
        !           294:                /* We've done what's important by just not trapping */
        !           295:                tfc.i = 0;
        !           296:                break;
        !           297:        case 2: /* T/G */
        !           298:                this_cannot_happen(4, inst.bits);
        !           299:                tfc.i = 0;
        !           300:                break;
        !           301:        case 3: /* Q/Q */
        !           302:                stt(inst.float_detail.fb, &tfb, p);
        !           303:                tfc.i = int64_to_float64(tfb.i);
        !           304:                break;
        !           305:        }
        !           306:        alpha_ldt(inst.float_detail.fc, &tfc);
        !           307: }
        !           308: /*
        !           309:  * XXX: AARM and 754 seem to disagree here, also, beware of softfloat's
        !           310:  *      unfortunate habit of always returning the nontrapping result.
        !           311:  * XXX: there are several apparent AARM/AAH disagreements, as well as
        !           312:  *      the issue of trap handler pc and trapping results.
        !           313:  */
        !           314: static void
        !           315: cvt_tq_gq(u_int32_t inst_bits, struct proc *p)
        !           316: {
        !           317:        t_float tfb, tfc;
        !           318:        alpha_instruction inst;
        !           319:
        !           320:        inst.bits = inst_bits;
        !           321:        stt(inst.float_detail.fb, &tfb, p);
        !           322:        tfc.i = float64_to_int64(tfb.i);
        !           323:        alpha_ldt(inst.float_detail.fc, &tfc);  /* yes, ldt */
        !           324: }
        !           325:
        !           326: static u_int64_t
        !           327: fp_c_to_fpcr_1(u_int64_t fpcr, u_int64_t fp_c)
        !           328: {
        !           329:        u_int64_t disables;
        !           330:
        !           331:        /*
        !           332:         * It's hard to arrange for conforming bit fields, because the FP_C
        !           333:         * and the FPCR are both architected, with specified (and relatively
        !           334:         * scrambled) bit numbers. Defining an internal unscrambled FP_C
        !           335:         * wouldn't help much, because every user exception requires the
        !           336:         * architected bit order in the sigcontext.
        !           337:         *
        !           338:         * Programs that fiddle with the fpcr exception bits (instead of fp_c)
        !           339:         * will lose, because those bits can be and usually are subsetted;
        !           340:         * the official home is in the fp_c. Furthermore, the kernel puts
        !           341:         * phony enables (it lies :-) in the fpcr in order to get control when
        !           342:         * it is necessary to initially set a sticky bit.
        !           343:         */
        !           344:
        !           345:        fpcr &= FPCR_DYN(3);
        !           346:
        !           347:        /*
        !           348:         * enable traps = case where flag bit is clear OR program wants a trap
        !           349:         * enables = ~flags | mask
        !           350:         * disables = ~(~flags | mask)
        !           351:         * disables = flags & ~mask. Thank you, Augustus De Morgan (1806-1871)
        !           352:         */
        !           353:        disables = FP_C_TO_OPENBSD_FLAG(fp_c) & ~FP_C_TO_OPENBSD_MASK(fp_c);
        !           354:
        !           355:        fpcr |= (disables & (FP_X_IMP | FP_X_UFL)) << (61 - 3);
        !           356:        fpcr |= (disables & (FP_X_OFL | FP_X_DZ | FP_X_INV)) << (49 - 0);
        !           357:
        !           358: #      if !(FP_X_INV == 1 && FP_X_DZ == 2 && FP_X_OFL == 4 &&          \
        !           359:            FP_X_UFL == 8 && FP_X_IMP == 16 && FP_X_IOV == 32 &&        \
        !           360:            FP_X_UFL << (61 - 3) == FPCR_UNFD &&                        \
        !           361:            FP_X_IMP << (61 - 3) == FPCR_INED &&                        \
        !           362:            FP_X_OFL << (49 - 0) == FPCR_OVFD)
        !           363: #              error "Assertion failed"
        !           364:        /*
        !           365:         * We don't care about the other built-in bit numbers because they
        !           366:         * have been architecturally specified.
        !           367:         */
        !           368: #      endif
        !           369:
        !           370:        fpcr |= fp_c & FP_C_MIRRORED << (FPCR_MIR_START - FP_C_MIR_START);
        !           371:        fpcr |= (fp_c & IEEE_MAP_DMZ) << 36;
        !           372:        if (fp_c & FP_C_MIRRORED)
        !           373:                fpcr |= FPCR_SUM;
        !           374:        if (fp_c & IEEE_MAP_UMZ)
        !           375:                fpcr |= FPCR_UNDZ | FPCR_UNFD;
        !           376:        fpcr |= (~fp_c & IEEE_TRAP_ENABLE_DNO) << 41;
        !           377:        return fpcr;
        !           378: }
        !           379:
        !           380: static void
        !           381: fp_c_to_fpcr(struct proc *p)
        !           382: {
        !           383:        alpha_write_fpcr(fp_c_to_fpcr_1(alpha_read_fpcr(), p->p_md.md_flags));
        !           384: }
        !           385:
        !           386: void
        !           387: alpha_write_fp_c(struct proc *p, u_int64_t fp_c)
        !           388: {
        !           389:        u_int64_t md_flags;
        !           390:
        !           391:        fp_c &= MDP_FP_C;
        !           392:        md_flags = p->p_md.md_flags;
        !           393:        if ((md_flags & MDP_FP_C) == fp_c)
        !           394:                return;
        !           395:        p->p_md.md_flags = (md_flags & ~MDP_FP_C) | fp_c;
        !           396:        alpha_enable_fp(p, 1);
        !           397:        fp_c_to_fpcr(p);
        !           398:        alpha_pal_wrfen(0);
        !           399: }
        !           400:
        !           401: u_int64_t
        !           402: alpha_read_fp_c(struct proc *p)
        !           403: {
        !           404:        /*
        !           405:         * A possibly desirable EV6-specific optimization would deviate from
        !           406:         * the Alpha Architecture spec and keep some FP_C bits in the FPCR,
        !           407:         * but in a transparent way. Some of the code for that would need to
        !           408:         * go right here.
        !           409:         */
        !           410:        return p->p_md.md_flags & MDP_FP_C;
        !           411: }
        !           412:
        !           413: static float64
        !           414: float64_unk(float64 a, float64 b)
        !           415: {
        !           416:        return 0;
        !           417: }
        !           418:
        !           419: /*
        !           420:  * The real function field encodings for IEEE and VAX FP instructions.
        !           421:  *
        !           422:  * Since there is only one operand type field, the cvtXX instructions
        !           423:  * require a variety of special cases, and these have to be analyzed as
        !           424:  * they don't always fit into the field descriptions in AARM section I.
        !           425:  *
        !           426:  * Lots of staring at bits in the appendix shows what's really going on.
        !           427:  *
        !           428:  *        |           |
        !           429:  * 15 14 13|12 11 10 09|08 07 06 05
        !           430:  * --------======------============
        !           431:  *  TRAP   : RND : SRC : FUNCTION  :
        !           432:  *  0  0  0:. . .:. . . . . . . . . . . . Imprecise
        !           433:  *  0  0  1|. . .:. . . . . . . . . . . ./U underflow enable (if FP output)
        !           434:  *        |                             /V overfloat enable (if int output)
        !           435:  *  0  1  0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST
        !           436:  *  0  1  1|. . .:. . . . . . . . . . . . Unsupported
        !           437:  *  1  0  0:. . .:. . . . . . . . . . . ./S software completion (VAX only)
        !           438:  *  1  0  1|. . .:. . . . . . . . . . . ./SU
        !           439:  *        |                             /SV
        !           440:  *  1  1  0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST/S
        !           441:  *  1  1  1|. . .:. . . . . . . . . . . ./SUI (if FP output)   (IEEE only)
        !           442:  *        |                             /SVI (if int output)   (IEEE only)
        !           443:  *  S  I  UV: In other words: bits 15:13 are S:I:UV, except that _usually_
        !           444:  *        |  not all combinations are valid.
        !           445:  *        |           |
        !           446:  * 15 14 13|12 11 10 09|08 07 06 05
        !           447:  * --------======------============
        !           448:  *  TRAP   : RND : SRC : FUNCTION  :
        !           449:  *        | 0  0 . . . . . . . . . . . ./C Chopped
        !           450:  *        : 0  1 . . . . . . . . . . . ./M Minus Infinity
        !           451:  *        | 1  0 . . . . . . . . . . . .   Normal
        !           452:  *        : 1  1 . . . . . . . . . . . ./D Dynamic (in FPCR: Plus Infinity)
        !           453:  *        |           |
        !           454:  * 15 14 13|12 11 10 09|08 07 06 05
        !           455:  * --------======------============
        !           456:  *  TRAP   : RND : SRC : FUNCTION  :
        !           457:  *                0 0. . . . . . . . . . S/F
        !           458:  *                0 1. . . . . . . . . . -/D
        !           459:  *                1 0. . . . . . . . . . T/G
        !           460:  *                1 1. . . . . . . . . . Q/Q
        !           461:  *        |           |
        !           462:  * 15 14 13|12 11 10 09|08 07 06 05
        !           463:  * --------======------============
        !           464:  *  TRAP   : RND : SRC : FUNCTION  :
        !           465:  *                      0  0  0  0 . . . addX
        !           466:  *                      0  0  0  1 . . . subX
        !           467:  *                      0  0  1  0 . . . mulX
        !           468:  *                      0  0  1  1 . . . divX
        !           469:  *                      0  1  0  0 . . . cmpXun
        !           470:  *                      0  1  0  1 . . . cmpXeq
        !           471:  *                      0  1  1  0 . . . cmpXlt
        !           472:  *                      0  1  1  1 . . . cmpXle
        !           473:  *                      1  0  0  0 . . . reserved
        !           474:  *                      1  0  0  1 . . . reserved
        !           475:  *                      1  0  1  0 . . . sqrt[fg] (op_fix, not exactly "vax")
        !           476:  *                      1  0  1  1 . . . sqrt[st] (op_fix, not exactly "ieee")
        !           477:  *                      1  1  0  0 . . . cvtXs/f (cvt[qt]s, cvtst(!), cvt[gq]f)
        !           478:  *                      1  1  0  1 . . . cvtXd   (vax only)
        !           479:  *                      1  1  1  0 . . . cvtXt/g (cvtqt, cvt[dq]g only)
        !           480:  *                      1  1  1  1 . . . cvtXq/q (cvttq, cvtgq)
        !           481:  *        |           |
        !           482:  * 15 14 13|12 11 10 09|08 07 06 05      the twilight zone
        !           483:  * --------======------============
        !           484:  *  TRAP   : RND : SRC : FUNCTION  :
        !           485:  * /s /i /u  x  x  1  0  1  1  0  0 . . . cvtts, /siu only 0, 1, 5, 7
        !           486:  *  0  1  0  1  0  1  0  1  1  0  0 . . . cvtst   (src == T (!)) 2ac NOT /S
        !           487:  *  1  1  0  1  0  1  0  1  1  0  0 . . . cvtst/s (src == T (!)) 6ac
        !           488:  *  x  0  x  x  x  x  0         1  1  1  1 . . . cvttq/_ (src == T)
        !           489:  */
        !           490:
        !           491: static void
        !           492: alpha_fp_interpret(alpha_instruction *pc, struct proc *p, u_int64_t bits)
        !           493: {
        !           494:        s_float sfa, sfb, sfc;
        !           495:        t_float tfa, tfb, tfc;
        !           496:        alpha_instruction inst;
        !           497:
        !           498:        inst.bits = bits;
        !           499:        switch(inst.generic_format.opcode) {
        !           500:        default:
        !           501:                /* this "cannot happen" */
        !           502:                this_cannot_happen(2, inst.bits);
        !           503:                return;
        !           504:        case op_any_float:
        !           505:                if (inst.float_format.function == op_cvtql_sv ||
        !           506:                    inst.float_format.function == op_cvtql_v) {
        !           507:                        alpha_stt(inst.float_detail.fb, &tfb);
        !           508:                        sfc.i = (int64_t)tfb.i >= 0L ? INT_MAX : INT_MIN;
        !           509:                        alpha_lds(inst.float_detail.fc, &sfc);
        !           510:                        float_raise(FP_X_INV);
        !           511:                } else {
        !           512:                        ++alpha_shadow.nilanyop;
        !           513:                        this_cannot_happen(3, inst.bits);
        !           514:                }
        !           515:                break;
        !           516:        case op_vax_float:
        !           517:                ++alpha_shadow.vax;     /* fall thru */
        !           518:        case op_ieee_float:
        !           519:        case op_fix_float:
        !           520:                switch(inst.float_detail.src) {
        !           521:                case op_src_sf:
        !           522:                        sts(inst.float_detail.fb, &sfb, p);
        !           523:                        if (inst.float_detail.opclass == 10)
        !           524:                                sfc.i = float32_sqrt(sfb.i);
        !           525:                        else if (inst.float_detail.opclass & ~3) {
        !           526:                                this_cannot_happen(1, inst.bits);
        !           527:                                sfc.i = FLOAT32QNAN;
        !           528:                        } else {
        !           529:                                sts(inst.float_detail.fa, &sfa, p);
        !           530:                                sfc.i = (*swfp_s[inst.float_detail.opclass])(
        !           531:                                    sfa.i, sfb.i);
        !           532:                        }
        !           533:                        lds(inst.float_detail.fc, &sfc, p);
        !           534:                        break;
        !           535:                case op_src_xd:
        !           536:                case op_src_tg:
        !           537:                        if (inst.float_detail.opclass >= 12)
        !           538:                                (*swfp_cvt[inst.float_detail.opclass - 12])(
        !           539:                                    inst.bits, p);
        !           540:                        else {
        !           541:                                stt(inst.float_detail.fb, &tfb, p);
        !           542:                                if (inst.float_detail.opclass == 10)
        !           543:                                        tfc.i = float64_sqrt(tfb.i);
        !           544:                                else {
        !           545:                                        stt(inst.float_detail.fa, &tfa, p);
        !           546:                                        tfc.i = (*swfp_t[inst.float_detail
        !           547:                                            .opclass])(tfa.i, tfb.i);
        !           548:                                }
        !           549:                                ldt(inst.float_detail.fc, &tfc, p);
        !           550:                        }
        !           551:                        break;
        !           552:                case op_src_qq:
        !           553:                        float_raise(FP_X_IMP);
        !           554:                        break;
        !           555:                }
        !           556:        }
        !           557: }
        !           558:
        !           559: static int
        !           560: alpha_fp_complete_at(alpha_instruction *trigger_pc, struct proc *p,
        !           561:     u_int64_t *ucode)
        !           562: {
        !           563:        int needsig;
        !           564:        alpha_instruction inst;
        !           565:        u_int64_t rm, fpcr, orig_fpcr;
        !           566:        u_int64_t orig_flags, new_flags, changed_flags, md_flags;
        !           567:
        !           568:        if (__predict_false(copyin(trigger_pc, &inst, sizeof inst))) {
        !           569:                this_cannot_happen(6, -1);
        !           570:                return SIGSEGV;
        !           571:        }
        !           572:        alpha_enable_fp(p, 1);
        !           573:        /*
        !           574:         * If necessary, lie about the dynamic rounding mode so emulation
        !           575:         * software need go to only one place for it, and so we don't have to
        !           576:         * lock any memory locations or pass a third parameter to every
        !           577:         * SoftFloat entry point.
        !           578:         */
        !           579:        orig_fpcr = fpcr = alpha_read_fpcr();
        !           580:        rm = inst.float_detail.rnd;
        !           581:        if (__predict_false(rm != 3 /* dynamic */ && rm != (fpcr >> 58 & 3))) {
        !           582:                fpcr = (fpcr & ~FPCR_DYN(3)) | FPCR_DYN(rm);
        !           583:                alpha_write_fpcr(fpcr);
        !           584:        }
        !           585:        orig_flags = FP_C_TO_OPENBSD_FLAG(p->p_md.md_flags);
        !           586:
        !           587:        alpha_fp_interpret(trigger_pc, p, inst.bits);
        !           588:
        !           589:        md_flags = p->p_md.md_flags;
        !           590:
        !           591:        new_flags = FP_C_TO_OPENBSD_FLAG(md_flags);
        !           592:        changed_flags = orig_flags ^ new_flags;
        !           593:        KASSERT((orig_flags | changed_flags) == new_flags); /* panic on 1->0 */
        !           594:        alpha_write_fpcr(fp_c_to_fpcr_1(orig_fpcr, md_flags));
        !           595:        needsig = changed_flags & FP_C_TO_OPENBSD_MASK(md_flags);
        !           596:        alpha_pal_wrfen(0);
        !           597:        if (__predict_false(needsig)) {
        !           598:                *ucode = needsig;
        !           599:                return SIGFPE;
        !           600:        }
        !           601:        return 0;
        !           602: }
        !           603:
        !           604: int
        !           605: alpha_fp_complete(u_long a0, u_long a1, struct proc *p, u_int64_t *ucode)
        !           606: {
        !           607:        int t;
        !           608:        int sig;
        !           609:        u_int64_t op_class;
        !           610:        alpha_instruction inst;
        !           611:        /* "trigger_pc" is Compaq's term for the earliest faulting op */
        !           612:        alpha_instruction *trigger_pc, *usertrap_pc;
        !           613:        alpha_instruction *pc, *win_begin, tsw[TSWINSIZE];
        !           614:
        !           615:        sig = SIGFPE;
        !           616:        pc = (alpha_instruction *)p->p_md.md_tf->tf_regs[FRAME_PC];
        !           617:        trigger_pc = pc - 1;    /* for ALPHA_AMASK_PAT case */
        !           618:        if (cpu_amask & ALPHA_AMASK_PAT) {
        !           619:                if (a0 & 1 || alpha_fp_sync_complete) {
        !           620:                        sig = alpha_fp_complete_at(trigger_pc, p, ucode);
        !           621:                        goto done;
        !           622:                }
        !           623:        }
        !           624:        *ucode = a0;
        !           625:        if (!(a0 & 1))
        !           626:                return sig;
        !           627: /*
        !           628:  * At this point we are somewhere in the trap shadow of one or more instruc-
        !           629:  * tions that have trapped with software completion specified.  We have a mask
        !           630:  * of the registers written by trapping instructions.
        !           631:  *
        !           632:  * Now step backwards through the trap shadow, clearing bits in the
        !           633:  * destination write mask until the trigger instruction is found, and
        !           634:  * interpret this one instruction in SW. If a SIGFPE is not required, back up
        !           635:  * the PC until just after this instruction and restart. This will execute all
        !           636:  * trap shadow instructions between the trigger pc and the trap pc twice.
        !           637:  *
        !           638:  * If a SIGFPE is generated from the OSF1 emulation,  back up one more
        !           639:  * instruction to the trigger pc itself. Native binaries don't because it
        !           640:  * is non-portable and completely defeats the intended purpose of IEEE
        !           641:  * traps -- for example, to count the number of exponent wraps for a later
        !           642:  * correction.
        !           643:  */
        !           644:        trigger_pc = 0;
        !           645:        win_begin = pc;
        !           646:        ++alpha_shadow.scans;
        !           647:        t = alpha_shadow.len;
        !           648:        for (--pc; a1; --pc) {
        !           649:                ++alpha_shadow.len;
        !           650:                if (pc < win_begin) {
        !           651:                        win_begin = pc - TSWINSIZE + 1;
        !           652:                        if (copyin(win_begin, tsw, sizeof tsw)) {
        !           653:                                /* sigh, try to get just one */
        !           654:                                win_begin = pc;
        !           655:                                if (copyin(win_begin, tsw, 4))
        !           656:                                        return SIGSEGV;
        !           657:                        }
        !           658:                }
        !           659:                inst = tsw[pc - win_begin];
        !           660:                op_class = 1UL << inst.generic_format.opcode;
        !           661:                if (op_class & FPUREG_CLASS) {
        !           662:                        a1 &= ~(1UL << (inst.operate_generic_format.rc + 32));
        !           663:                        trigger_pc = pc;
        !           664:                } else if (op_class & CPUREG_CLASS) {
        !           665:                        a1 &= ~(1UL << inst.operate_generic_format.rc);
        !           666:                        trigger_pc = pc;
        !           667:                } else if (op_class & TRAPSHADOWBOUNDARY) {
        !           668:                        if (op_class & CHECKFUNCTIONCODE) {
        !           669:                                if (inst.mem_format.displacement == op_trapb ||
        !           670:                                    inst.mem_format.displacement == op_excb)
        !           671:                                        break;  /* code breaks AARM rules */
        !           672:                        } else
        !           673:                                break; /* code breaks AARM rules */
        !           674:                }
        !           675:                /* Some shadow-safe op, probably load, store, or FPTI class */
        !           676:        }
        !           677:        t = alpha_shadow.len - t;
        !           678:        if (t > alpha_shadow.max)
        !           679:                alpha_shadow.max = t;
        !           680:        if (__predict_true(trigger_pc != 0 && a1 == 0)) {
        !           681:                ++alpha_shadow.resolved;
        !           682:                sig = alpha_fp_complete_at(trigger_pc, p, ucode);
        !           683:        } else {
        !           684:                ++alpha_shadow.unresolved;
        !           685:                return sig;
        !           686:        }
        !           687: done:
        !           688:        if (sig) {
        !           689:                usertrap_pc = trigger_pc + 1;
        !           690:                p->p_md.md_tf->tf_regs[FRAME_PC] = (unsigned long)usertrap_pc;
        !           691:                return sig;
        !           692:        }
        !           693:        return 0;
        !           694: }

CVSweb