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