Commit | Line | Data |
---|---|---|
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 | */ | |
20 | extern float Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf(); | |
21 | extern double Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd(); | |
22 | extern 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 | ||
27 | struct 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*/ | |
56 | fpemulate(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 | } |