xref: /csrg-svn/sys/tahoe/tahoe/trap.c (revision 24012)
1*24012Ssam /*	trap.c	4.10	84/02/09	*/
2*24012Ssam 
3*24012Ssam #include "../machine/psl.h"
4*24012Ssam #include "../machine/reg.h"
5*24012Ssam #include "../machine/pte.h"
6*24012Ssam 
7*24012Ssam #include "../h/param.h"
8*24012Ssam #include "../h/systm.h"
9*24012Ssam #include "../h/dir.h"
10*24012Ssam #include "../h/user.h"
11*24012Ssam #include "../h/proc.h"
12*24012Ssam #include "../h/seg.h"
13*24012Ssam #include "../machine/trap.h"
14*24012Ssam #include "../h/acct.h"
15*24012Ssam #include "../h/kernel.h"
16*24012Ssam #include "../machine/mtpr.h"
17*24012Ssam #ifdef SYSCALLTRACE
18*24012Ssam #include "../sys/syscalls.c"
19*24012Ssam #endif
20*24012Ssam #include "../machine/fp_in_krnl.h"
21*24012Ssam 
22*24012Ssam #define	USER	040		/* user-mode flag added to type */
23*24012Ssam 
24*24012Ssam struct	sysent	sysent[];
25*24012Ssam int nsysent;
26*24012Ssam 
27*24012Ssam /*
28*24012Ssam  * Called from the trap handler when a processor trap occurs.
29*24012Ssam  */
30*24012Ssam trap(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
31*24012Ssam unsigned code;
32*24012Ssam {
33*24012Ssam 	/* Next 2 dummy variables MUST BE the first local */
34*24012Ssam 	/* variables; leaving place for registers 0 and 1 */
35*24012Ssam 	/* which are not preserved by the 'cct' */
36*24012Ssam 
37*24012Ssam 	int	dumm1;		/* register 1 */
38*24012Ssam 	int	dumm0;		/* register 0 */
39*24012Ssam 	register dumm3;		/* register 12 is the 1'st register variable */
40*24012Ssam 				/* in TAHOE  (register 11 in VAX) */
41*24012Ssam 
42*24012Ssam 	register int *locr0 = ((int *)&psl)-PS;
43*24012Ssam 	register int i;
44*24012Ssam 	register struct proc *p;
45*24012Ssam 	struct timeval syst;
46*24012Ssam 	char	*typename;
47*24012Ssam 
48*24012Ssam 	syst = u.u_ru.ru_stime;
49*24012Ssam 	if (USERMODE(locr0[PS])) {
50*24012Ssam 		type |= USER;
51*24012Ssam 		u.u_ar0 = locr0;
52*24012Ssam 	}
53*24012Ssam 	switch (type) {
54*24012Ssam 
55*24012Ssam 	default: switch (type) {
56*24012Ssam 		case T_RESADFLT:
57*24012Ssam 			typename = "reserved addressing mode";break;
58*24012Ssam 		case T_PRIVINFLT:
59*24012Ssam 			typename = "illegal opcode";break;
60*24012Ssam 		case T_RESOPFLT:
61*24012Ssam 			typename = "reserved operand";break;
62*24012Ssam 		case T_BPTFLT:
63*24012Ssam 			typename = "breakpoint";break;
64*24012Ssam 		case T_SYSCALL:
65*24012Ssam 			typename = "kernel call";break;
66*24012Ssam 		case T_ARITHTRAP:
67*24012Ssam 			typename = "arithmetic exception";break;
68*24012Ssam 		case T_ASTFLT:
69*24012Ssam 			typename = "system forced exception";break;
70*24012Ssam 		case T_SEGFLT:
71*24012Ssam 			typename = "limit fault";break;
72*24012Ssam 		case T_PROTFLT:
73*24012Ssam 			typename = "illegal access type";break;
74*24012Ssam 		case T_TRCTRAP:
75*24012Ssam 			typename = "trace trap";break;
76*24012Ssam 		case T_PAGEFLT:
77*24012Ssam 			typename = "page fault";break;
78*24012Ssam 		case T_TABLEFLT:
79*24012Ssam 			typename = "page table fault";break;
80*24012Ssam 		case T_ALIGNFLT:
81*24012Ssam 			typename = "alignment fault";break;
82*24012Ssam 		case T_KSPNOTVAL:
83*24012Ssam 			typename = "kernel stack not valid";break;
84*24012Ssam 		}
85*24012Ssam 		printf("System trap (%s), code = %x, pc = %x\n",
86*24012Ssam 				typename, code, pc);
87*24012Ssam 		panic("trap");
88*24012Ssam 
89*24012Ssam 	case T_PROTFLT + USER:	/* protection fault */
90*24012Ssam 		i = SIGBUS;
91*24012Ssam 		break;
92*24012Ssam 
93*24012Ssam 	case T_PRIVINFLT + USER:	/* privileged instruction fault */
94*24012Ssam 	case T_RESADFLT + USER:	/* reserved addressing fault */
95*24012Ssam 	case T_RESOPFLT + USER:	/* resereved operand fault */
96*24012Ssam 	case T_ALIGNFLT + USER:	/* unaligned data fault */
97*24012Ssam 		u.u_code = type &~ USER;
98*24012Ssam 		i = SIGILL;
99*24012Ssam 		break;
100*24012Ssam 
101*24012Ssam 	case T_ASTFLT + USER:	/* Allow process switch */
102*24012Ssam 	case T_ASTFLT:
103*24012Ssam 		astoff();
104*24012Ssam 		if ((u.u_procp->p_flag & SOWEUPC) && u.u_prof.pr_scale) {
105*24012Ssam 			addupc(pc, &u.u_prof, 1);
106*24012Ssam 			u.u_procp->p_flag &= ~SOWEUPC;
107*24012Ssam 		}
108*24012Ssam 		goto out;
109*24012Ssam 
110*24012Ssam 	case T_ARITHTRAP + USER:
111*24012Ssam 		u.u_code = code;
112*24012Ssam 		i = SIGFPE;
113*24012Ssam 		break;
114*24012Ssam 
115*24012Ssam 	/*
116*24012Ssam 	 * If the user SP is above the stack segment,
117*24012Ssam 	 * grow the stack automatically.
118*24012Ssam 	 */
119*24012Ssam 	case T_SEGFLT + USER:
120*24012Ssam 		if (grow((unsigned)locr0[SP]) || grow(code))
121*24012Ssam 			goto out;
122*24012Ssam 		i = SIGSEGV;
123*24012Ssam 		break;
124*24012Ssam 
125*24012Ssam 	case T_TABLEFLT:		/* allow page table faults in kernel mode */
126*24012Ssam 	case T_TABLEFLT + USER:   /* page table fault */
127*24012Ssam 		panic("ptable fault");
128*24012Ssam 
129*24012Ssam 	case T_PAGEFLT:		/* allow page faults in kernel mode */
130*24012Ssam 	case T_PAGEFLT + USER:	/* page fault */
131*24012Ssam 		i = u.u_error;
132*24012Ssam 		if(fastreclaim(code) == 0)
133*24012Ssam 			pagein(code, 0);
134*24012Ssam 		u.u_error = i;
135*24012Ssam 		if (type == T_PAGEFLT)
136*24012Ssam 			return;
137*24012Ssam 		goto out;
138*24012Ssam 
139*24012Ssam 	case T_BPTFLT + USER:	/* bpt instruction fault */
140*24012Ssam 	case T_TRCTRAP + USER:	/* trace trap */
141*24012Ssam 		locr0[PS] &= ~PSL_T;
142*24012Ssam 		i = SIGTRAP;
143*24012Ssam 		break;
144*24012Ssam 	case T_KSPNOTVAL:
145*24012Ssam 	case T_KSPNOTVAL + USER:
146*24012Ssam 		i = SIGKILL;	/* There is nothing to do but to kill the
147*24012Ssam 				 * process.. */
148*24012Ssam 		printf("KSP NOT VALID.\n");
149*24012Ssam 		break;
150*24012Ssam 
151*24012Ssam 	}
152*24012Ssam 	psignal(u.u_procp, i);
153*24012Ssam out:
154*24012Ssam 	p = u.u_procp;
155*24012Ssam 	if (p->p_cursig || ISSIG(p))
156*24012Ssam 		psig();
157*24012Ssam 	p->p_pri = p->p_usrpri;
158*24012Ssam 	if (runrun) {
159*24012Ssam 		/*
160*24012Ssam 		 * Since we are u.u_procp, clock will normally just change
161*24012Ssam 		 * our priority without moving us from one queue to another
162*24012Ssam 		 * (since the running process is not on a queue.)
163*24012Ssam 		 * If that happened after we setrq ourselves but before we
164*24012Ssam 		 * swtch()'ed, we might not be on the queue indicated by
165*24012Ssam 		 * our priority.
166*24012Ssam 		 */
167*24012Ssam 		(void) spl8();
168*24012Ssam 		setrq(p);
169*24012Ssam 		u.u_ru.ru_nivcsw++;
170*24012Ssam 		swtch();
171*24012Ssam 	}
172*24012Ssam 	if (u.u_prof.pr_scale) {
173*24012Ssam 		int ticks;
174*24012Ssam 		struct timeval *tv = &u.u_ru.ru_stime;
175*24012Ssam 
176*24012Ssam 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
177*24012Ssam 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
178*24012Ssam 		if (ticks)
179*24012Ssam 			addupc(locr0[PC], &u.u_prof, ticks);
180*24012Ssam 	}
181*24012Ssam 	curpri = p->p_pri;
182*24012Ssam }
183*24012Ssam 
184*24012Ssam #ifdef SYSCALLTRACE
185*24012Ssam int syscalltrace = 0;
186*24012Ssam #endif
187*24012Ssam 
188*24012Ssam /*
189*24012Ssam  * Called from the trap handler when a system call occurs
190*24012Ssam  */
191*24012Ssam syscall(sp, type, hfs, accmst, acclst, dbl, code, pc, psl)
192*24012Ssam unsigned code;
193*24012Ssam {
194*24012Ssam 	/* Next 2 dummy variables MUST BE the first local */
195*24012Ssam 	/* variables; leaving place for registers 0 and 1 */
196*24012Ssam 	/* which are not preserved by the 'cct' */
197*24012Ssam 
198*24012Ssam 	int	dumm1;		/* register 1 */
199*24012Ssam 	int	dumm0;		/* register 0 */
200*24012Ssam 	register dumm3;		/* register 12 is the 1'st register variable */
201*24012Ssam 				/* in TAHOE  (register 11 in VAX) */
202*24012Ssam 
203*24012Ssam 	register int *locr0 = ((int *)&psl)-PS;
204*24012Ssam 	register caddr_t params;		/* known to be r10 below */
205*24012Ssam 	register int i;				/* known to be r9 below */
206*24012Ssam 	register struct sysent *callp;
207*24012Ssam 	register struct proc *p;
208*24012Ssam 	struct	timeval syst;
209*24012Ssam 	int opc;
210*24012Ssam 
211*24012Ssam 	syst = u.u_ru.ru_stime;
212*24012Ssam 	if (!USERMODE(locr0[PS]))
213*24012Ssam 		panic("syscall");
214*24012Ssam 	u.u_ar0 = locr0;
215*24012Ssam 	if (code == 139) {			/* XXX */
216*24012Ssam 		sigcleanup();			/* XXX */
217*24012Ssam 		goto done;			/* XXX */
218*24012Ssam 	}
219*24012Ssam 	params = (caddr_t)locr0[FP] + NBPW;
220*24012Ssam 	u.u_error = 0;
221*24012Ssam 	/*------ DIRTY CODE !!!!!!!!!---------*/
222*24012Ssam 	/* try to reconstruct pc, assuming code is an immediate constant */
223*24012Ssam 	opc = pc - 2;		/* short literal */
224*24012Ssam 	if (code > 0x3f) {
225*24012Ssam 		opc--;	/* byte immediate */
226*24012Ssam 		if (code > 0x7f) {
227*24012Ssam 			opc--;	/* word immediate */
228*24012Ssam 			if (code > 0x7fff)
229*24012Ssam 				opc -= 2;	/* long immediate */
230*24012Ssam 		}
231*24012Ssam 	}
232*24012Ssam 	/*------------------------------------*/
233*24012Ssam 	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
234*24012Ssam 	if (callp == sysent) {
235*24012Ssam 		i = fuword(params);
236*24012Ssam 		params += NBPW;
237*24012Ssam 	callp = (code >= nsysent) ? &sysent[63] : &sysent[code];
238*24012Ssam 	}
239*24012Ssam 	if (i = callp->sy_narg * sizeof (int)) {
240*24012Ssam 		asm("prober $1,(r10),r9");		/* GROT */
241*24012Ssam 		asm("bnequ ok");			/* GROT */
242*24012Ssam 		u.u_error = EFAULT;			/* GROT */
243*24012Ssam 		goto bad;				/* GROT */
244*24012Ssam asm("ok:");						/* GROT */
245*24012Ssam 		bcopy(params,u.u_arg,i);
246*24012Ssam 	}
247*24012Ssam 	u.u_ap = u.u_arg;
248*24012Ssam 	u.u_dirp = (caddr_t)u.u_arg[0];
249*24012Ssam 	u.u_r.r_val1 = 0;
250*24012Ssam 	u.u_r.r_val2 = locr0[R1]; /*------------ CHECK again */
251*24012Ssam 	if (setjmp(&u.u_qsave)) {
252*24012Ssam 		if (u.u_error == 0 && u.u_eosys == JUSTRETURN)
253*24012Ssam 			u.u_error = EINTR;
254*24012Ssam 	} else {
255*24012Ssam 		u.u_eosys = JUSTRETURN;
256*24012Ssam #ifdef SYSCALLTRACE
257*24012Ssam 		if (syscalltrace) {
258*24012Ssam 			register int i;
259*24012Ssam 			char *cp;
260*24012Ssam 
261*24012Ssam 			if (code >= nsysent)
262*24012Ssam 				printf("0x%x", code);
263*24012Ssam 			else
264*24012Ssam 				printf("%s", syscallnames[code]);
265*24012Ssam 			cp = "(";
266*24012Ssam 			for (i= 0; i < callp->sy_narg; i++) {
267*24012Ssam 				printf("%s%x", cp, u.u_arg[i]);
268*24012Ssam 				cp = ", ";
269*24012Ssam 			}
270*24012Ssam 			if (i)
271*24012Ssam 				putchar(')', 0);
272*24012Ssam 			putchar('\n', 0);
273*24012Ssam 		}
274*24012Ssam #endif
275*24012Ssam 
276*24012Ssam 		(*(callp->sy_call))();
277*24012Ssam 	}
278*24012Ssam 	if (u.u_eosys == RESTARTSYS)
279*24012Ssam 		pc = opc;
280*24012Ssam 	else if (u.u_error) {
281*24012Ssam bad:
282*24012Ssam 		locr0[R0] = u.u_error;
283*24012Ssam 		locr0[PS] |= PSL_C;	/* carry bit */
284*24012Ssam 	} else {
285*24012Ssam 		locr0[PS] &= ~PSL_C;	/* clear carry bit */
286*24012Ssam 		locr0[R0] = u.u_r.r_val1;
287*24012Ssam 		locr0[R1] = u.u_r.r_val2;
288*24012Ssam 	}
289*24012Ssam done:
290*24012Ssam 	p = u.u_procp;
291*24012Ssam 	if (p->p_cursig || ISSIG(p))
292*24012Ssam 		psig();
293*24012Ssam 	p->p_pri = p->p_usrpri;
294*24012Ssam 	if (runrun) {
295*24012Ssam 		/*
296*24012Ssam 		 * Since we are u.u_procp, clock will normally just change
297*24012Ssam 		 * our priority without moving us from one queue to another
298*24012Ssam 		 * (since the running process is not on a queue.)
299*24012Ssam 		 * If that happened after we setrq ourselves but before we
300*24012Ssam 		 * swtch()'ed, we might not be on the queue indicated by
301*24012Ssam 		 * our priority.
302*24012Ssam 		 */
303*24012Ssam 		(void) spl8();
304*24012Ssam 		setrq(p);
305*24012Ssam 		u.u_ru.ru_nivcsw++;
306*24012Ssam 		swtch();
307*24012Ssam 	}
308*24012Ssam 	if (u.u_prof.pr_scale) {
309*24012Ssam 		int ticks;
310*24012Ssam 		struct timeval *tv = &u.u_ru.ru_stime;
311*24012Ssam 
312*24012Ssam 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
313*24012Ssam 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
314*24012Ssam 		if (ticks)
315*24012Ssam 			addupc(locr0[PC], &u.u_prof, ticks);
316*24012Ssam 	}
317*24012Ssam 	curpri = p->p_pri;
318*24012Ssam }
319*24012Ssam 
320*24012Ssam /*
321*24012Ssam  * nonexistent system call-- signal process (may want to handle it)
322*24012Ssam  * flag error if process won't see signal immediately
323*24012Ssam  * Q: should we do that all the time ??
324*24012Ssam  */
325*24012Ssam nosys()
326*24012Ssam {
327*24012Ssam 	if (u.u_signal[SIGSYS] == SIG_IGN || u.u_signal[SIGSYS] == SIG_HOLD)
328*24012Ssam 		u.u_error = EINVAL;
329*24012Ssam 	psignal(u.u_procp, SIGSYS);
330*24012Ssam }
331*24012Ssam 
332*24012Ssam /*
333*24012Ssam  * Ignored system call
334*24012Ssam  */
335*24012Ssam nullsys()
336*24012Ssam {
337*24012Ssam 
338*24012Ssam }
339*24012Ssam 
340*24012Ssam fpemulate(hfsreg,acc_most,acc_least,dbl,op_most,op_least,opcode,pc,psl)
341*24012Ssam {
342*24012Ssam /*
343*24012Ssam  * Emulate the F.P. 'opcode'. Update psl flags as necessary.
344*24012Ssam  * If all OK, set 'opcode' to 0, else to the F.P. exception #.
345*24012Ssam  * Not all parameter longwords are relevant - depends on opcode.
346*24012Ssam  *
347*24012Ssam  * The entry mask is set so ALL registers are saved - courtesy of
348*24012Ssam  *  locore.s. This enables F.P. opcodes to change 'user' registers
349*24012Ssam  *  before return.
350*24012Ssam  */
351*24012Ssam 
352*24012Ssam  /* WARNING!!!! THIS CODE MUST NOT PRODUCE ANY FLOATING POINT EXCEPTIONS. */
353*24012Ssam 
354*24012Ssam 	/* Next 2 dummy variables MUST BE the first local */
355*24012Ssam 	/* variables; leaving place for registers 0 and 1 */
356*24012Ssam 	/* which are not preserved by the 'cct' */
357*24012Ssam 
358*24012Ssam 	int	dumm1;		/* register 1 */
359*24012Ssam 	int	dumm0;		/* register 0 */
360*24012Ssam 	register dumm3;		/* register 12 is the 1'st register variable */
361*24012Ssam 				/* in TAHOE  (register 11 in VAX) */
362*24012Ssam 
363*24012Ssam 	register int *locr0 = ((int *)&psl)-PS; /* R11 */
364*24012Ssam 	int hfs = 0; 			/* returned data about exceptions */
365*24012Ssam 	float (*f_proc)();		/* fp procedure to be called.	*/
366*24012Ssam 	double (*d_proc)();		/* fp procedure to be called.	*/
367*24012Ssam 	int dest_type;			/* float or double.	*/
368*24012Ssam 	union{
369*24012Ssam 		float ff;			/* float result. 	*/
370*24012Ssam 		int fi;
371*24012Ssam 	}f_res;
372*24012Ssam 	union{
373*24012Ssam 		double	dd;			/* double result.	*/
374*24012Ssam 		int	di[2] ;
375*24012Ssam 	}d_res;
376*24012Ssam 	extern float 	Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf();
377*24012Ssam 	extern double 	Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd();
378*24012Ssam 	extern float   	Ksinf(), Kcosf(), Katanf(), Klogf(), Ksqrtf(), Kexpf();
379*24012Ssam 
380*24012Ssam 
381*24012Ssam 
382*24012Ssam 	switch(opcode & 0x0FF){
383*24012Ssam 
384*24012Ssam 	case CVLF:	f_proc = Kcvtlf; dest_type = FLOAT;
385*24012Ssam 			locr0[PS] &= ~PSL_DBL;break;	/* clear double bit */
386*24012Ssam 	case CVLD:	d_proc = Kcvtld; dest_type = DOUBLE;
387*24012Ssam 			locr0[PS] |= PSL_DBL; break;	/* turn on double bit */
388*24012Ssam 	case ADDF:	f_proc = Kaddf; dest_type = FLOAT;
389*24012Ssam 			break;
390*24012Ssam 	case ADDD:	d_proc = Kaddd; dest_type = DOUBLE;
391*24012Ssam 			break;
392*24012Ssam 	case SUBF:	f_proc = Ksubf; dest_type = FLOAT;
393*24012Ssam 			break;
394*24012Ssam 	case SUBD:	d_proc = Ksubd; dest_type = DOUBLE;
395*24012Ssam 			break;
396*24012Ssam 	case MULF:	f_proc = Kmulf; dest_type = FLOAT;
397*24012Ssam 			break;
398*24012Ssam 	case MULD:	d_proc = Kmuld; dest_type = DOUBLE;
399*24012Ssam 			break;
400*24012Ssam 	case DIVF:	f_proc = Kdivf; dest_type = FLOAT;
401*24012Ssam 			break;
402*24012Ssam 	case DIVD:	d_proc = Kdivd; dest_type = DOUBLE;
403*24012Ssam 			break;
404*24012Ssam 	case SINF:	f_proc = Ksinf; dest_type = FLOAT;
405*24012Ssam 			break;
406*24012Ssam 	case COSF:	f_proc = Kcosf; dest_type = FLOAT;
407*24012Ssam 			break;
408*24012Ssam 	case ATANF:	f_proc = Katanf; dest_type = FLOAT;
409*24012Ssam 			break;
410*24012Ssam 	case LOGF:	f_proc = Klogf; dest_type = FLOAT;
411*24012Ssam 			break;
412*24012Ssam 	case SQRTF:	f_proc = Ksqrtf; dest_type = FLOAT;
413*24012Ssam 			break;
414*24012Ssam 	case EXPF:	f_proc = Kexpf; dest_type = FLOAT;
415*24012Ssam 			break;
416*24012Ssam 	}
417*24012Ssam 
418*24012Ssam 	switch(dest_type){
419*24012Ssam 
420*24012Ssam 	case FLOAT:
421*24012Ssam 		f_res.ff = (*f_proc)(acc_most,acc_least,op_most,op_least,&hfs);
422*24012Ssam 
423*24012Ssam 		if (f_res.fi == 0 ) locr0[PS] |= PSL_Z;
424*24012Ssam 		if (f_res.fi < 0 ) locr0[PS] |= PSL_N;
425*24012Ssam 		break;
426*24012Ssam 	case DOUBLE:
427*24012Ssam 		d_res.dd = (*d_proc)(acc_most,acc_least,op_most,op_least,&hfs);
428*24012Ssam 		if ((d_res.di[0] == 0) && (d_res.di[1] == 0))
429*24012Ssam 						locr0[PS] |= PSL_Z;
430*24012Ssam 		if (d_res.di[0] < 0 ) locr0[PS] |= PSL_N;
431*24012Ssam 		break;
432*24012Ssam 	}
433*24012Ssam 
434*24012Ssam 	if (hfs & HFS_OVF){
435*24012Ssam 		locr0[PS] |= PSL_V;	/* turn on overflow bit */
436*24012Ssam 		/* if (locr0[PS] & PSL_IV)   {  /* overflow elabled?	*/
437*24012Ssam 			opcode = OVF_EXC;
438*24012Ssam 			u.u_error = (hfs & HFS_DOM) ? EDOM : ERANGE;
439*24012Ssam 			return;
440*24012Ssam 		/*}*/
441*24012Ssam 	}
442*24012Ssam 	else if (hfs & HFS_UNDF){
443*24012Ssam 		if (locr0[PS] & PSL_FU){  /* underflow elabled?	*/
444*24012Ssam 			opcode = UNDF_EXC;
445*24012Ssam 			u.u_error = (hfs & HFS_DOM) ? EDOM : ERANGE;
446*24012Ssam 			return;
447*24012Ssam 		}
448*24012Ssam 	}
449*24012Ssam 	else if (hfs & HFS_DIVZ){
450*24012Ssam 		opcode = DIV0_EXC;
451*24012Ssam 		return;
452*24012Ssam 	}
453*24012Ssam 	else if (hfs & HFS_DOM)
454*24012Ssam 		u.u_error = EDOM;
455*24012Ssam 	else if (hfs & HFS_RANGE)
456*24012Ssam 		u.u_error = ERANGE;
457*24012Ssam 
458*24012Ssam 	switch(dest_type){
459*24012Ssam 	case FLOAT:
460*24012Ssam 		if ((hfs & HFS_OVF) || (hfs & HFS_UNDF)) {
461*24012Ssam 			f_res.ff = 0.0;
462*24012Ssam 			locr0[PS] |= PSL_Z;
463*24012Ssam 		}
464*24012Ssam 		mvtofacc(f_res.ff, &acc_most);
465*24012Ssam 		break;
466*24012Ssam 	case DOUBLE:
467*24012Ssam 		if ((hfs & HFS_OVF) || (hfs & HFS_UNDF)) {
468*24012Ssam 			d_res.dd = 0.0;
469*24012Ssam 			locr0[PS] |= PSL_Z;
470*24012Ssam 		}
471*24012Ssam 		mvtodacc(d_res.di[0], d_res.di[1], &acc_most);
472*24012Ssam 		break;
473*24012Ssam 	}
474*24012Ssam 	opcode=0;
475*24012Ssam }
476