word = fusword(frame->f_pc);
word = fusword((void *) (frame->f_pc));
static struct fpn *fpu_cmp __P((struct fpemu *fe));#if !defined(DL_DEFAULT)#  if defined(DEBUG_WITH_FPU)#    define DL_DEFAULT DL_ALL#  else#    define DL_DEFAULT 0#  endif#endifint fpu_debug_level;static int global_debug_level = DL_DEFAULT;#define DUMP_INSN(insn)							\if (fpu_debug_level & DL_DUMPINSN) {					\    printf("  fpu_emulate: insn={adv=%d,siz=%d,op=%04x,w1=%04x}\n",	\	   (insn)->is_advance, (insn)->is_datasize,			\	   (insn)->is_opcode, (insn)->is_word1);			\}#ifdef DEBUG_WITH_FPU/* mock fpframe for FPE - it's never overwritten by the real fpframe */struct fpframe mockfpf;#endif/* * Emulate a floating-point instruction. * Return zero for success, else signal number. * (Typically: zero, SIGFPE, SIGILL, SIGSEGV) */intfpu_emulate(frame, fpf)     struct frame *frame;     struct fpframe *fpf;{    static struct instruction insn;    static struct fpemu fe;    int word, optype, sig;    int i;    u_int *pt;#ifdef DEBUG    /* initialize insn.is_datasize to tell it is *not* initialized */    insn.is_datasize = -1;#endif    fe.fe_frame = frame;#ifdef DEBUG_WITH_FPU    fe.fe_fpframe = &mockfpf;    fe.fe_fpsr = mockfpf.fpf_fpsr;    fe.fe_fpcr = mockfpf.fpf_fpcr;#else    fe.fe_fpframe = fpf;    fe.fe_fpsr = fpf->fpf_fpsr;    fe.fe_fpcr = fpf->fpf_fpcr;#endif#ifdef DEBUG    if ((fpu_debug_level = (fe.fe_fpcr >> 16) & 0x0000ffff) == 0) {	/* set the default */	fpu_debug_level = global_debug_level;    }#endif    if (fpu_debug_level & DL_VERBOSE) {	printf("ENTERING fpu_emulate: FPSR=%08x, FPCR=%08x\n",	       fe.fe_fpsr, fe.fe_fpcr);    }    word = fusword(frame->f_pc);    if (word < 0) {#ifdef DEBUG	printf("  fpu_emulate: fault reading opcode\n");#endif	return SIGSEGV;    }    if ((word & 0xf000) != 0xf000) {#ifdef DEBUG	printf("  fpu_emulate: not coproc. insn.: opcode=0x%x\n", word);#endif	return SIGILL;    }    if (#ifdef  DEBUG_WITH_FPU	(word & 0x0E00) != 0x0c00 /* accept fake ID == 6 */#else	(word & 0x0E00) != 0x0200#endif	) {#ifdef DEBUG	printf("  fpu_emulate: bad coproc. id: opcode=0x%x\n", word);#endif	return SIGILL;    }    insn.is_opcode = word;    optype = (word & 0x01C0);    word = fusword(frame->f_pc + 2);    if (word < 0) {#ifdef DEBUG	printf("  fpu_emulate: fault reading word1\n");#endif	return SIGSEGV;    }    insn.is_word1 = word;    /* all FPU instructions are at least 4-byte long */    insn.is_advance = 4;    DUMP_INSN(&insn);    /*     * Which family (or type) of opcode is it?     * Tests ordered by likelihood (hopefully).     * Certainly, type 0 is the most common.     */    if (optype == 0x0000) {	/* type=0: generic */	if ((word & 0xc000) == 0xc000) {	    if (fpu_debug_level & DL_INSN)		printf("  fpu_emulate: fmovm FPr\n");	    sig = fpu_emul_fmovm(&fe, &insn);	} else if ((word & 0xc000) == 0x8000) {	    if (fpu_debug_level & DL_INSN)		printf("  fpu_emulate: fmovm FPcr\n");	    sig = fpu_emul_fmovmcr(&fe, &insn);	} else if ((word & 0xe000) == 0x6000) {	    /* fstore = fmove FPn,mem */	    if (fpu_debug_level & DL_INSN)		printf("  fpu_emulate: fmove to mem\n");	    sig = fpu_emul_fstore(&fe, &insn);	} else if ((word & 0xfc00) == 0x5c00) {	    /* fmovecr */	    if (fpu_debug_level & DL_INSN)		printf("  fpu_emulate: fmovecr\n");	    sig = fpu_emul_fmovecr(&fe, &insn);	} else if ((word & 0xa07f) == 0x26) {	    /* fscale */	    if (fpu_debug_level & DL_INSN)		printf("  fpu_emulate: fscale\n");	    sig = fpu_emul_fscale(&fe, &insn);	} else {	    if (fpu_debug_level & DL_INSN)		printf("  fpu_emulte: other type0\n");	    /* all other type0 insns are arithmetic */	    sig = fpu_emul_arith(&fe, &insn);	}	if (sig == 0) {	    if (fpu_debug_level & DL_VERBOSE)		printf("  fpu_emulate: type 0 returned 0\n");	    sig = fpu_upd_excp(&fe);	}    } else if (optype == 0x0080 || optype == 0x00C0) {	/* type=2 or 3: fbcc, short or long disp. */	if (fpu_debug_level & DL_INSN)	    printf("  fpu_emulate: fbcc %s\n",		   (optype & 0x40) ? "long" : "short");	sig = fpu_emul_brcc(&fe, &insn);    } else if (optype == 0x0040) {	/* type=1: fdbcc, fscc, ftrapcc */	if (fpu_debug_level & DL_INSN)	    printf("  fpu_emulate: type1\n");	sig = fpu_emul_type1(&fe, &insn);    } else {	/* type=4: fsave    (privileged) */	/* type=5: frestore (privileged) */	/* type=6: reserved */	/* type=7: reserved */#ifdef DEBUG	printf(" fpu_emulate: bad opcode type: opcode=0x%x\n", insn.is_opcode);#endif	sig = SIGILL;    }    DUMP_INSN(&insn);    if (sig == 0) {	frame->f_pc += insn.is_advance;    }#if defined(DDB) && defined(DEBUG)    else {	printf(" fpu_emulate: sig=%d, opcode=%x, word1=%x\n",	       sig, insn.is_opcode, insn.is_word1);	kdb_trap(-1, frame);    }#endif    if (fpu_debug_level & DL_VERBOSE)	printf("EXITING fpu_emulate: w/FPSR=%08x, FPCR=%08x\n",	       fe.fe_fpsr, fe.fe_fpcr);    return (sig);}/* update accrued exception bits and see if there's an FP exception */intfpu_upd_excp(fe)     struct fpemu *fe;{    u_int fpsr;    u_int fpcr;    fpsr = fe->fe_fpsr;    fpcr = fe->fe_fpcr;    /* update fpsr accrued exception bits; each insn doesn't have to       update this */    if (fpsr & (FPSR_BSUN | FPSR_SNAN | FPSR_OPERR)) {	fpsr |= FPSR_AIOP;    }    if (fpsr & FPSR_OVFL) {	fpsr |= FPSR_AOVFL;    }    if ((fpsr & FPSR_UNFL) && (fpsr & FPSR_INEX2)) {	fpsr |= FPSR_AUNFL;    }    if (fpsr & FPSR_DZ) {	fpsr |= FPSR_ADZ;    }    if (fpsr & (FPSR_INEX1 | FPSR_INEX2 | FPSR_OVFL)) {	fpsr |= FPSR_AINEX;    }    fe->fe_fpframe->fpf_fpsr = fe->fe_fpsr = fpsr;    return (fpsr & fpcr & FPSR_EXCP) ? SIGFPE : 0;}/* update fpsr according to fp (= result of an fp op) */u_intfpu_upd_fpsr(fe, fp)     struct fpemu *fe;     struct fpn *fp;{    u_int fpsr;    if (fpu_debug_level & DL_RESULT)	printf("  fpu_upd_fpsr: previous fpsr=%08x\n", fe->fe_fpsr);    /* clear all condition code */    fpsr = fe->fe_fpsr & ~FPSR_CCB;    if (fpu_debug_level & DL_RESULT)	printf("  fpu_upd_fpsr: result is a ");    if (fp->fp_sign) {	if (fpu_debug_level & DL_RESULT)	    printf("negative ");	fpsr |= FPSR_NEG;    } else {	if (fpu_debug_level & DL_RESULT)	    printf("positive ");    }    switch (fp->fp_class) {    case FPC_SNAN:	if (fpu_debug_level & DL_RESULT)	    printf("signaling NAN\n");	fpsr |= (FPSR_NAN | FPSR_SNAN);	break;    case FPC_QNAN:	if (fpu_debug_level & DL_RESULT)	    printf("quiet NAN\n");	fpsr |= FPSR_NAN;	break;    case FPC_ZERO:	if (fpu_debug_level & DL_RESULT)	    printf("Zero\n");	fpsr |= FPSR_ZERO;	break;    case FPC_INF:	if (fpu_debug_level & DL_RESULT)	    printf("Inf\n");	fpsr |= FPSR_INF;	break;    default:	if (fpu_debug_level & DL_RESULT)	    printf("Number\n");	/* anything else is treated as if it is a number */	break;    }    fe->fe_fpsr = fe->fe_fpframe->fpf_fpsr = fpsr;    if (fpu_debug_level & DL_RESULT)	printf("  fpu_upd_fpsr: new fpsr=%08x\n", fe->fe_fpframe->fpf_fpsr);    return fpsr;}static intfpu_emul_fmovmcr(fe, insn)     struct fpemu *fe;     struct instruction *insn;{    struct frame *frame = fe->fe_frame;    struct fpframe *fpf = fe->fe_fpframe;    int word1, sig;    int reglist, regmask, regnum;    int fpu_to_mem;    /* move to/from control registers */    reglist = (insn->is_word1 & 0x1c00) >> 10;    /* Bit 13 selects direction (FPU to/from Mem) */    fpu_to_mem = insn->is_word1 & 0x2000;    insn->is_datasize = 4;    insn->is_advance = 4;    sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);    if (sig) { return sig; }    if (reglist != 1 && reglist != 2 && reglist != 4 &&	(insn->is_ea0.ea_flags & EA_DIRECT)) {	/* attempted to copy more than one FPcr to CPU regs */#ifdef DEBUG	printf("  fpu_emul_fmovmcr: tried to copy too many FPcr\n");#endif	return SIGILL;    }    if (reglist & 4) {	/* fpcr */	if ((insn->is_ea0.ea_flags & EA_DIRECT) &&	    insn->is_ea0.ea_regnum >= 8 /* address reg */) {	    /* attempted to copy FPCR to An */#ifdef DEBUG	    printf("  fpu_emul_fmovmcr: tried to copy FPCR from/to A%d\n",		   insn->is_ea0.ea_regnum & 7);#endif	    return SIGILL;	}	if (fpu_to_mem) {	    sig = fpu_store_ea(frame, insn, &insn->is_ea0,			       (char *)&fpf->fpf_fpcr);	} else {	    sig = fpu_load_ea(frame, insn, &insn->is_ea0,			      (char *)&fpf->fpf_fpcr);	}    }    if (sig) { return sig; }    if (reglist & 2) {	/* fpsr */	if ((insn->is_ea0.ea_flags & EA_DIRECT) &&	    insn->is_ea0.ea_regnum >= 8 /* address reg */) {	    /* attempted to copy FPSR to An */#ifdef DEBUG	    printf("  fpu_emul_fmovmcr: tried to copy FPSR from/to A%d\n",		   insn->is_ea0.ea_regnum & 7);#endif	    return SIGILL;	}	if (fpu_to_mem) {	    sig = fpu_store_ea(frame, insn, &insn->is_ea0,			       (char *)&fpf->fpf_fpsr);	} else {	    sig = fpu_load_ea(frame, insn, &insn->is_ea0,			      (char *)&fpf->fpf_fpsr);	}    }    if (sig) { return sig; }      if (reglist & 1) {	/* fpiar - can be moved to/from An */	if (fpu_to_mem) {	    sig = fpu_store_ea(frame, insn, &insn->is_ea0,			       (char *)&fpf->fpf_fpiar);	} else {	    sig = fpu_load_ea(frame, insn, &insn->is_ea0,			      (char *)&fpf->fpf_fpiar);	}    }    return sig;}/* * type 0: fmovem * Separated out of fpu_emul_type0 for efficiency. * In this function, we know: *   (opcode & 0x01C0) == 0 *   (word1 & 0x8000) == 0x8000 * * No conversion or rounding is done by this instruction, * and the FPSR is not affected. */static intfpu_emul_fmovm(fe, insn)     struct fpemu *fe;     struct instruction *insn;{    struct frame *frame = fe->fe_frame;    struct fpframe *fpf = fe->fe_fpframe;    int word1, sig;    int reglist, regmask, regnum;    int fpu_to_mem, order;    int w1_post_incr;		/* XXX - FP regs order? */    int *fpregs;    insn->is_advance = 4;    insn->is_datasize = 12;    word1 = insn->is_word1;    /* Bit 13 selects direction (FPU to/from Mem) */    fpu_to_mem = word1 & 0x2000;    /*     * Bits 12,11 select register list mode:     * 0,0: Static  reg list, pre-decr.     * 0,1: Dynamic reg list, pre-decr.     * 1,0: Static  reg list, post-incr.     * 1,1: Dynamic reg list, post-incr     */    w1_post_incr = word1 & 0x1000;    if (word1 & 0x0800) {	/* dynamic reg list */	reglist = frame->f_regs[(word1 & 0x70) >> 4];    } else {	reglist = word1;    }    reglist &= 0xFF;    /* Get effective address. (modreg=opcode&077) */    sig = fpu_decode_ea(frame, insn, &insn->is_ea0, insn->is_opcode);    if (sig) { return sig; }    /* Get address of soft coprocessor regs. */    fpregs = &fpf->fpf_regs[0];    if (insn->is_ea0.ea_flags & EA_PREDECR) {	regnum = 7;	order = -1;    } else {	regnum = 0;	order = 1;    }    while ((0 <= regnum) && (regnum < 8)) {	regmask = 1 << regnum;	if (regmask & reglist) {	    if (fpu_to_mem) {		sig = fpu_store_ea(frame, insn, &insn->is_ea0,				   (char*)&fpregs[regnum * 3]);		if (fpu_debug_level & DL_RESULT)		    printf("  fpu_emul_fmovm: FP%d (%08x,%08x,%08x) saved\n",			   regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],			   fpregs[regnum * 3 + 2]);	    } else {		/* mem to fpu */		sig = fpu_load_ea(frame, insn, &insn->is_ea0,				  (char*)&fpregs[regnum * 3]);		if (fpu_debug_level & DL_RESULT)		    printf("  fpu_emul_fmovm: FP%d (%08x,%08x,%08x) loaded\n",			   regnum, fpregs[regnum * 3], fpregs[regnum * 3 + 1],			   fpregs[regnum * 3 + 2]);	    }	    if (sig) { break; }	}	regnum += order;    }    return sig;}static struct fpn *fpu_cmp(fe)     struct fpemu *fe;{    struct fpn *x = &fe->fe_f1, *y = &fe->fe_f2;    /* take care of special cases */    if (x->fp_class < 0 || y->fp_class < 0) {	/* if either of two is a SNAN, result is SNAN */	x->fp_class = (y->fp_class < x->fp_class) ? y->fp_class : x->fp_class;    } else if (x->fp_class == FPC_INF) {	if (y->fp_class == FPC_INF) {	    /* both infinities */	    if (x->fp_sign == y->fp_sign) {		x->fp_class = FPC_ZERO;	/* return a signed zero */	    } else {		x->fp_class = FPC_NUM; /* return a faked number w/x's sign */		x->fp_exp = 16383;		x->fp_mant[0] = FP_1;	    }	} else {	    /* y is a number */	    x->fp_class = FPC_NUM; /* return a forged number w/x's sign */	    x->fp_exp = 16383;	    x->fp_mant[0] = FP_1;	}    } else if (y->fp_class == FPC_INF) {	/* x is a Num but y is an Inf */	/* return a forged number w/y's sign inverted */	x->fp_class = FPC_NUM;	x->fp_sign = !y->fp_sign;	x->fp_exp = 16383;	x->fp_mant[0] = FP_1;    } else {	/* x and y are both numbers or zeros, or pair of a number and a zero */	y->fp_sign = !y->fp_sign;	x = fpu_add(fe);	/* (x - y) */	/*	 * FCMP does not set Inf bit in CC, so return a forged number	 * (value doesn't matter) if Inf is the result of fsub.	 */	if (x->fp_class == FPC_INF) {	    x->fp_class = FPC_NUM;	    x->fp_exp = 16383;	    x->fp_mant[0] = FP_1;	}    }    return x;}