redo include files for kernel reorg
[unix-history] / usr / src / sys / tahoe / math / fpe.c
CommitLineData
a6730a00 1/* fpe.c 1.4 90/12/04 */
4742af8a 2
a6730a00
KB
3#include "../include/psl.h"
4#include "../include/reg.h"
5#include "../include/pte.h"
6#include "../include/mtpr.h"
7#include "../math/Kfp.h"
4742af8a 8
a6730a00
KB
9#include "sys/param.h"
10#include "sys/systm.h"
11#include "sys/user.h"
12#include "sys/proc.h"
13#include "sys/seg.h"
14#include "sys/acct.h"
15#include "sys/kernel.h"
4742af8a
SL
16
17/*
18 * Floating point emulation support.
19 */
20extern float Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf();
21extern double Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd();
22extern float Ksinf(), Kcosf(), Katanf(), Klogf(), Ksqrtf(), Kexpf();
23
24#define OP(dop) ((dop) &~ 01) /* precision-less version of opcode */
25#define isdouble(op) ((op) & 01) /* is opcode double or float */
26
27struct fpetab {
28 int fpe_op; /* base opcode emulating */
29 float (*fpe_ffunc)(); /* float version of op */
30 double (*fpe_dfunc)(); /* double version of op */
31} fpetab[] = {
32 { OP(CVLD), Kcvtlf, Kcvtld },
33 { OP(ADDD), Kaddf, Kaddd },
34 { OP(SUBD), Ksubf, Ksubd },
35 { OP(MULD), Kmulf, Kmuld },
36 { OP(DIVD), Kdivf, Kdivd },
37 { SINF, Ksinf, 0 },
38 { COSF, Kcosf, 0 },
39 { ATANF, Katanf, 0 },
40 { LOGF, Klogf, 0 },
41 { SQRTF, Ksqrtf, 0 },
42 { EXPF, Kexpf, 0 },
43};
44#define NFPETAB (sizeof (fpetab) / sizeof (fpetab[0]))
45
46/*
47 * Emulate the FP opcode. Update psl as necessary.
48 * If OK, set opcode to 0, else to the FP exception #.
49 * Not all parameter longwords are relevant, depends on opcode.
50 *
51 * The entry mask is set by locore.s so ALL registers are saved.
52 * This enables FP opcodes to change user registers on return.
53 */
54/* WARNING!!!! THIS CODE MUST NOT PRODUCE ANY FLOATING POINT EXCEPTIONS */
55/*ARGSUSED*/
56fpemulate(hfsreg, acc_most, acc_least, dbl, op_most, op_least, opcode, pc, psl)
57{
58 int r0, r1; /* must reserve space */
59 register int *locr0 = ((int *)&psl)-PS;
60 register struct fpetab *fp;
61 int hfs = 0; /* returned data about exceptions */
62 int type; /* opcode type, FLOAT or DOUBLE */
63 union { float ff; int fi; } f_res;
64 union { double dd; int di[2]; } d_res;
c8e57b38 65 int error = 0;
4742af8a
SL
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 */
c8e57b38 82 return (0);
4742af8a
SL
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;
c8e57b38 110 return ((hfs & HFS_DOM) ? EDOM : ERANGE);
4742af8a
SL
111#ifdef notdef
112 }
113#endif
114 } else if (hfs & HFS_UNDF) {
115 if (locr0[PS] & PSL_FU) { /* underflow enabled? */
116 opcode = UNDF_EXC;
c8e57b38 117 return ((hfs & HFS_DOM) ? EDOM : ERANGE);
4742af8a
SL
118 }
119 } else if (hfs & HFS_DIVZ) {
120 opcode = DIV0_EXC;
c8e57b38 121 return (0);
4742af8a 122 } else if (hfs & HFS_DOM)
c8e57b38 123 error = EDOM;
4742af8a 124 else if (hfs & HFS_RANGE)
c8e57b38 125 error = ERANGE;
4742af8a
SL
126 switch (type) {
127
128 case DOUBLE:
129 if (hfs & (HFS_OVF|HFS_UNDF)) {
130 d_res.dd = 0.0;
131 locr0[PS] |= PSL_Z;
132 }
133 mvtodacc(d_res.di[0], d_res.di[1], &acc_most);
134 break;
135
136 case FLOAT:
137 if (hfs & (HFS_OVF|HFS_UNDF)) {
138 f_res.ff = 0.0;
139 locr0[PS] |= PSL_Z;
140 }
141 mvtofacc(f_res.ff, &acc_most);
142 break;
143 }
144 opcode = 0;
c8e57b38 145 return (error);
4742af8a 146}