xref: /original-bsd/sys/tahoe/math/fpe.c (revision a141c157)
1 /*	fpe.c	1.1	86/01/03	*/
2 
3 #include "../tahoe/psl.h"
4 #include "../tahoe/reg.h"
5 #include "../tahoe/pte.h"
6 #include "../tahoe/mtpr.h"
7 #include "../tahoemath/Kfp.h"
8 
9 #include "param.h"
10 #include "systm.h"
11 #include "dir.h"
12 #include "user.h"
13 #include "proc.h"
14 #include "seg.h"
15 #include "acct.h"
16 #include "kernel.h"
17 
18 /*
19  * Floating point emulation support.
20  */
21 extern	float Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf();
22 extern	double Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd();
23 extern	float Ksinf(), Kcosf(), Katanf(), Klogf(), Ksqrtf(), Kexpf();
24 
25 #define	OP(dop)		((dop) &~ 01)	/* precision-less version of opcode */
26 #define	isdouble(op)	((op) & 01)	/* is opcode double or float */
27 
28 struct	fpetab {
29 	int	fpe_op;		/* base opcode emulating */
30 	float	(*fpe_ffunc)();	/* float version of op */
31 	double	(*fpe_dfunc)();	/* double version of op */
32 } fpetab[] = {
33 	{ OP(CVLD),	Kcvtlf,	Kcvtld },
34 	{ OP(ADDD),	Kaddf,	Kaddd },
35 	{ OP(SUBD),	Ksubf,	Ksubd },
36 	{ OP(MULD),	Kmulf,	Kmuld },
37 	{ OP(DIVD),	Kdivf,	Kdivd },
38 	{ SINF,		Ksinf,	0 },
39 	{ COSF,		Kcosf,	0 },
40 	{ ATANF,	Katanf,	0 },
41 	{ LOGF,		Klogf,	0 },
42 	{ SQRTF,	Ksqrtf,	0 },
43 	{ EXPF,		Kexpf,	0 },
44 };
45 #define	NFPETAB	(sizeof (fpetab) / sizeof (fpetab[0]))
46 
47 /*
48  * Emulate the FP opcode. Update psl as necessary.
49  * If OK, set opcode to 0, else to the FP exception #.
50  * Not all parameter longwords are relevant, depends on opcode.
51  *
52  * The entry mask is set by locore.s so ALL registers are saved.
53  * This enables FP opcodes to change user registers on return.
54  */
55 /* WARNING!!!! THIS CODE MUST NOT PRODUCE ANY FLOATING POINT EXCEPTIONS */
56 /*ARGSUSED*/
57 fpemulate(hfsreg, acc_most, acc_least, dbl, op_most, op_least, opcode, pc, psl)
58 {
59 	int r0, r1;			/* must reserve space */
60 	register int *locr0 = ((int *)&psl)-PS;
61 	register struct fpetab *fp;
62 	int hfs = 0; 			/* returned data about exceptions */
63 	int type;			/* opcode type, FLOAT or DOUBLE */
64 	union { float ff; int fi; } f_res;
65 	union { double dd; int di[2]; } d_res;
66 
67 #ifdef lint
68 	r0 = 0; r0 = r0; r1 = 0; r1 = r1;
69 #endif
70 	type = isdouble(opcode) ? DOUBLE : FLOAT;
71 	for (fp = fpetab; fp < &fpetab[NFPETAB]; fp++)
72 		if ((opcode & 0xfe) == fp->fpe_op)
73 			break;
74 	if (type == DOUBLE) {
75 		if (fp->fpe_dfunc == 0)
76 			fp = &fpetab[NFPETAB];
77 		else
78 			locr0[PS] &= ~PSL_DBL;
79 	}
80 	if (fp >= &fpetab[NFPETAB]) {
81 		opcode = DIV0_EXC;	/* generate SIGILL - XXX */
82 		return;
83 	}
84 	switch (type) {
85 
86 	case DOUBLE:
87 		d_res.dd = (*fp->fpe_dfunc)(acc_most, acc_least, op_most,
88 		    op_least, &hfs);
89 		if (d_res.di[0] == 0 && d_res.di[1] == 0)
90 			locr0[PS] |= PSL_Z;
91 		if (d_res.di[0] < 0)
92 			locr0[PS] |= PSL_N;
93 		break;
94 
95 	case FLOAT:
96 		f_res.ff = (*fp->fpe_ffunc)(acc_most, acc_least, op_most,
97 		    op_least, &hfs);
98 		if (f_res.fi == 0)
99 			locr0[PS] |= PSL_Z;
100 		if (f_res.fi ==  0)
101 			locr0[PS] |= PSL_N;
102 		break;
103 	}
104 	if (hfs & HFS_OVF) {
105 		locr0[PS] |= PSL_V;	/* turn on overflow bit */
106 #ifdef notdef
107 		if (locr0[PS] & PSL_IV)   {  /* overflow enabled? */
108 #endif
109 			opcode = OVF_EXC;
110 			u.u_error = (hfs & HFS_DOM) ? EDOM : ERANGE;
111 			return;
112 #ifdef notdef
113 		}
114 #endif
115 	} else if (hfs & HFS_UNDF) {
116 		if (locr0[PS] &  PSL_FU) {  /* underflow enabled? */
117 			opcode = UNDF_EXC;
118 			u.u_error = (hfs & HFS_DOM) ? EDOM : ERANGE;
119 			return;
120 		}
121 	} else if (hfs & HFS_DIVZ) {
122 		opcode = DIV0_EXC;
123 		return;
124 	} else if (hfs & HFS_DOM)
125 		u.u_error = EDOM;
126 	else if (hfs & HFS_RANGE)
127 		u.u_error = ERANGE;
128 	switch (type) {
129 
130 	case DOUBLE:
131 		if (hfs & (HFS_OVF|HFS_UNDF)) {
132 			d_res.dd = 0.0;
133 			locr0[PS] |= PSL_Z;
134 		}
135 		mvtodacc(d_res.di[0], d_res.di[1], &acc_most);
136 		break;
137 
138 	case FLOAT:
139 		if (hfs & (HFS_OVF|HFS_UNDF)) {
140 			f_res.ff = 0.0;
141 			locr0[PS] |= PSL_Z;
142 		}
143 		mvtofacc(f_res.ff, &acc_most);
144 		break;
145 	}
146 	opcode = 0;
147 }
148