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