xref: /csrg-svn/sys/i386/isa/npx.c (revision 53642)
149617Sbostic /*-
249617Sbostic  * Copyright (c) 1990 William Jolitz.
349617Sbostic  * Copyright (c) 1991 The Regents of the University of California.
449617Sbostic  * All rights reserved.
549617Sbostic  *
649617Sbostic  * %sccs.include.redist.c%
749617Sbostic  *
8*53642Sbostic  *	@(#)npx.c	7.4 (Berkeley) 05/20/92
945624Sbill  */
1045624Sbill #include "npx.h"
1149617Sbostic #if NNPX > 0
1245624Sbill 
1345624Sbill #include "param.h"
1445624Sbill #include "systm.h"
1545624Sbill #include "conf.h"
1645624Sbill #include "file.h"
1749573Swilliam #include "proc.h"
1849694Swilliam #include "machine/cpu.h"
1951728Swilliam #include "user.h"
2049694Swilliam #include "machine/trap.h"
2145624Sbill #include "ioctl.h"
2249573Swilliam #include "machine/specialreg.h"
2349573Swilliam #include "i386/isa/isa_device.h"
2445624Sbill #include "icu.h"
2545624Sbill /*
2645547Sbill  * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
2745547Sbill  */
2845547Sbill 
2945547Sbill int	npxprobe(), npxattach(), npxintr();
3045624Sbill struct	isa_driver npxdriver = {
3145547Sbill 	npxprobe, npxattach, "npx",
3245547Sbill };
3345547Sbill 
3449694Swilliam struct proc *npxproc;	/* process who owns device, otherwise zero */
3549694Swilliam struct pcb *npxpcb;	/* owners context structure */
3649573Swilliam static npxexists;
3749573Swilliam extern long npx0mask;
3845547Sbill 
3945547Sbill /*
4045547Sbill  * Probe routine - look device, otherwise set emulator bit
4145547Sbill  */
4245547Sbill npxprobe(dvp)
4345624Sbill 	struct isa_device *dvp;
4445624Sbill {	static status, control;
4545547Sbill 
4645547Sbill #ifdef lint
4745547Sbill 	npxintr();
4845547Sbill #endif
4945547Sbill 
5045624Sbill 	/* insure EM bit off */
51*53642Sbostic 	load_cr0(rcr0() & ~CR0_EM);
52*53642Sbostic 
5345624Sbill 	asm("	fninit ");	/* put device in known state */
5445624Sbill 
5545547Sbill 	/* check for a proper status of zero */
5645547Sbill 	status = 0xa5a5;
5745624Sbill 	asm ("	fnstsw	%0 " : "=m" (status) : "m" (status) );
5845547Sbill 
5945547Sbill 	if (status == 0) {
6045547Sbill 
6145547Sbill 		/* good, now check for a proper control word */
6245547Sbill 		control = 0xa5a5;
6345624Sbill 		asm ("	fnstcw %0 " : "=m" (control) : "m" (control));
6445547Sbill 
6545624Sbill 		if ((control&0x103f) == 0x3f) {
6645547Sbill 			/* then we have a numeric coprocessor */
6745547Sbill 		/* XXX should force an exception here to generate an intr */
6845547Sbill 			return (1);
6945547Sbill 		}
7045547Sbill 	}
7145547Sbill 
72*53642Sbostic 	/* insure EM bit on */
73*53642Sbostic 	load_cr0(rcr0() | CR0_EM);
7445547Sbill 	return (0);
7545547Sbill }
7645547Sbill 
7745547Sbill /*
7845547Sbill  * Attach routine - announce which it is, and wire into system
7945547Sbill  */
8045547Sbill npxattach(dvp)
8145624Sbill 	struct isa_device *dvp;
8245547Sbill {
8345547Sbill 
8445624Sbill 	npxinit(0x262);
8545547Sbill 	/* check for ET bit to decide 387/287 */
8649573Swilliam 	npxexists++;
8749573Swilliam 	npx0mask = dvp->id_irq;
8845547Sbill }
8945547Sbill 
9045547Sbill /*
9145547Sbill  * Initialize floating point unit, usually after an error
9245547Sbill  */
9345624Sbill npxinit(control) {
9445547Sbill 
9549573Swilliam 	if (npxexists == 0) return;
9649573Swilliam 
9749573Swilliam 	load_cr0(rcr0() & ~CR0_EM);	/* stop emulating */
9849573Swilliam #ifdef INTEL_COMPAT
9949573Swilliam 	asm ("	finit");
10045624Sbill 	asm("	fldcw %0" : : "g" (control));
10149694Swilliam 	asm("	fnsave %0 " : : "g" (curpcb->pcb_savefpu) );
10249573Swilliam #else
10349573Swilliam 	asm("fninit");
10449694Swilliam 	asm("	fnsave %0 " : : "g" (curpcb->pcb_savefpu) );
10549573Swilliam #endif
10649573Swilliam 	load_cr0(rcr0() | CR0_EM);	/* start emulating */
10745547Sbill 
10845547Sbill }
10945547Sbill 
11045547Sbill /*
11145547Sbill  * Record information needed in processing an exception and clear status word
11245547Sbill  */
113*53642Sbostic npxintr(frame)
114*53642Sbostic 	struct intrframe frame;
115*53642Sbostic {
116*53642Sbostic 	if (npxexists == 0) {
117*53642Sbostic 		printf ("stray npxintr\n");
118*53642Sbostic 		return;
119*53642Sbostic 	}
12045547Sbill 
121*53642Sbostic 	outb(0xf0,0);		/* reset coprocessor */
12249573Swilliam 
12349694Swilliam 	/*
124*53642Sbostic 	 * npxproc may be NULL, if this is a delayed interrupt from
125*53642Sbostic 	 * a process that just exited.
12649694Swilliam 	 */
127*53642Sbostic 	if (npxproc) {
128*53642Sbostic 		/*
129*53642Sbostic 		 * sync state in process context structure, in advance
130*53642Sbostic 		 * of debugger/process looking for it.
131*53642Sbostic 		 */
132*53642Sbostic 		asm("fnsave %0" :: "g" (npxproc->p_addr->u_pcb.pcb_savefpu));
133*53642Sbostic 		psignal(npxproc, SIGFPE);
13445547Sbill 
135*53642Sbostic 		/* clear the exception so we can catch others like it */
136*53642Sbostic 		asm ("	fnclex");
137*53642Sbostic 	}
13845547Sbill }
13945547Sbill 
14045547Sbill /*
14145547Sbill  * Implement device not available (DNA) exception
14245547Sbill  */
143*53642Sbostic npxdna()
144*53642Sbostic {
145*53642Sbostic 	if (npxexists == 0)
146*53642Sbostic 		return(0);
14749573Swilliam 
148*53642Sbostic 	load_cr0(rcr0() & ~CR0_EM);	/* stop emulating */
149*53642Sbostic 	if (npxproc != curproc) {
15051728Swilliam 		if (npxproc)
151*53642Sbostic 			asm(" fnsave %0 "::"g"
152*53642Sbostic 			    (npxproc->p_addr->u_pcb.pcb_savefpu));
15351728Swilliam 		asm("	frstor %0 " : : "g" (curpcb->pcb_savefpu));
15451728Swilliam 		npxproc = curproc;
15551728Swilliam 	}
15651728Swilliam 	return (1);
15745547Sbill }
15845624Sbill #endif
159