Commit | Line | Data |
---|---|---|
a6d13d53 GCI |
1 | fpemul/\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 40755 \0 0 \0 0 \0 0 5462553466 10470\0 5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/control_w.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 6533 5462320154 12735\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* |
2 | * control_w.h | |
3 | * | |
4 | * | |
5 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
6 | * Vic 3163, Australia. | |
7 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
8 | * All rights reserved. | |
9 | * | |
10 | * This copyright notice covers the redistribution and use of the | |
11 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
12 | * in the 386BSD operating system. Any other use is not permitted | |
13 | * under this copyright. | |
14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must include information specifying | |
21 | * that source code for the emulator is freely available and include | |
22 | * either: | |
23 | * a) an offer to provide the source code for a nominal distribution | |
24 | * fee, or | |
25 | * b) list at least two alternative methods whereby the source | |
26 | * can be obtained, e.g. a publically accessible bulletin board | |
27 | * and an anonymous ftp site from which the software can be | |
28 | * downloaded. | |
29 | * 3. All advertising materials specifically mentioning features or use of | |
30 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
31 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
32 | * products derived from this software without specific prior written | |
33 | * permission. | |
34 | * | |
35 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
36 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
37 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
38 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
39 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
40 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
41 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
42 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
43 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
44 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
45 | * | |
46 | */ | |
47 | ||
48 | #ifndef _CONTROLW_H_ | |
49 | #define _CONTROLW_H_ | |
50 | ||
51 | #ifdef LOCORE | |
52 | #define _Const_(x) $/**/x | |
53 | #else | |
54 | #define _Const_(x) x | |
55 | #endif | |
56 | ||
57 | #define CW_RC _Const_(0x0C00) /* rounding control */ | |
58 | #define CW_PC _Const_(0x0300) /* precision control */ | |
59 | ||
60 | #define CW_Precision Const_(0x0020) /* loss of precision mask */ | |
61 | #define CW_Underflow Const_(0x0010) /* underflow mask */ | |
62 | #define CW_Overflow Const_(0x0008) /* overflow mask */ | |
63 | #define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */ | |
64 | #define CW_Denormal Const_(0x0002) /* denormalized operand mask */ | |
65 | #define CW_Invalid Const_(0x0001) /* invalid operation mask */ | |
66 | ||
67 | #define CW_Exceptions _Const_(0x003f) /* all masks */ | |
68 | ||
69 | #define RC_RND _Const_(0x0000) | |
70 | #define RC_DOWN _Const_(0x0400) | |
71 | #define RC_UP _Const_(0x0800) | |
72 | #define RC_CHOP _Const_(0x0C00) | |
73 | ||
74 | /* p 15-5: Precision control bits affect only the following: | |
75 | ADD, SUB(R), MUL, DIV(R), and SQRT */ | |
76 | #define PR_24_BITS _Const_(0x000) | |
77 | #define PR_53_BITS _Const_(0x200) | |
78 | #define PR_64_BITS _Const_(0x300) | |
79 | /* FULL_PRECISION simulates all exceptions masked */ | |
80 | #define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) | |
81 | ||
82 | #endif /* _CONTROLW_H_ */ | |
83 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_entry.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 41015 5462541274 12757\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
84 | * fpu_entry.c | |
85 | * | |
86 | * The entry function for wm-FPU-emu | |
87 | * | |
88 | * | |
89 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
90 | * Vic 3163, Australia. | |
91 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
92 | * All rights reserved. | |
93 | * | |
94 | * This copyright notice covers the redistribution and use of the | |
95 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
96 | * in the 386BSD operating system. Any other use is not permitted | |
97 | * under this copyright. | |
98 | * | |
99 | * Redistribution and use in source and binary forms, with or without | |
100 | * modification, are permitted provided that the following conditions | |
101 | * are met: | |
102 | * 1. Redistributions of source code must retain the above copyright | |
103 | * notice, this list of conditions and the following disclaimer. | |
104 | * 2. Redistributions in binary form must include information specifying | |
105 | * that source code for the emulator is freely available and include | |
106 | * either: | |
107 | * a) an offer to provide the source code for a nominal distribution | |
108 | * fee, or | |
109 | * b) list at least two alternative methods whereby the source | |
110 | * can be obtained, e.g. a publically accessible bulletin board | |
111 | * and an anonymous ftp site from which the software can be | |
112 | * downloaded. | |
113 | * 3. All advertising materials specifically mentioning features or use of | |
114 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
115 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
116 | * products derived from this software without specific prior written | |
117 | * permission. | |
118 | * | |
119 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
120 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
121 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
122 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
123 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
124 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
125 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
126 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
127 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
128 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
129 | * | |
130 | * | |
131 | * The purpose of the copyright is to ensure that the covered software | |
132 | * remains freely available to everyone. It is felt to be necessary to | |
133 | * try and prevent the software being taken by unscrupulous people and | |
134 | * (perhaps after modification) being copyrighted or otherwise | |
135 | * restricted and being made no longer freely available. There are a | |
136 | * number of examples of corporations hijacking ideas and trying to | |
137 | * sue the pants of lesser financed entities who try to subsequently | |
138 | * use the ideas. | |
139 | * | |
140 | * If the software were placed in the public domain then there would | |
141 | * be no protection at all. By claiming a copyright it puts at least a | |
142 | * strong moral pressure on the greedy to restrain themselves and | |
143 | * behave ethically. And let's not be naive, we are all subject to the | |
144 | * emotion of greed to some extent... | |
145 | * | |
146 | * Up until now, the software has been covered by the GNU copyleft. | |
147 | * That copyright mechanism has problems for operating systems which | |
148 | * are not themselves covered by the GNU copyleft. Hence I have | |
149 | * decided to allow the covered software to be used with 386BSD under | |
150 | * restrictions which are meant to be broadly similar, but not | |
151 | * identical, to those which already cover the 386BSD operating | |
152 | * system. | |
153 | * | |
154 | * The software, in its form for the Linux operating system, remains | |
155 | * available under the terms of the GNU copyleft. | |
156 | * | |
157 | * W. Metzenthen June 1993. | |
158 | */ | |
159 | ||
160 | /*---------------------------------------------------------------------------+ | |
161 | | Note: | | |
162 | | The file contains code which accesses user memory. | | |
163 | | Emulator static data may change when user memory is accessed, due to | | |
164 | | other processes using the emulator while swapping is in progress. | | |
165 | +---------------------------------------------------------------------------*/ | |
166 | ||
167 | /*---------------------------------------------------------------------------+ | |
168 | | math_emulate() is the sole entry point for wm-FPU-emu | | |
169 | +---------------------------------------------------------------------------*/ | |
170 | ||
171 | ||
172 | #include "param.h" | |
173 | #include "systm.h" | |
174 | #include "proc.h" | |
175 | #include "machine/cpu.h" | |
176 | #include "machine/pcb.h" | |
177 | ||
178 | #include "fpu_emu.h" | |
179 | #include "fpu_system.h" | |
180 | #include "exception.h" | |
181 | #include "control_w.h" | |
182 | #include "status_w.h" | |
183 | ||
184 | ||
185 | #define __BAD__ Un_impl /* Not implemented */ | |
186 | ||
187 | #define FPU_LOOKAHEAD 1 /* For performance boost */ | |
188 | ||
189 | #if FPU_LOOKAHEAD != 0 /* I think thet we have to limit the */ | |
190 | #define LOOKAHEAD_LIMIT 7 /* Max number of lookahead instructions*/ | |
191 | #endif /* Or else a prog consisting of a million */ | |
192 | /* fnops will spend all its time in kernel*/ | |
193 | ||
194 | #ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by | |
195 | * default. */ | |
196 | ||
197 | /* WARNING: These codes are not documented by Intel in their 80486 manual | |
198 | and may not work on FPU clones or later Intel FPUs. */ | |
199 | ||
200 | /* Changes to support the un-doc codes provided by Linus Torvalds. */ | |
201 | ||
202 | #define _d9_d8_ fstp_i /* unofficial code (19) */ | |
203 | #define _dc_d0_ fcom_st /* unofficial code (14) */ | |
204 | #define _dc_d8_ fcompst /* unofficial code (1c) */ | |
205 | #define _dd_c8_ fxch_i /* unofficial code (0d) */ | |
206 | #define _de_d0_ fcompst /* unofficial code (16) */ | |
207 | #define _df_c0_ ffreep /* unofficial code (07) ffree + pop */ | |
208 | #define _df_c8_ fxch_i /* unofficial code (0f) */ | |
209 | #define _df_d0_ fstp_i /* unofficial code (17) */ | |
210 | #define _df_d8_ fstp_i /* unofficial code (1f) */ | |
211 | ||
212 | static FUNC st_instr_table[64] = { | |
213 | fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_, | |
214 | fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_, | |
215 | fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_, | |
216 | fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_, | |
217 | fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, | |
218 | fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, | |
219 | fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, | |
220 | fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, | |
221 | }; | |
222 | #else /* Support only documented FPU op-codes */ | |
223 | ||
224 | static FUNC st_instr_table[64] = { | |
225 | fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__, | |
226 | fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__, | |
227 | fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__, | |
228 | fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__, | |
229 | fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, | |
230 | fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, | |
231 | fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, | |
232 | fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, | |
233 | }; | |
234 | #endif /* NO_UNDOC_CODE */ | |
235 | ||
236 | ||
237 | #define _NONE_ 0 /* Take no special action */ | |
238 | #define _REG0_ 1 /* Need to check for not empty st(0) */ | |
239 | #define _REGI_ 2 /* Need to check for not empty st(0) and | |
240 | * st(rm) */ | |
241 | #define _REGi_ 0 /* Uses st(rm) */ | |
242 | #define _PUSH_ 3 /* Need to check for space to push onto stack */ | |
243 | #define _null_ 4 /* Function illegal or not implemented */ | |
244 | #define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */ | |
245 | #define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) | |
246 | * then pop */ | |
247 | #define _REGIc 0 /* Compare st(0) and st(rm) */ | |
248 | #define _REGIn 0 /* Uses st(0) and st(rm), but handle checks | |
249 | * later */ | |
250 | ||
251 | #ifndef NO_UNDOC_CODE | |
252 | ||
253 | /* Un-documented FPU op-codes supported by default. (see above) */ | |
254 | ||
255 | static unsigned char type_table[64] = { | |
256 | _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_, | |
257 | _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_, | |
258 | _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, | |
259 | _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, | |
260 | _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, | |
261 | _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, | |
262 | _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, | |
263 | _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ | |
264 | }; | |
265 | #else /* Support only documented FPU op-codes */ | |
266 | ||
267 | static unsigned char type_table[64] = { | |
268 | _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_, | |
269 | _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_, | |
270 | _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_, | |
271 | _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_, | |
272 | _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, | |
273 | _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, | |
274 | _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, | |
275 | _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ | |
276 | }; | |
277 | #endif /* NO_UNDOC_CODE */ | |
278 | ||
279 | /* Be careful when using any of these global variables... | |
280 | they might change if swapping is triggered */ | |
281 | unsigned char FPU_rm; | |
282 | char FPU_st0_tag; | |
283 | FPU_REG *FPU_st0_ptr; | |
284 | ||
285 | #ifdef PARANOID | |
286 | char emulating = 0; | |
287 | #endif /* PARANOID */ | |
288 | ||
289 | #define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x)) | |
290 | #define math_abort(signo) \ | |
291 | FPU_EIP = FPU_ORIG_EIP;REENTRANT_CHECK(OFF);return(signo); | |
292 | ||
293 | int | |
294 | math_emulate(struct trapframe * tframe) | |
295 | { | |
296 | ||
297 | unsigned char FPU_modrm; | |
298 | unsigned short code; | |
299 | #ifdef LOOKAHEAD_LIMIT | |
300 | int lookahead_limit = LOOKAHEAD_LIMIT; | |
301 | #endif | |
302 | #ifdef PARANOID | |
303 | if (emulating) { | |
304 | printf("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); | |
305 | } | |
306 | REENTRANT_CHECK(ON); | |
307 | #endif /* PARANOID */ | |
308 | ||
309 | if ((((struct pcb *) curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) { | |
310 | finit(); | |
311 | ((struct pcb *) curproc->p_addr)->pcb_flags |= FP_SOFTFP; | |
312 | } | |
313 | FPU_info = tframe; | |
314 | FPU_ORIG_EIP = FPU_EIP; /* --pink-- */ | |
315 | ||
316 | if (FPU_CS != 0x001f) { | |
317 | printf("math_emulate: %x : %x\n", FPU_CS, FPU_EIP); | |
318 | panic("FPU emulation in kernel"); | |
319 | } | |
320 | #ifdef notyet | |
321 | /* We cannot handle emulation in v86-mode */ | |
322 | if (FPU_EFLAGS & 0x00020000) { | |
323 | FPU_ORIG_EIP = FPU_EIP; | |
324 | math_abort(FPU_info, SIGILL); | |
325 | } | |
326 | #endif | |
327 | ||
328 | FPU_lookahead = FPU_LOOKAHEAD; | |
329 | #if notnow /* I dont know that much of traceing. Is it right? --pink-- */ | |
330 | if (curproc->p_flag & STRC) | |
331 | FPU_lookahead = 0; | |
332 | #endif | |
333 | ||
334 | do_another_FPU_instruction: | |
335 | ||
336 | REENTRANT_CHECK(OFF); | |
337 | code = fuword((u_int *) FPU_EIP); | |
338 | REENTRANT_CHECK(ON); | |
339 | if ((code & 0xff) == 0x9b) { /* fwait */ | |
340 | if (status_word & SW_Summary) | |
341 | goto do_the_FPU_interrupt; | |
342 | else { | |
343 | FPU_EIP++; | |
344 | goto FPU_instruction_done; | |
345 | } | |
346 | } | |
347 | if (status_word & SW_Summary) { | |
348 | /* Ignore the error for now if the current instruction is a | |
349 | * no-wait control instruction */ | |
350 | /* The 80486 manual contradicts itself on this topic, so I use | |
351 | * the following list of such instructions until I can check | |
352 | * on a real 80486: fninit, fnstenv, fnsave, fnstsw, fnstenv, | |
353 | * fnclex. */ | |
354 | if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit, | |
355 | * fnstsw */ | |
356 | (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, | |
357 | * fnstenv, fnstsw */ | |
358 | ((code & 0xc000) != 0xc000))))) { | |
359 | /* This is a guess about what a real FPU might do to | |
360 | * this bit: */ | |
361 | /* status_word &= ~SW_Summary; ****/ | |
362 | ||
363 | /* We need to simulate the action of the kernel to FPU | |
364 | * interrupts here. Currently, the "real FPU" part of | |
365 | * the kernel (0.99.10) clears the exception flags, | |
366 | * sets the registers to empty, and passes information | |
367 | * back to the interrupted process via the cs selector | |
368 | * and operand selector, so we do the same. */ | |
369 | do_the_FPU_interrupt: | |
370 | cs_selector &= 0xffff0000; | |
371 | cs_selector |= (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift); | |
372 | operand_selector = tag_word(); | |
373 | status_word = 0; | |
374 | top = 0; | |
375 | { | |
376 | int r; | |
377 | for (r = 0; r < 8; r++) { | |
378 | regs[r].tag = TW_Empty; | |
379 | } | |
380 | } | |
381 | REENTRANT_CHECK(OFF); | |
382 | math_abort(SIGFPE); | |
383 | } | |
384 | } | |
385 | FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP; | |
386 | ||
387 | if ((code & 0xff) == 0x66) { /* size prefix */ | |
388 | FPU_EIP++; | |
389 | REENTRANT_CHECK(OFF); | |
390 | code = fuword((u_int *) FPU_EIP); | |
391 | REENTRANT_CHECK(ON); | |
392 | } | |
393 | FPU_EIP += 2; | |
394 | ||
395 | FPU_modrm = code >> 8; | |
396 | FPU_rm = FPU_modrm & 7; | |
397 | ||
398 | if (FPU_modrm < 0300) { | |
399 | /* All of these instructions use the mod/rm byte to get a data | |
400 | * address */ | |
401 | get_address(FPU_modrm); | |
402 | if (!(code & 1)) { | |
403 | unsigned short status1 = status_word; | |
404 | FPU_st0_ptr = &st(0); | |
405 | FPU_st0_tag = FPU_st0_ptr->tag; | |
406 | ||
407 | /* Stack underflow has priority */ | |
408 | if (NOT_EMPTY_0) { | |
409 | switch ((code >> 1) & 3) { | |
410 | case 0: | |
411 | reg_load_single(); | |
412 | break; | |
413 | case 1: | |
414 | reg_load_int32(); | |
415 | break; | |
416 | case 2: | |
417 | reg_load_double(); | |
418 | break; | |
419 | case 3: | |
420 | reg_load_int16(); | |
421 | break; | |
422 | } | |
423 | ||
424 | /* No more access to user memory, it is safe | |
425 | * to use static data now */ | |
426 | FPU_st0_ptr = &st(0); | |
427 | FPU_st0_tag = FPU_st0_ptr->tag; | |
428 | ||
429 | /* NaN operands have the next priority. */ | |
430 | /* We have to delay looking at st(0) until | |
431 | * after loading the data, because that data | |
432 | * might contain an SNaN */ | |
433 | if ((FPU_st0_tag == TW_NaN) || | |
434 | (FPU_loaded_data.tag == TW_NaN)) { | |
435 | /* Restore the status word; we might | |
436 | * have loaded a denormal. */ | |
437 | status_word = status1; | |
438 | if ((FPU_modrm & 0x30) == 0x10) { | |
439 | /* fcom or fcomp */ | |
440 | EXCEPTION(EX_Invalid); | |
441 | setcc(SW_C3 | SW_C2 | SW_C0); | |
442 | if (FPU_modrm & 0x08) | |
443 | pop(); /* fcomp, so we pop. */ | |
444 | } else | |
445 | real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr); | |
446 | goto reg_mem_instr_done; | |
447 | } | |
448 | switch ((FPU_modrm >> 3) & 7) { | |
449 | case 0: /* fadd */ | |
450 | reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word); | |
451 | break; | |
452 | case 1: /* fmul */ | |
453 | reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word); | |
454 | break; | |
455 | case 2: /* fcom */ | |
456 | compare_st_data(); | |
457 | break; | |
458 | case 3: /* fcomp */ | |
459 | compare_st_data(); | |
460 | pop(); | |
461 | break; | |
462 | case 4: /* fsub */ | |
463 | reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word); | |
464 | break; | |
465 | case 5: /* fsubr */ | |
466 | reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word); | |
467 | break; | |
468 | case 6: /* fdiv */ | |
469 | reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word); | |
470 | break; | |
471 | case 7: /* fdivr */ | |
472 | if (FPU_st0_tag == TW_Zero) | |
473 | status_word = status1; /* Undo any denorm tag, | |
474 | * zero-divide has | |
475 | * priority. */ | |
476 | reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word); | |
477 | break; | |
478 | } | |
479 | } else { | |
480 | if ((FPU_modrm & 0x30) == 0x10) { | |
481 | /* The instruction is fcom or fcomp */ | |
482 | EXCEPTION(EX_StackUnder); | |
483 | setcc(SW_C3 | SW_C2 | SW_C0); | |
484 | if (FPU_modrm & 0x08) | |
485 | pop(); /* fcomp, Empty or not, | |
486 | * we pop. */ | |
487 | } else | |
488 | stack_underflow(); | |
489 | } | |
490 | } else { | |
491 | load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1); | |
492 | } | |
493 | ||
494 | reg_mem_instr_done: | |
495 | ||
496 | data_operand_offset = (unsigned long) FPU_data_address; | |
497 | } else { | |
498 | /* None of these instructions access user memory */ | |
499 | unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7); | |
500 | ||
501 | FPU_st0_ptr = &st(0); | |
502 | FPU_st0_tag = FPU_st0_ptr->tag; | |
503 | switch (type_table[(int) instr_index]) { | |
504 | case _NONE_: /* also _REGIc: _REGIn */ | |
505 | break; | |
506 | case _REG0_: | |
507 | if (!NOT_EMPTY_0) { | |
508 | stack_underflow(); | |
509 | goto FPU_instruction_done; | |
510 | } | |
511 | break; | |
512 | case _REGIi: | |
513 | if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) { | |
514 | stack_underflow_i(FPU_rm); | |
515 | goto FPU_instruction_done; | |
516 | } | |
517 | break; | |
518 | case _REGIp: | |
519 | if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) { | |
520 | stack_underflow_i(FPU_rm); | |
521 | pop(); | |
522 | goto FPU_instruction_done; | |
523 | } | |
524 | break; | |
525 | case _REGI_: | |
526 | if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) { | |
527 | stack_underflow(); | |
528 | goto FPU_instruction_done; | |
529 | } | |
530 | break; | |
531 | case _PUSH_: /* Only used by the fld st(i) instruction */ | |
532 | break; | |
533 | case _null_: | |
534 | Un_impl(); | |
535 | goto FPU_instruction_done; | |
536 | default: | |
537 | EXCEPTION(EX_INTERNAL | 0x111); | |
538 | goto FPU_instruction_done; | |
539 | } | |
540 | (*st_instr_table[(int) instr_index]) (); | |
541 | } | |
542 | ||
543 | FPU_instruction_done: | |
544 | ||
545 | ip_offset = FPU_entry_eip; | |
546 | bswapw(code); | |
547 | *(1 + (unsigned short *) &cs_selector) = code & 0x7ff; | |
548 | ||
549 | #ifdef DEBUG | |
550 | REENTRANT_CHECK(OFF); | |
551 | emu_printall(); | |
552 | REENTRANT_CHECK(ON); | |
553 | #endif /* DEBUG */ | |
554 | #ifdef LOOKAHEAD_LIMIT | |
555 | if (--lookahead_limit) | |
556 | #endif | |
557 | if (FPU_lookahead) { | |
558 | unsigned char next; | |
559 | ||
560 | /* (This test should generate no machine code) */ | |
561 | while (1) { | |
562 | REENTRANT_CHECK(OFF); | |
563 | next = fubyte((u_char *) FPU_EIP); | |
564 | REENTRANT_CHECK(ON); | |
565 | if (((next & 0xf8) == 0xd8) || (next == 0x9b)) { /* fwait */ | |
566 | goto do_another_FPU_instruction; | |
567 | } else | |
568 | if (next == 0x66) { /* size prefix */ | |
569 | REENTRANT_CHECK(OFF); | |
570 | next = fubyte((u_char *) (FPU_EIP + 1)); | |
571 | REENTRANT_CHECK(ON); | |
572 | if ((next & 0xf8) == 0xd8) { | |
573 | FPU_EIP++; | |
574 | goto do_another_FPU_instruction; | |
575 | } | |
576 | } | |
577 | break; | |
578 | } | |
579 | } | |
580 | REENTRANT_CHECK(OFF); | |
581 | return (0); /* --pink-- */ | |
582 | } | |
583 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/errors.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 35403 5462512042 12253\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
584 | * errors.c | |
585 | * | |
586 | * The error handling functions for wm-FPU-emu | |
587 | * | |
588 | * | |
589 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
590 | * Vic 3163, Australia. | |
591 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
592 | * All rights reserved. | |
593 | * | |
594 | * This copyright notice covers the redistribution and use of the | |
595 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
596 | * in the 386BSD operating system. Any other use is not permitted | |
597 | * under this copyright. | |
598 | * | |
599 | * Redistribution and use in source and binary forms, with or without | |
600 | * modification, are permitted provided that the following conditions | |
601 | * are met: | |
602 | * 1. Redistributions of source code must retain the above copyright | |
603 | * notice, this list of conditions and the following disclaimer. | |
604 | * 2. Redistributions in binary form must include information specifying | |
605 | * that source code for the emulator is freely available and include | |
606 | * either: | |
607 | * a) an offer to provide the source code for a nominal distribution | |
608 | * fee, or | |
609 | * b) list at least two alternative methods whereby the source | |
610 | * can be obtained, e.g. a publically accessible bulletin board | |
611 | * and an anonymous ftp site from which the software can be | |
612 | * downloaded. | |
613 | * 3. All advertising materials specifically mentioning features or use of | |
614 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
615 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
616 | * products derived from this software without specific prior written | |
617 | * permission. | |
618 | * | |
619 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
620 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
621 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
622 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
623 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
624 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
625 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
626 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
627 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
628 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
629 | * | |
630 | */ | |
631 | ||
632 | /*---------------------------------------------------------------------------+ | |
633 | | Note: | | |
634 | | The file contains code which accesses user memory. | | |
635 | | Emulator static data may change when user memory is accessed, due to | | |
636 | | other processes using the emulator while swapping is in progress. | | |
637 | +---------------------------------------------------------------------------*/ | |
638 | ||
639 | ||
640 | ||
641 | ||
642 | ||
643 | #include "param.h" | |
644 | #include "proc.h" | |
645 | #include "machine/cpu.h" | |
646 | #include "machine/pcb.h" | |
647 | ||
648 | #include "fpu_emu.h" | |
649 | #include "fpu_system.h" | |
650 | #include "exception.h" | |
651 | #include "status_w.h" | |
652 | #include "control_w.h" | |
653 | #include "reg_constant.h" | |
654 | #include "version.h" | |
655 | ||
656 | /* */ | |
657 | #undef PRINT_MESSAGES | |
658 | /* */ | |
659 | ||
660 | ||
661 | void | |
662 | Un_impl(void) | |
663 | { | |
664 | unsigned char byte1, FPU_modrm; | |
665 | ||
666 | REENTRANT_CHECK(OFF); | |
667 | byte1 = fubyte((unsigned char *) FPU_ORIG_EIP); | |
668 | FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP); | |
669 | ||
670 | printf("Unimplemented FPU Opcode at eip=%p : %02x ", | |
671 | FPU_ORIG_EIP, byte1); | |
672 | ||
673 | if (FPU_modrm >= 0300) | |
674 | printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); | |
675 | else | |
676 | printf("/%d\n", (FPU_modrm >> 3) & 7); | |
677 | REENTRANT_CHECK(ON); | |
678 | ||
679 | EXCEPTION(EX_Invalid); | |
680 | ||
681 | } | |
682 | ||
683 | ||
684 | ||
685 | ||
686 | void | |
687 | emu_printall() | |
688 | { | |
689 | int i; | |
690 | static char *tag_desc[] = {"Valid", "Zero", "ERROR", "ERROR", | |
691 | "DeNorm", "Inf", "NaN", "Empty"}; | |
692 | unsigned char byte1, FPU_modrm; | |
693 | ||
694 | REENTRANT_CHECK(OFF); | |
695 | byte1 = fubyte((unsigned char *) FPU_ORIG_EIP); | |
696 | FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP); | |
697 | ||
698 | #ifdef DEBUGGING | |
699 | if (status_word & SW_Backward) | |
700 | printf("SW: backward compatibility\n"); | |
701 | if (status_word & SW_C3) | |
702 | printf("SW: condition bit 3\n"); | |
703 | if (status_word & SW_C2) | |
704 | printf("SW: condition bit 2\n"); | |
705 | if (status_word & SW_C1) | |
706 | printf("SW: condition bit 1\n"); | |
707 | if (status_word & SW_C0) | |
708 | printf("SW: condition bit 0\n"); | |
709 | if (status_word & SW_Summary) | |
710 | printf("SW: exception summary\n"); | |
711 | if (status_word & SW_Stack_Fault) | |
712 | printf("SW: stack fault\n"); | |
713 | if (status_word & SW_Precision) | |
714 | printf("SW: loss of precision\n"); | |
715 | if (status_word & SW_Underflow) | |
716 | printf("SW: underflow\n"); | |
717 | if (status_word & SW_Overflow) | |
718 | printf("SW: overflow\n"); | |
719 | if (status_word & SW_Zero_Div) | |
720 | printf("SW: divide by zero\n"); | |
721 | if (status_word & SW_Denorm_Op) | |
722 | printf("SW: denormalized operand\n"); | |
723 | if (status_word & SW_Invalid) | |
724 | printf("SW: invalid operation\n"); | |
725 | #endif /* DEBUGGING */ | |
726 | ||
727 | status_word = status_word & ~SW_Top; | |
728 | status_word |= (top & 7) << SW_Top_Shift; | |
729 | ||
730 | printf("At %p: %02x ", FPU_ORIG_EIP, byte1); | |
731 | if (FPU_modrm >= 0300) | |
732 | printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); | |
733 | else | |
734 | printf("/%d, mod=%d rm=%d\n", | |
735 | (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); | |
736 | ||
737 | printf(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", | |
738 | status_word & 0x8000 ? 1 : 0, /* busy */ | |
739 | (status_word & 0x3800) >> 11, /* stack top pointer */ | |
740 | status_word & 0x80 ? 1 : 0, /* Error summary status */ | |
741 | status_word & 0x40 ? 1 : 0, /* Stack flag */ | |
742 | status_word & SW_C3 ? 1 : 0, status_word & SW_C2 ? 1 : 0, /* cc */ | |
743 | status_word & SW_C1 ? 1 : 0, status_word & SW_C0 ? 1 : 0, /* cc */ | |
744 | status_word & SW_Precision ? 1 : 0, status_word & SW_Underflow ? 1 : 0, | |
745 | status_word & SW_Overflow ? 1 : 0, status_word & SW_Zero_Div ? 1 : 0, | |
746 | status_word & SW_Denorm_Op ? 1 : 0, status_word & SW_Invalid ? 1 : 0); | |
747 | ||
748 | printf(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n", | |
749 | control_word & 0x1000 ? 1 : 0, | |
750 | (control_word & 0x800) >> 11, (control_word & 0x400) >> 10, | |
751 | (control_word & 0x200) >> 9, (control_word & 0x100) >> 8, | |
752 | control_word & 0x80 ? 1 : 0, | |
753 | control_word & SW_Precision ? 1 : 0, control_word & SW_Underflow ? 1 : 0, | |
754 | control_word & SW_Overflow ? 1 : 0, control_word & SW_Zero_Div ? 1 : 0, | |
755 | control_word & SW_Denorm_Op ? 1 : 0, control_word & SW_Invalid ? 1 : 0); | |
756 | ||
757 | for (i = 0; i < 8; i++) { | |
758 | FPU_REG *r = &st(i); | |
759 | switch (r->tag) { | |
760 | case TW_Empty: | |
761 | continue; | |
762 | break; | |
763 | case TW_Zero: | |
764 | printf("st(%d) %c .0000 0000 0000 0000 ", | |
765 | i, r->sign ? '-' : '+'); | |
766 | break; | |
767 | case TW_Valid: | |
768 | case TW_NaN: | |
769 | case TW_Denormal: | |
770 | case TW_Infinity: | |
771 | printf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i, | |
772 | r->sign ? '-' : '+', | |
773 | (long) (r->sigh >> 16), | |
774 | (long) (r->sigh & 0xFFFF), | |
775 | (long) (r->sigl >> 16), | |
776 | (long) (r->sigl & 0xFFFF), | |
777 | r->exp - EXP_BIAS + 1); | |
778 | break; | |
779 | default: | |
780 | printf("Whoops! Error in errors.c "); | |
781 | break; | |
782 | } | |
783 | printf("%s\n", tag_desc[(int) (unsigned) r->tag]); | |
784 | } | |
785 | ||
786 | printf("[data] %c .%04x %04x %04x %04x e%+-6d ", | |
787 | FPU_loaded_data.sign ? '-' : '+', | |
788 | (long) (FPU_loaded_data.sigh >> 16), | |
789 | (long) (FPU_loaded_data.sigh & 0xFFFF), | |
790 | (long) (FPU_loaded_data.sigl >> 16), | |
791 | (long) (FPU_loaded_data.sigl & 0xFFFF), | |
792 | FPU_loaded_data.exp - EXP_BIAS + 1); | |
793 | printf("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]); | |
794 | REENTRANT_CHECK(ON); | |
795 | ||
796 | } | |
797 | ||
798 | static struct { | |
799 | int type; | |
800 | char *name; | |
801 | } exception_names[] = { | |
802 | { | |
803 | EX_StackOver, "stack overflow" | |
804 | }, | |
805 | { | |
806 | EX_StackUnder, "stack underflow" | |
807 | }, | |
808 | { | |
809 | EX_Precision, "loss of precision" | |
810 | }, | |
811 | { | |
812 | EX_Underflow, "underflow" | |
813 | }, | |
814 | { | |
815 | EX_Overflow, "overflow" | |
816 | }, | |
817 | { | |
818 | EX_ZeroDiv, "divide by zero" | |
819 | }, | |
820 | { | |
821 | EX_Denormal, "denormalized operand" | |
822 | }, | |
823 | { | |
824 | EX_Invalid, "invalid operation" | |
825 | }, | |
826 | { | |
827 | EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION | |
828 | }, | |
829 | { | |
830 | 0, NULL | |
831 | } | |
832 | }; | |
833 | /* | |
834 | EX_INTERNAL is always given with a code which indicates where the | |
835 | error was detected. | |
836 | ||
837 | Internal error types: | |
838 | 0x14 in e14.c | |
839 | 0x1nn in a *.c file: | |
840 | 0x101 in reg_add_sub.c | |
841 | 0x102 in reg_mul.c | |
842 | 0x103 in poly_sin.c | |
843 | 0x104 in poly_tan.c | |
844 | 0x105 in reg_mul.c | |
845 | 0x106 in reg_mov.c | |
846 | 0x107 in fpu_trig.c | |
847 | 0x108 in reg_compare.c | |
848 | 0x109 in reg_compare.c | |
849 | 0x110 in reg_add_sub.c | |
850 | 0x111 in interface.c | |
851 | 0x112 in fpu_trig.c | |
852 | 0x113 in reg_add_sub.c | |
853 | 0x114 in reg_ld_str.c | |
854 | 0x115 in fpu_trig.c | |
855 | 0x116 in fpu_trig.c | |
856 | 0x117 in fpu_trig.c | |
857 | 0x118 in fpu_trig.c | |
858 | 0x119 in fpu_trig.c | |
859 | 0x120 in poly_atan.c | |
860 | 0x121 in reg_compare.c | |
861 | 0x122 in reg_compare.c | |
862 | 0x123 in reg_compare.c | |
863 | 0x2nn in an *.s file: | |
864 | 0x201 in reg_u_add.S | |
865 | 0x202 in reg_u_div.S | |
866 | 0x203 in reg_u_div.S | |
867 | 0x204 in reg_u_div.S | |
868 | 0x205 in reg_u_mul.S | |
869 | 0x206 in reg_u_sub.S | |
870 | 0x207 in wm_sqrt.S | |
871 | 0x208 in reg_div.S | |
872 | 0x209 in reg_u_sub.S | |
873 | 0x210 in reg_u_sub.S | |
874 | 0x211 in reg_u_sub.S | |
875 | 0x212 in reg_u_sub.S | |
876 | 0x213 in wm_sqrt.S | |
877 | 0x214 in wm_sqrt.S | |
878 | 0x215 in wm_sqrt.S | |
879 | 0x216 in reg_round.S | |
880 | 0x217 in reg_round.S | |
881 | 0x218 in reg_round.S | |
882 | */ | |
883 | ||
884 | void | |
885 | exception(int n) | |
886 | { | |
887 | int i, int_type; | |
888 | ||
889 | int_type = 0; /* Needed only to stop compiler warnings */ | |
890 | if (n & EX_INTERNAL) { | |
891 | int_type = n - EX_INTERNAL; | |
892 | n = EX_INTERNAL; | |
893 | /* Set lots of exception bits! */ | |
894 | status_word |= (SW_Exc_Mask | SW_Summary | FPU_BUSY); | |
895 | } else { | |
896 | /* Extract only the bits which we use to set the status word */ | |
897 | n &= (SW_Exc_Mask); | |
898 | /* Set the corresponding exception bit */ | |
899 | status_word |= n; | |
900 | if (status_word & ~control_word & CW_Exceptions) | |
901 | status_word |= SW_Summary; | |
902 | if (n & (SW_Stack_Fault | EX_Precision)) { | |
903 | if (!(n & SW_C1)) | |
904 | /* This bit distinguishes over- from underflow | |
905 | * for a stack fault, and roundup from | |
906 | * round-down for precision loss. */ | |
907 | status_word &= ~SW_C1; | |
908 | } | |
909 | } | |
910 | ||
911 | REENTRANT_CHECK(OFF); | |
912 | if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) { | |
913 | #ifdef PRINT_MESSAGES | |
914 | /* My message from the sponsor */ | |
915 | printf(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n"); | |
916 | #endif /* PRINT_MESSAGES */ | |
917 | ||
918 | /* Get a name string for error reporting */ | |
919 | for (i = 0; exception_names[i].type; i++) | |
920 | if ((exception_names[i].type & n) == exception_names[i].type) | |
921 | break; | |
922 | ||
923 | if (exception_names[i].type) { | |
924 | #ifdef PRINT_MESSAGES | |
925 | printf("FP Exception: %s!\n", exception_names[i].name); | |
926 | #endif /* PRINT_MESSAGES */ | |
927 | } else | |
928 | printf("FP emulator: Unknown Exception: 0x%04x!\n", n); | |
929 | ||
930 | if (n == EX_INTERNAL) { | |
931 | printf("FP emulator: Internal error type 0x%04x\n", int_type); | |
932 | emu_printall(); | |
933 | } | |
934 | #ifdef PRINT_MESSAGES | |
935 | else | |
936 | emu_printall(); | |
937 | #endif /* PRINT_MESSAGES */ | |
938 | ||
939 | /* The 80486 generates an interrupt on the next non-control | |
940 | * FPU instruction. So we need some means of flagging it. We | |
941 | * use the ES (Error Summary) bit for this, assuming that this | |
942 | * is the way a real FPU does it (until I can check it out), | |
943 | * if not, then some method such as the following kludge might | |
944 | * be needed. */ | |
945 | /* regs[0].tag |= TW_FPU_Interrupt; */ | |
946 | } | |
947 | REENTRANT_CHECK(ON); | |
948 | ||
949 | #ifdef __DEBUG__ | |
950 | math_abort(SIGFPE); | |
951 | #endif /* __DEBUG__ */ | |
952 | ||
953 | } | |
954 | ||
955 | ||
956 | /* Real operation attempted on two operands, one a NaN */ | |
957 | void | |
958 | real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest) | |
959 | { | |
960 | FPU_REG *x; | |
961 | int signalling; | |
962 | ||
963 | x = a; | |
964 | if (a->tag == TW_NaN) { | |
965 | if (b->tag == TW_NaN) { | |
966 | signalling = !(a->sigh & b->sigh & 0x40000000); | |
967 | /* find the "larger" */ | |
968 | if (*(long long *) &(a->sigl) < *(long long *) &(b->sigl)) | |
969 | x = b; | |
970 | } else { | |
971 | /* return the quiet version of the NaN in a */ | |
972 | signalling = !(a->sigh & 0x40000000); | |
973 | } | |
974 | } else | |
975 | #ifdef PARANOID | |
976 | if (b->tag == TW_NaN) | |
977 | #endif /* PARANOID */ | |
978 | { | |
979 | signalling = !(b->sigh & 0x40000000); | |
980 | x = b; | |
981 | } | |
982 | #ifdef PARANOID | |
983 | else { | |
984 | signalling = 0; | |
985 | EXCEPTION(EX_INTERNAL | 0x113); | |
986 | x = &CONST_QNaN; | |
987 | } | |
988 | #endif /* PARANOID */ | |
989 | ||
990 | if (!signalling) { | |
991 | if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */ | |
992 | x = &CONST_QNaN; | |
993 | reg_move(x, dest); | |
994 | return; | |
995 | } | |
996 | if (control_word & CW_Invalid) { | |
997 | /* The masked response */ | |
998 | if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */ | |
999 | x = &CONST_QNaN; | |
1000 | reg_move(x, dest); | |
1001 | /* ensure a Quiet NaN */ | |
1002 | dest->sigh |= 0x40000000; | |
1003 | } | |
1004 | EXCEPTION(EX_Invalid); | |
1005 | ||
1006 | return; | |
1007 | } | |
1008 | /* Invalid arith operation on Valid registers */ | |
1009 | void | |
1010 | arith_invalid(FPU_REG * dest) | |
1011 | { | |
1012 | ||
1013 | if (control_word & CW_Invalid) { | |
1014 | /* The masked response */ | |
1015 | reg_move(&CONST_QNaN, dest); | |
1016 | } | |
1017 | EXCEPTION(EX_Invalid); | |
1018 | ||
1019 | return; | |
1020 | ||
1021 | } | |
1022 | ||
1023 | ||
1024 | /* Divide a finite number by zero */ | |
1025 | void | |
1026 | divide_by_zero(int sign, FPU_REG * dest) | |
1027 | { | |
1028 | ||
1029 | if (control_word & CW_ZeroDiv) { | |
1030 | /* The masked response */ | |
1031 | reg_move(&CONST_INF, dest); | |
1032 | dest->sign = (unsigned char) sign; | |
1033 | } | |
1034 | EXCEPTION(EX_ZeroDiv); | |
1035 | ||
1036 | return; | |
1037 | ||
1038 | } | |
1039 | ||
1040 | ||
1041 | /* This may be called often, so keep it lean */ | |
1042 | void | |
1043 | set_precision_flag_up(void) | |
1044 | { | |
1045 | if (control_word & CW_Precision) | |
1046 | status_word |= (SW_Precision | SW_C1); /* The masked response */ | |
1047 | else | |
1048 | exception(EX_Precision | SW_C1); | |
1049 | ||
1050 | } | |
1051 | ||
1052 | ||
1053 | /* This may be called often, so keep it lean */ | |
1054 | void | |
1055 | set_precision_flag_down(void) | |
1056 | { | |
1057 | if (control_word & CW_Precision) { /* The masked response */ | |
1058 | status_word &= ~SW_C1; | |
1059 | status_word |= SW_Precision; | |
1060 | } else | |
1061 | exception(EX_Precision); | |
1062 | } | |
1063 | ||
1064 | ||
1065 | int | |
1066 | denormal_operand(void) | |
1067 | { | |
1068 | if (control_word & CW_Denormal) { /* The masked response */ | |
1069 | status_word |= SW_Denorm_Op; | |
1070 | return 0; | |
1071 | } else { | |
1072 | exception(EX_Denormal); | |
1073 | return 1; | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | ||
1078 | void | |
1079 | arith_overflow(FPU_REG * dest) | |
1080 | { | |
1081 | ||
1082 | if (control_word & CW_Overflow) { | |
1083 | char sign; | |
1084 | /* The masked response */ | |
1085 | /* **** The response here depends upon the rounding mode */ | |
1086 | sign = dest->sign; | |
1087 | reg_move(&CONST_INF, dest); | |
1088 | dest->sign = sign; | |
1089 | } else { | |
1090 | /* Subtract the magic number from the exponent */ | |
1091 | dest->exp -= (3 * (1 << 13)); | |
1092 | } | |
1093 | ||
1094 | /* By definition, precision is lost. It appears that the roundup bit | |
1095 | * (C1) is also set by convention. */ | |
1096 | EXCEPTION(EX_Overflow | EX_Precision | SW_C1); | |
1097 | ||
1098 | return; | |
1099 | ||
1100 | } | |
1101 | ||
1102 | ||
1103 | void | |
1104 | arith_underflow(FPU_REG * dest) | |
1105 | { | |
1106 | ||
1107 | if (control_word & CW_Underflow) { | |
1108 | /* The masked response */ | |
1109 | if (dest->exp <= EXP_UNDER - 63) | |
1110 | reg_move(&CONST_Z, dest); | |
1111 | } else { | |
1112 | /* Add the magic number to the exponent */ | |
1113 | dest->exp += (3 * (1 << 13)); | |
1114 | } | |
1115 | ||
1116 | EXCEPTION(EX_Underflow); | |
1117 | ||
1118 | return; | |
1119 | } | |
1120 | ||
1121 | ||
1122 | void | |
1123 | stack_overflow(void) | |
1124 | { | |
1125 | ||
1126 | if (control_word & CW_Invalid) { | |
1127 | /* The masked response */ | |
1128 | top--; | |
1129 | reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0)); | |
1130 | } | |
1131 | EXCEPTION(EX_StackOver); | |
1132 | ||
1133 | return; | |
1134 | ||
1135 | } | |
1136 | ||
1137 | ||
1138 | void | |
1139 | stack_underflow(void) | |
1140 | { | |
1141 | ||
1142 | if (control_word & CW_Invalid) { | |
1143 | /* The masked response */ | |
1144 | reg_move(&CONST_QNaN, FPU_st0_ptr); | |
1145 | } | |
1146 | EXCEPTION(EX_StackUnder); | |
1147 | ||
1148 | return; | |
1149 | ||
1150 | } | |
1151 | ||
1152 | ||
1153 | void | |
1154 | stack_underflow_i(int i) | |
1155 | { | |
1156 | ||
1157 | if (control_word & CW_Invalid) { | |
1158 | /* The masked response */ | |
1159 | reg_move(&CONST_QNaN, &(st(i))); | |
1160 | } | |
1161 | EXCEPTION(EX_StackUnder); | |
1162 | ||
1163 | return; | |
1164 | ||
1165 | } | |
1166 | ||
1167 | ||
1168 | void | |
1169 | stack_underflow_pop(int i) | |
1170 | { | |
1171 | ||
1172 | if (control_word & CW_Invalid) { | |
1173 | /* The masked response */ | |
1174 | reg_move(&CONST_QNaN, &(st(i))); | |
1175 | pop(); | |
1176 | } | |
1177 | EXCEPTION(EX_StackUnder); | |
1178 | ||
1179 | return; | |
1180 | ||
1181 | } | |
1182 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/exception.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 6530 5462320155 12723\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
1183 | * exception.h | |
1184 | * | |
1185 | * | |
1186 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
1187 | * Vic 3163, Australia. | |
1188 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
1189 | * All rights reserved. | |
1190 | * | |
1191 | * This copyright notice covers the redistribution and use of the | |
1192 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
1193 | * in the 386BSD operating system. Any other use is not permitted | |
1194 | * under this copyright. | |
1195 | * | |
1196 | * Redistribution and use in source and binary forms, with or without | |
1197 | * modification, are permitted provided that the following conditions | |
1198 | * are met: | |
1199 | * 1. Redistributions of source code must retain the above copyright | |
1200 | * notice, this list of conditions and the following disclaimer. | |
1201 | * 2. Redistributions in binary form must include information specifying | |
1202 | * that source code for the emulator is freely available and include | |
1203 | * either: | |
1204 | * a) an offer to provide the source code for a nominal distribution | |
1205 | * fee, or | |
1206 | * b) list at least two alternative methods whereby the source | |
1207 | * can be obtained, e.g. a publically accessible bulletin board | |
1208 | * and an anonymous ftp site from which the software can be | |
1209 | * downloaded. | |
1210 | * 3. All advertising materials specifically mentioning features or use of | |
1211 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
1212 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
1213 | * products derived from this software without specific prior written | |
1214 | * permission. | |
1215 | * | |
1216 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
1217 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
1218 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
1219 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
1220 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
1221 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
1222 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
1223 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
1224 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1225 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1226 | * | |
1227 | */ | |
1228 | ||
1229 | #ifndef _EXCEPTION_H_ | |
1230 | #define _EXCEPTION_H_ | |
1231 | ||
1232 | ||
1233 | #ifdef LOCORE | |
1234 | #define Const_(x) $/**/x | |
1235 | #else | |
1236 | #define Const_(x) x | |
1237 | #endif | |
1238 | ||
1239 | #ifndef SW_C1 | |
1240 | #include "fpu_emu.h" | |
1241 | #endif /* SW_C1 */ | |
1242 | ||
1243 | #define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ | |
1244 | #define EX_ErrorSummary Const_(0x0080) /* Error summary status */ | |
1245 | /* Special exceptions: */ | |
1246 | #define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */ | |
1247 | #define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */ | |
1248 | #define EX_StackUnder Const_(0x0041) /* stack underflow */ | |
1249 | /* Exception flags: */ | |
1250 | #define EX_Precision Const_(0x0020) /* loss of precision */ | |
1251 | #define EX_Underflow Const_(0x0010) /* underflow */ | |
1252 | #define EX_Overflow Const_(0x0008) /* overflow */ | |
1253 | #define EX_ZeroDiv Const_(0x0004) /* divide by zero */ | |
1254 | #define EX_Denormal Const_(0x0002) /* denormalized operand */ | |
1255 | #define EX_Invalid Const_(0x0001) /* invalid operation */ | |
1256 | ||
1257 | ||
1258 | #ifndef LOCORE | |
1259 | ||
1260 | #ifdef DEBUG | |
1261 | #define EXCEPTION(x) { printf("exception in %s at line %d\n", \ | |
1262 | __FILE__, __LINE__); exception(x); } | |
1263 | #else | |
1264 | #define EXCEPTION(x) exception(x) | |
1265 | #endif | |
1266 | ||
1267 | #endif /* LOCORE */ | |
1268 | ||
1269 | #endif /* _EXCEPTION_H_ */ | |
1270 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_arith.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 11436 5462511711 12722\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
1271 | * fpu_arith.c | |
1272 | * | |
1273 | * Code to implement the FPU register/register arithmetic instructions | |
1274 | * | |
1275 | * | |
1276 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
1277 | * Vic 3163, Australia. | |
1278 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
1279 | * All rights reserved. | |
1280 | * | |
1281 | * This copyright notice covers the redistribution and use of the | |
1282 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
1283 | * in the 386BSD operating system. Any other use is not permitted | |
1284 | * under this copyright. | |
1285 | * | |
1286 | * Redistribution and use in source and binary forms, with or without | |
1287 | * modification, are permitted provided that the following conditions | |
1288 | * are met: | |
1289 | * 1. Redistributions of source code must retain the above copyright | |
1290 | * notice, this list of conditions and the following disclaimer. | |
1291 | * 2. Redistributions in binary form must include information specifying | |
1292 | * that source code for the emulator is freely available and include | |
1293 | * either: | |
1294 | * a) an offer to provide the source code for a nominal distribution | |
1295 | * fee, or | |
1296 | * b) list at least two alternative methods whereby the source | |
1297 | * can be obtained, e.g. a publically accessible bulletin board | |
1298 | * and an anonymous ftp site from which the software can be | |
1299 | * downloaded. | |
1300 | * 3. All advertising materials specifically mentioning features or use of | |
1301 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
1302 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
1303 | * products derived from this software without specific prior written | |
1304 | * permission. | |
1305 | * | |
1306 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
1307 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
1308 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
1309 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
1310 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
1311 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
1312 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
1313 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
1314 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1315 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1316 | * | |
1317 | */ | |
1318 | ||
1319 | ||
1320 | ||
1321 | ||
1322 | #include "param.h" | |
1323 | #include "proc.h" | |
1324 | #include "machine/cpu.h" | |
1325 | #include "machine/pcb.h" | |
1326 | ||
1327 | #include "fpu_emu.h" | |
1328 | #include "fpu_system.h" | |
1329 | #include "control_w.h" | |
1330 | ||
1331 | ||
1332 | void | |
1333 | fadd__() | |
1334 | { | |
1335 | /* fadd st,st(i) */ | |
1336 | reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); | |
1337 | } | |
1338 | ||
1339 | ||
1340 | void | |
1341 | fmul__() | |
1342 | { | |
1343 | /* fmul st,st(i) */ | |
1344 | reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); | |
1345 | } | |
1346 | ||
1347 | ||
1348 | ||
1349 | void | |
1350 | fsub__() | |
1351 | { | |
1352 | /* fsub st,st(i) */ | |
1353 | reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); | |
1354 | } | |
1355 | ||
1356 | ||
1357 | void | |
1358 | fsubr_() | |
1359 | { | |
1360 | /* fsubr st,st(i) */ | |
1361 | reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word); | |
1362 | } | |
1363 | ||
1364 | ||
1365 | void | |
1366 | fdiv__() | |
1367 | { | |
1368 | /* fdiv st,st(i) */ | |
1369 | reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); | |
1370 | } | |
1371 | ||
1372 | ||
1373 | void | |
1374 | fdivr_() | |
1375 | { | |
1376 | /* fdivr st,st(i) */ | |
1377 | reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word); | |
1378 | } | |
1379 | ||
1380 | ||
1381 | ||
1382 | void | |
1383 | fadd_i() | |
1384 | { | |
1385 | /* fadd st(i),st */ | |
1386 | reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); | |
1387 | } | |
1388 | ||
1389 | ||
1390 | void | |
1391 | fmul_i() | |
1392 | { | |
1393 | /* fmul st(i),st */ | |
1394 | reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); | |
1395 | } | |
1396 | ||
1397 | ||
1398 | void | |
1399 | fsubri() | |
1400 | { | |
1401 | /* fsubr st(i),st */ | |
1402 | /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm), | |
1403 | * FPU_st0_ptr, &st(FPU_rm), control_word); */ | |
1404 | reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); | |
1405 | } | |
1406 | ||
1407 | ||
1408 | void | |
1409 | fsub_i() | |
1410 | { | |
1411 | /* fsub st(i),st */ | |
1412 | /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr, | |
1413 | * &st(FPU_rm), &st(FPU_rm), control_word); */ | |
1414 | reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); | |
1415 | } | |
1416 | ||
1417 | ||
1418 | void | |
1419 | fdivri() | |
1420 | { | |
1421 | /* fdivr st(i),st */ | |
1422 | reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); | |
1423 | } | |
1424 | ||
1425 | ||
1426 | void | |
1427 | fdiv_i() | |
1428 | { | |
1429 | /* fdiv st(i),st */ | |
1430 | reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); | |
1431 | } | |
1432 | ||
1433 | ||
1434 | ||
1435 | void | |
1436 | faddp_() | |
1437 | { | |
1438 | /* faddp st(i),st */ | |
1439 | reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); | |
1440 | pop(); | |
1441 | } | |
1442 | ||
1443 | ||
1444 | void | |
1445 | fmulp_() | |
1446 | { | |
1447 | /* fmulp st(i),st */ | |
1448 | reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); | |
1449 | pop(); | |
1450 | } | |
1451 | ||
1452 | ||
1453 | ||
1454 | void | |
1455 | fsubrp() | |
1456 | { | |
1457 | /* fsubrp st(i),st */ | |
1458 | /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm), | |
1459 | * FPU_st0_ptr, &st(FPU_rm), control_word); */ | |
1460 | reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); | |
1461 | pop(); | |
1462 | } | |
1463 | ||
1464 | ||
1465 | void | |
1466 | fsubp_() | |
1467 | { | |
1468 | /* fsubp st(i),st */ | |
1469 | /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr, | |
1470 | * &st(FPU_rm), &st(FPU_rm), control_word); */ | |
1471 | reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); | |
1472 | pop(); | |
1473 | } | |
1474 | ||
1475 | ||
1476 | void | |
1477 | fdivrp() | |
1478 | { | |
1479 | /* fdivrp st(i),st */ | |
1480 | reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); | |
1481 | pop(); | |
1482 | } | |
1483 | ||
1484 | ||
1485 | void | |
1486 | fdivp_() | |
1487 | { | |
1488 | /* fdivp st(i),st */ | |
1489 | reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); | |
1490 | pop(); | |
1491 | } | |
1492 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_asm.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 5157 5462320155 12410\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
1493 | * fpu_asm.h | |
1494 | * | |
1495 | * | |
1496 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
1497 | * Vic 3163, Australia. | |
1498 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
1499 | * All rights reserved. | |
1500 | * | |
1501 | * This copyright notice covers the redistribution and use of the | |
1502 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
1503 | * in the 386BSD operating system. Any other use is not permitted | |
1504 | * under this copyright. | |
1505 | * | |
1506 | * Redistribution and use in source and binary forms, with or without | |
1507 | * modification, are permitted provided that the following conditions | |
1508 | * are met: | |
1509 | * 1. Redistributions of source code must retain the above copyright | |
1510 | * notice, this list of conditions and the following disclaimer. | |
1511 | * 2. Redistributions in binary form must include information specifying | |
1512 | * that source code for the emulator is freely available and include | |
1513 | * either: | |
1514 | * a) an offer to provide the source code for a nominal distribution | |
1515 | * fee, or | |
1516 | * b) list at least two alternative methods whereby the source | |
1517 | * can be obtained, e.g. a publically accessible bulletin board | |
1518 | * and an anonymous ftp site from which the software can be | |
1519 | * downloaded. | |
1520 | * 3. All advertising materials specifically mentioning features or use of | |
1521 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
1522 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
1523 | * products derived from this software without specific prior written | |
1524 | * permission. | |
1525 | * | |
1526 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
1527 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
1528 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
1529 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
1530 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
1531 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
1532 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
1533 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
1534 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1535 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1536 | * | |
1537 | */ | |
1538 | ||
1539 | #ifndef _FPU_ASM_H_ | |
1540 | #define _FPU_ASM_H_ | |
1541 | ||
1542 | #include "fpu_emu.h" | |
1543 | ||
1544 | #define EXCEPTION _exception | |
1545 | ||
1546 | ||
1547 | #define PARAM1 8(%ebp) | |
1548 | #define PARAM2 12(%ebp) | |
1549 | #define PARAM3 16(%ebp) | |
1550 | #define PARAM4 20(%ebp) | |
1551 | ||
1552 | #define SIGL_OFFSET 8 | |
1553 | #define SIGN(x) (x) | |
1554 | #define TAG(x) 1(x) | |
1555 | #define EXP(x) 4(x) | |
1556 | #define SIG(x) SIGL_OFFSET/**/(x) | |
1557 | #define SIGL(x) SIGL_OFFSET/**/(x) | |
1558 | #define SIGH(x) 12(x) | |
1559 | ||
1560 | #endif /* _FPU_ASM_H_ */ | |
1561 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_aux.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 11274 5462512021 12403\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
1562 | * fpu_aux.c | |
1563 | * | |
1564 | * Code to implement some of the FPU auxiliary instructions. | |
1565 | * | |
1566 | * | |
1567 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
1568 | * Vic 3163, Australia. | |
1569 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
1570 | * All rights reserved. | |
1571 | * | |
1572 | * This copyright notice covers the redistribution and use of the | |
1573 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
1574 | * in the 386BSD operating system. Any other use is not permitted | |
1575 | * under this copyright. | |
1576 | * | |
1577 | * Redistribution and use in source and binary forms, with or without | |
1578 | * modification, are permitted provided that the following conditions | |
1579 | * are met: | |
1580 | * 1. Redistributions of source code must retain the above copyright | |
1581 | * notice, this list of conditions and the following disclaimer. | |
1582 | * 2. Redistributions in binary form must include information specifying | |
1583 | * that source code for the emulator is freely available and include | |
1584 | * either: | |
1585 | * a) an offer to provide the source code for a nominal distribution | |
1586 | * fee, or | |
1587 | * b) list at least two alternative methods whereby the source | |
1588 | * can be obtained, e.g. a publically accessible bulletin board | |
1589 | * and an anonymous ftp site from which the software can be | |
1590 | * downloaded. | |
1591 | * 3. All advertising materials specifically mentioning features or use of | |
1592 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
1593 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
1594 | * products derived from this software without specific prior written | |
1595 | * permission. | |
1596 | * | |
1597 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
1598 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
1599 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
1600 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
1601 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
1602 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
1603 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
1604 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
1605 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1606 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1607 | * | |
1608 | */ | |
1609 | ||
1610 | ||
1611 | #include "param.h" | |
1612 | #include "proc.h" | |
1613 | #include "machine/cpu.h" | |
1614 | #include "machine/pcb.h" | |
1615 | ||
1616 | #include "fpu_emu.h" | |
1617 | #include "fpu_system.h" | |
1618 | #include "exception.h" | |
1619 | #include "status_w.h" | |
1620 | ||
1621 | ||
1622 | ||
1623 | void | |
1624 | fclex(void) | |
1625 | { | |
1626 | status_word &= ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision | | |
1627 | SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op | | |
1628 | SW_Invalid); | |
1629 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
1630 | } | |
1631 | /* Needs to be externally visible */ | |
1632 | void | |
1633 | finit() | |
1634 | { | |
1635 | int r; | |
1636 | control_word = 0x037f; | |
1637 | status_word = 0; | |
1638 | top = 0; /* We don't keep top in the status word | |
1639 | * internally. */ | |
1640 | for (r = 0; r < 8; r++) { | |
1641 | regs[r].tag = TW_Empty; | |
1642 | } | |
1643 | FPU_entry_eip = ip_offset = 0; | |
1644 | } | |
1645 | ||
1646 | static FUNC finit_table[] = { | |
1647 | Un_impl, Un_impl, fclex, finit, Un_impl, Un_impl, Un_impl, Un_impl | |
1648 | }; | |
1649 | ||
1650 | void | |
1651 | finit_() | |
1652 | { | |
1653 | (finit_table[FPU_rm]) (); | |
1654 | } | |
1655 | ||
1656 | ||
1657 | static void | |
1658 | fstsw_ax(void) | |
1659 | { | |
1660 | ||
1661 | status_word &= ~SW_Top; | |
1662 | status_word |= (top & 7) << SW_Top_Shift; | |
1663 | ||
1664 | *(short *) &FPU_EAX = status_word; | |
1665 | ||
1666 | } | |
1667 | ||
1668 | static FUNC fstsw_table[] = { | |
1669 | fstsw_ax, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl | |
1670 | }; | |
1671 | ||
1672 | void | |
1673 | fstsw_() | |
1674 | { | |
1675 | (fstsw_table[FPU_rm]) (); | |
1676 | } | |
1677 | ||
1678 | ||
1679 | ||
1680 | static void | |
1681 | fnop(void) | |
1682 | { | |
1683 | } | |
1684 | ||
1685 | FUNC fp_nop_table[] = { | |
1686 | fnop, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl | |
1687 | }; | |
1688 | ||
1689 | void | |
1690 | fp_nop() | |
1691 | { | |
1692 | (fp_nop_table[FPU_rm]) (); | |
1693 | } | |
1694 | ||
1695 | ||
1696 | void | |
1697 | fld_i_() | |
1698 | { | |
1699 | FPU_REG *st_new_ptr; | |
1700 | ||
1701 | if (STACK_OVERFLOW) { | |
1702 | stack_overflow(); | |
1703 | return; | |
1704 | } | |
1705 | /* fld st(i) */ | |
1706 | if (NOT_EMPTY(FPU_rm)) { | |
1707 | reg_move(&st(FPU_rm), st_new_ptr); | |
1708 | push(); | |
1709 | } else { | |
1710 | if (control_word & EX_Invalid) { | |
1711 | /* The masked response */ | |
1712 | push(); | |
1713 | stack_underflow(); | |
1714 | } else | |
1715 | EXCEPTION(EX_StackUnder); | |
1716 | } | |
1717 | ||
1718 | } | |
1719 | ||
1720 | ||
1721 | void | |
1722 | fxch_i() | |
1723 | { | |
1724 | /* fxch st(i) */ | |
1725 | FPU_REG t; | |
1726 | register FPU_REG *sti_ptr = &st(FPU_rm); | |
1727 | ||
1728 | if (FPU_st0_tag == TW_Empty) { | |
1729 | if (sti_ptr->tag == TW_Empty) { | |
1730 | stack_underflow(); | |
1731 | stack_underflow_i(FPU_rm); | |
1732 | return; | |
1733 | } | |
1734 | reg_move(sti_ptr, FPU_st0_ptr); | |
1735 | stack_underflow_i(FPU_rm); | |
1736 | return; | |
1737 | } | |
1738 | if (sti_ptr->tag == TW_Empty) { | |
1739 | reg_move(FPU_st0_ptr, sti_ptr); | |
1740 | stack_underflow(); | |
1741 | return; | |
1742 | } | |
1743 | reg_move(FPU_st0_ptr, &t); | |
1744 | reg_move(sti_ptr, FPU_st0_ptr); | |
1745 | reg_move(&t, sti_ptr); | |
1746 | } | |
1747 | ||
1748 | ||
1749 | void | |
1750 | ffree_() | |
1751 | { | |
1752 | /* ffree st(i) */ | |
1753 | st(FPU_rm).tag = TW_Empty; | |
1754 | } | |
1755 | ||
1756 | ||
1757 | void | |
1758 | ffreep() | |
1759 | { | |
1760 | /* ffree st(i) + pop - unofficial code */ | |
1761 | st(FPU_rm).tag = TW_Empty; | |
1762 | pop(); | |
1763 | } | |
1764 | ||
1765 | ||
1766 | void | |
1767 | fst_i_() | |
1768 | { | |
1769 | /* fst st(i) */ | |
1770 | reg_move(FPU_st0_ptr, &st(FPU_rm)); | |
1771 | } | |
1772 | ||
1773 | ||
1774 | void | |
1775 | fstp_i() | |
1776 | { | |
1777 | /* fstp st(i) */ | |
1778 | reg_move(FPU_st0_ptr, &st(FPU_rm)); | |
1779 | pop(); | |
1780 | } | |
1781 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_etc.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 10162 5462320157 12363\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
1782 | * fpu_etc.c | |
1783 | * | |
1784 | * Implement a few FPU instructions. | |
1785 | * | |
1786 | * | |
1787 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
1788 | * Vic 3163, Australia. | |
1789 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
1790 | * All rights reserved. | |
1791 | * | |
1792 | * This copyright notice covers the redistribution and use of the | |
1793 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
1794 | * in the 386BSD operating system. Any other use is not permitted | |
1795 | * under this copyright. | |
1796 | * | |
1797 | * Redistribution and use in source and binary forms, with or without | |
1798 | * modification, are permitted provided that the following conditions | |
1799 | * are met: | |
1800 | * 1. Redistributions of source code must retain the above copyright | |
1801 | * notice, this list of conditions and the following disclaimer. | |
1802 | * 2. Redistributions in binary form must include information specifying | |
1803 | * that source code for the emulator is freely available and include | |
1804 | * either: | |
1805 | * a) an offer to provide the source code for a nominal distribution | |
1806 | * fee, or | |
1807 | * b) list at least two alternative methods whereby the source | |
1808 | * can be obtained, e.g. a publically accessible bulletin board | |
1809 | * and an anonymous ftp site from which the software can be | |
1810 | * downloaded. | |
1811 | * 3. All advertising materials specifically mentioning features or use of | |
1812 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
1813 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
1814 | * products derived from this software without specific prior written | |
1815 | * permission. | |
1816 | * | |
1817 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
1818 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
1819 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
1820 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
1821 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
1822 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
1823 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
1824 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
1825 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1826 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1827 | * | |
1828 | */ | |
1829 | ||
1830 | #include "param.h" | |
1831 | #include "proc.h" | |
1832 | #include "machine/cpu.h" | |
1833 | #include "machine/pcb.h" | |
1834 | ||
1835 | #include "fpu_emu.h" | |
1836 | #include "fpu_system.h" | |
1837 | #include "exception.h" | |
1838 | #include "status_w.h" | |
1839 | #include "reg_constant.h" | |
1840 | ||
1841 | ||
1842 | static void | |
1843 | fchs(void) | |
1844 | { | |
1845 | if (NOT_EMPTY_0) { | |
1846 | FPU_st0_ptr->sign ^= SIGN_POS ^ SIGN_NEG; | |
1847 | status_word &= ~SW_C1; | |
1848 | } else | |
1849 | stack_underflow(); | |
1850 | } | |
1851 | ||
1852 | static void | |
1853 | fabs(void) | |
1854 | { | |
1855 | if (FPU_st0_tag ^ TW_Empty) { | |
1856 | FPU_st0_ptr->sign = SIGN_POS; | |
1857 | status_word &= ~SW_C1; | |
1858 | } else | |
1859 | stack_underflow(); | |
1860 | } | |
1861 | ||
1862 | ||
1863 | static void | |
1864 | ftst_(void) | |
1865 | { | |
1866 | switch (FPU_st0_tag) { | |
1867 | case TW_Zero: | |
1868 | setcc(SW_C3); | |
1869 | break; | |
1870 | case TW_Valid: | |
1871 | ||
1872 | #ifdef DENORM_OPERAND | |
1873 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
1874 | return; | |
1875 | #endif /* DENORM_OPERAND */ | |
1876 | ||
1877 | if (FPU_st0_ptr->sign == SIGN_POS) | |
1878 | setcc(0); | |
1879 | else | |
1880 | setcc(SW_C0); | |
1881 | break; | |
1882 | case TW_NaN: | |
1883 | setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ | |
1884 | EXCEPTION(EX_Invalid); | |
1885 | break; | |
1886 | case TW_Infinity: | |
1887 | if (FPU_st0_ptr->sign == SIGN_POS) | |
1888 | setcc(0); | |
1889 | else | |
1890 | setcc(SW_C0); | |
1891 | EXCEPTION(EX_Invalid); | |
1892 | break; | |
1893 | case TW_Empty: | |
1894 | setcc(SW_C0 | SW_C2 | SW_C3); | |
1895 | EXCEPTION(EX_StackUnder); | |
1896 | break; | |
1897 | default: | |
1898 | setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */ | |
1899 | EXCEPTION(EX_INTERNAL | 0x14); | |
1900 | break; | |
1901 | } | |
1902 | } | |
1903 | ||
1904 | static void | |
1905 | fxam(void) | |
1906 | { | |
1907 | int c = 0; | |
1908 | switch (FPU_st0_tag) { | |
1909 | case TW_Empty: | |
1910 | c = SW_C3 | SW_C0; | |
1911 | break; | |
1912 | case TW_Zero: | |
1913 | c = SW_C3; | |
1914 | break; | |
1915 | case TW_Valid: | |
1916 | /* This will need to be changed if TW_Denormal is ever used. */ | |
1917 | if (FPU_st0_ptr->exp <= EXP_UNDER) | |
1918 | c = SW_C2 | SW_C3; /* Denormal */ | |
1919 | else | |
1920 | c = SW_C3; | |
1921 | break; | |
1922 | case TW_NaN: | |
1923 | c = SW_C0; | |
1924 | break; | |
1925 | case TW_Infinity: | |
1926 | c = SW_C2 | SW_C0; | |
1927 | break; | |
1928 | } | |
1929 | if (FPU_st0_ptr->sign == SIGN_NEG) | |
1930 | c |= SW_C1; | |
1931 | setcc(c); | |
1932 | } | |
1933 | ||
1934 | static FUNC fp_etc_table[] = { | |
1935 | fchs, fabs, Un_impl, Un_impl, ftst_, fxam, Un_impl, Un_impl | |
1936 | }; | |
1937 | ||
1938 | void | |
1939 | fp_etc() | |
1940 | { | |
1941 | (fp_etc_table[FPU_rm]) (); | |
1942 | } | |
1943 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_system.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 6377 5462534357 13174\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
1944 | * fpu_system.h | |
1945 | * | |
1946 | * | |
1947 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
1948 | * Vic 3163, Australia. | |
1949 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
1950 | * All rights reserved. | |
1951 | * | |
1952 | * This copyright notice covers the redistribution and use of the | |
1953 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
1954 | * in the 386BSD operating system. Any other use is not permitted | |
1955 | * under this copyright. | |
1956 | * | |
1957 | * Redistribution and use in source and binary forms, with or without | |
1958 | * modification, are permitted provided that the following conditions | |
1959 | * are met: | |
1960 | * 1. Redistributions of source code must retain the above copyright | |
1961 | * notice, this list of conditions and the following disclaimer. | |
1962 | * 2. Redistributions in binary form must include information specifying | |
1963 | * that source code for the emulator is freely available and include | |
1964 | * either: | |
1965 | * a) an offer to provide the source code for a nominal distribution | |
1966 | * fee, or | |
1967 | * b) list at least two alternative methods whereby the source | |
1968 | * can be obtained, e.g. a publically accessible bulletin board | |
1969 | * and an anonymous ftp site from which the software can be | |
1970 | * downloaded. | |
1971 | * 3. All advertising materials specifically mentioning features or use of | |
1972 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
1973 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
1974 | * products derived from this software without specific prior written | |
1975 | * permission. | |
1976 | * | |
1977 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
1978 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
1979 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
1980 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
1981 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
1982 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
1983 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
1984 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
1985 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
1986 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
1987 | * | |
1988 | */ | |
1989 | ||
1990 | ||
1991 | #ifndef _FPU_SYSTEM_H | |
1992 | #define _FPU_SYSTEM_H | |
1993 | ||
1994 | /* system dependent definitions */ | |
1995 | ||
1996 | /* | |
1997 | #include <linux/sched.h> | |
1998 | #include <linux/kernel.h> | |
1999 | */ | |
2000 | ||
2001 | #define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu)) | |
2002 | #define FPU_info (I387.soft.frame) | |
2003 | ||
2004 | #define FPU_CS (*(unsigned short *) &(FPU_info->tf_cs)) | |
2005 | #define FPU_DS (*(unsigned short *) &(FPU_info->tf_ds)) | |
2006 | #define FPU_EAX (FPU_info->tf_eax) | |
2007 | #define FPU_EFLAGS (FPU_info->tf_eflags) | |
2008 | #define FPU_EIP (FPU_info->tf_eip) | |
2009 | /*#define FPU_ORIG_EIP (FPU_info->___orig_eip) */ | |
2010 | /*#define FPU_ORIG_EIP (FPU_info->tf_isp)*/ | |
2011 | #define FPU_ORIG_EIP (I387.soft.orig_eip) | |
2012 | ||
2013 | #define FPU_lookahead (I387.soft.lookahead) | |
2014 | #define FPU_entry_eip (I387.soft.entry_eip) | |
2015 | ||
2016 | #define status_word (I387.soft.swd) | |
2017 | #define control_word (I387.soft.cwd) | |
2018 | #define regs (I387.soft.regs) | |
2019 | #define top (I387.soft.top) | |
2020 | ||
2021 | #define ip_offset (I387.soft.fip) | |
2022 | #define cs_selector (I387.soft.fcs) | |
2023 | #define data_operand_offset (I387.soft.foo) | |
2024 | #define operand_selector (I387.soft.fos) | |
2025 | ||
2026 | #endif | |
2027 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/README\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 27206 5462277677 11530\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
2028 | * wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | |
2029 | * | |
2030 | * | |
2031 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
2032 | * Vic 3163, Australia. | |
2033 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
2034 | * All rights reserved. | |
2035 | * | |
2036 | * This copyright notice covers the redistribution and use of the | |
2037 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
2038 | * in the 386BSD operating system. Any other use is not permitted | |
2039 | * under this copyright. | |
2040 | * | |
2041 | * Redistribution and use in source and binary forms, with or without | |
2042 | * modification, are permitted provided that the following conditions | |
2043 | * are met: | |
2044 | * 1. Redistributions of source code must retain the above copyright | |
2045 | * notice, this list of conditions and the following disclaimer. | |
2046 | * 2. Redistributions in binary form must include information specifying | |
2047 | * that source code for the emulator is freely available and include | |
2048 | * either: | |
2049 | * a) an offer to provide the source code for a nominal distribution | |
2050 | * fee, or | |
2051 | * b) list at least two alternative methods whereby the source | |
2052 | * can be obtained, e.g. a publically accessible bulletin board | |
2053 | * and an anonymous ftp site from which the software can be | |
2054 | * downloaded. | |
2055 | * 3. All advertising materials specifically mentioning features or use of | |
2056 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
2057 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
2058 | * products derived from this software without specific prior written | |
2059 | * permission. | |
2060 | * | |
2061 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
2062 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
2063 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
2064 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
2065 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
2066 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
2067 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
2068 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
2069 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
2070 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
2071 | * | |
2072 | */ | |
2073 | ||
2074 | wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387 | |
2075 | which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was | |
2076 | in turn based upon emu387 which was written by DJ Delorie for djgpp. | |
2077 | The interface to the Linux kernel is based upon the original Linux | |
2078 | math emulator by Linus Torvalds. | |
2079 | ||
2080 | My target FPU for wm-FPU-emu is that described in the Intel486 | |
2081 | Programmer's Reference Manual (1992 edition). Numerous facets of the | |
2082 | functioning of the FPU are not well covered in the Reference Manual; | |
2083 | in the absence of clear details I have made guesses about the most | |
2084 | reasonable behaviour. Recently, this situation has improved because | |
2085 | I now have some access to the results produced by a real 80486 FPU. | |
2086 | ||
2087 | wm-FPU-emu does not implement all of the behaviour of the 80486 FPU. | |
2088 | See "Limitations" later in this file for a partial list of some | |
2089 | differences. I believe that the missing features are never used by | |
2090 | normal C or FORTRAN programs. | |
2091 | ||
2092 | ||
2093 | Please report bugs, etc to me at: | |
2094 | apm233m@vaxc.cc.monash.edu.au | |
2095 | ||
2096 | ||
2097 | --Bill Metzenthen | |
2098 | May 1993 | |
2099 | ||
2100 | ||
2101 | ----------------------- Internals of wm-FPU-emu ----------------------- | |
2102 | ||
2103 | Numeric algorithms: | |
2104 | (1) Add, subtract, and multiply. Nothing remarkable in these. | |
2105 | (2) Divide has been tuned to get reasonable performance. The algorithm | |
2106 | is not the obvious one which most people seem to use, but is designed | |
2107 | to take advantage of the characteristics of the 80386. I expect that | |
2108 | it has been invented many times before I discovered it, but I have not | |
2109 | seen it. It is based upon one of those ideas which one carries around | |
2110 | for years without ever bothering to check it out. | |
2111 | (3) The sqrt function has been tuned to get good performance. It is based | |
2112 | upon Newton's classic method. Performance was improved by capitalizing | |
2113 | upon the properties of Newton's method, and the code is once again | |
2114 | structured taking account of the 80386 characteristics. | |
2115 | (4) The trig, log, and exp functions are based in each case upon quasi- | |
2116 | "optimal" polynomial approximations. My definition of "optimal" was | |
2117 | based upon getting good accuracy with reasonable speed. | |
2118 | ||
2119 | The code of the emulator is complicated slightly by the need to | |
2120 | account for a limited form of re-entrancy. Normally, the emulator will | |
2121 | emulate each FPU instruction to completion without interruption. | |
2122 | However, it may happen that when the emulator is accessing the user | |
2123 | memory space, swapping may be needed. In this case the emulator may be | |
2124 | temporarily suspended while disk i/o takes place. During this time | |
2125 | another process may use the emulator, thereby changing some static | |
2126 | variables (eg FPU_st0_ptr, etc). The code which accesses user memory | |
2127 | is confined to five files: | |
2128 | fpu_entry.c | |
2129 | reg_ld_str.c | |
2130 | load_store.c | |
2131 | get_address.c | |
2132 | errors.c | |
2133 | ||
2134 | ----------------------- Limitations of wm-FPU-emu ----------------------- | |
2135 | ||
2136 | There are a number of differences between the current wm-FPU-emu | |
2137 | (version beta 1.4) and the 80486 FPU (apart from bugs). Some of the | |
2138 | more important differences are listed below: | |
2139 | ||
2140 | All internal computations are performed at 64 bit or higher precision | |
2141 | and rounded etc as required by the PC bits of the FPU control word. | |
2142 | Under the crt0 version for Linux current at March 1993, the FPU PC | |
2143 | bits specify 53 bits precision. | |
2144 | ||
2145 | The precision flag (PE of the FPU status word) and the Roundup flag | |
2146 | (C1 of the status word) are now partially implemented. Does anyone | |
2147 | write code which uses these features? | |
2148 | ||
2149 | The functions which load/store the FPU state are partially implemented, | |
2150 | but the implementation should be sufficient for handling FPU errors etc | |
2151 | in 32 bit protected mode. | |
2152 | ||
2153 | The implementation of the exception mechanism is flawed for unmasked | |
2154 | interrupts. | |
2155 | ||
2156 | Detection of certain conditions, such as denormal operands, is not yet | |
2157 | complete. | |
2158 | ||
2159 | ----------------------- Performance of wm-FPU-emu ----------------------- | |
2160 | ||
2161 | Speed. | |
2162 | ----- | |
2163 | ||
2164 | The speed of floating point computation with the emulator will depend | |
2165 | upon instruction mix. Relative performance is best for the instructions | |
2166 | which require most computation. The simple instructions are adversely | |
2167 | affected by the fpu instruction trap overhead. | |
2168 | ||
2169 | ||
2170 | Timing: Some simple timing tests have been made on the emulator functions. | |
2171 | The times include load/store instructions. All times are in microseconds | |
2172 | measured on a 33MHz 386 with 64k cache. The Turbo C tests were under | |
2173 | ms-dos, the next two columns are for emulators running with the djgpp | |
2174 | ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97, | |
2175 | using libm4.0 (hard). | |
2176 | ||
2177 | function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu | |
2178 | ||
2179 | + 60.5 154.8 76.5 139.4 | |
2180 | - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7 | |
2181 | * 71.0 190.8 79.6 146.6 | |
2182 | / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1 | |
2183 | ||
2184 | sin() 310.8 4692.0 319.0 398.5 | |
2185 | cos() 284.4 4855.2 308.0 388.7 | |
2186 | tan() 495.0 8807.1 394.9 504.7 | |
2187 | atan() 328.9 4866.4 601.1 419.5-491.9 | |
2188 | ||
2189 | sqrt() 128.7 crashed 145.2 227.0 | |
2190 | log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1 | |
2191 | exp() 479.1 6619.2 469.1 850.8 | |
2192 | ||
2193 | ||
2194 | The performance under Linux is improved by the use of look-ahead code. | |
2195 | The following results show the improvement which is obtained under | |
2196 | Linux due to the look-ahead code. Also given are the times for the | |
2197 | original Linux emulator with the 4.1 'soft' lib. | |
2198 | ||
2199 | [ Linus' note: I changed look-ahead to be the default under linux, as | |
2200 | there was no reason not to use it after I had edited it to be | |
2201 | disabled during tracing ] | |
2202 | ||
2203 | wm-FPU-emu w original w | |
2204 | look-ahead 'soft' lib | |
2205 | + 106.4 190.2 | |
2206 | - 108.6-111.6 192.4-216.2 | |
2207 | * 113.4 193.1 | |
2208 | / 108.8-124.4 700.1-706.2 | |
2209 | ||
2210 | sin() 390.5 2642.0 | |
2211 | cos() 381.5 2767.4 | |
2212 | tan() 496.5 3153.3 | |
2213 | atan() 367.2-435.5 2439.4-3396.8 | |
2214 | ||
2215 | sqrt() 195.1 4732.5 | |
2216 | log() 358.0-387.5 3359.2-3390.3 | |
2217 | exp() 619.3 4046.4 | |
2218 | ||
2219 | ||
2220 | These figures are now somewhat out-of-date. The emulator has become | |
2221 | progressively slower for most functions as more of the 80486 features | |
2222 | have been implemented. | |
2223 | ||
2224 | ||
2225 | ----------------------- Accuracy of wm-FPU-emu ----------------------- | |
2226 | ||
2227 | ||
2228 | Accuracy: The following table gives the accuracy of the sqrt(), trig | |
2229 | and log functions. Each function was tested at about 400 points. Ideal | |
2230 | results would be 64 bits. The reduced accuracy of cos() and tan() for | |
2231 | arguments greater than pi/4 can be thought of as being due to the | |
2232 | precision of the argument x; e.g. an argument of pi/2-(1e-10) which is | |
2233 | accurate to 64 bits can result in a relative accuracy in cos() of about | |
2234 | 64 + log2(cos(x)) = 31 bits. Results for the Turbo C emulator are given | |
2235 | in the last column. | |
2236 | ||
2237 | ||
2238 | Function Tested x range Worst result (bits) Turbo C | |
2239 | ||
2240 | sqrt(x) 1 .. 2 64.1 63.2 | |
2241 | atan(x) 1e-10 .. 200 62.6 62.8 | |
2242 | cos(x) 0 .. pi/2-(1e-10) 63.2 (x <= pi/4) 62.4 | |
2243 | 35.2 (x = pi/2-(1e-10)) 31.9 | |
2244 | sin(x) 1e-10 .. pi/2 63.0 62.8 | |
2245 | tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1 | |
2246 | 35.2 (x = pi/2-(1e-10)) 31.9 | |
2247 | exp(x) 0 .. 1 63.1 62.9 | |
2248 | log(x) 1+1e-6 .. 2 62.4 62.1 | |
2249 | ||
2250 | ||
2251 | As of version 1.3 of the emulator, the accuracy of the basic | |
2252 | arithmetic has been improved (by a small fraction of a bit). Care has | |
2253 | been taken to ensure full accuracy of the rounding of the basic | |
2254 | arithmetic functions (+,-,*,/,and fsqrt), and they all now produce | |
2255 | results which are exact to the 64th bit (unless there are any bugs | |
2256 | left). To ensure this, it was necessary to effectively get information | |
2257 | of up to about 128 bits precision. The emulator now passes the | |
2258 | "paranoia" tests (compiled with gcc 2.3.3) for 'float' variables (24 | |
2259 | bit precision numbers) when precision control is set to 24, 53 or 64 | |
2260 | bits, and for 'double' variables (53 bit precision numbers) when | |
2261 | precision control is set to 53 bits (a properly performing FPU cannot | |
2262 | pass the 'paranoia' tests for 'double' variables when precision | |
2263 | control is set to 64 bits). | |
2264 | ||
2265 | ------------------------- Contributors ------------------------------- | |
2266 | ||
2267 | A number of people have contributed to the development of the | |
2268 | emulator, often by just reporting bugs, sometimes with a suggested | |
2269 | fix, and a few kind people have provided me with access in one way or | |
2270 | another to an 80486 machine. Contributors include (to those people who | |
2271 | I have forgotten, please excuse me): | |
2272 | ||
2273 | Linus Torvalds | |
2274 | Tommy.Thorn@daimi.aau.dk | |
2275 | Andrew.Tridgell@anu.edu.au | |
2276 | Nick Holloway alfie@dcs.warwick.ac.uk | |
2277 | Hermano Moura moura@dcs.gla.ac.uk | |
2278 | Jon Jagger J.Jagger@scp.ac.uk | |
2279 | Lennart Benschop | |
2280 | Brian Gallew geek+@CMU.EDU | |
2281 | Thomas Staniszewski ts3v+@andrew.cmu.edu | |
2282 | Martin Howell mph@plasma.apana.org.au | |
2283 | M Saggaf alsaggaf@athena.mit.edu | |
2284 | Peter Barker PETER@socpsy.sci.fau.edu | |
2285 | tom@vlsivie.tuwien.ac.at | |
2286 | Dan Russel russed@rpi.edu | |
2287 | Daniel Carosone danielce@ee.mu.oz.au | |
2288 | cae@jpmorgan.com | |
2289 | Hamish Coleman t933093@minyos.xx.rmit.oz.au | |
2290 | ||
2291 | ...and numerous others who responded to my request for help with | |
2292 | a real 80486. | |
2293 | ||
2294 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_trig.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 76162 5462320160 12563\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
2295 | * fpu_trig.c | |
2296 | * | |
2297 | * Implementation of the FPU "transcendental" functions. | |
2298 | * | |
2299 | * | |
2300 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
2301 | * Vic 3163, Australia. | |
2302 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
2303 | * All rights reserved. | |
2304 | * | |
2305 | * This copyright notice covers the redistribution and use of the | |
2306 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
2307 | * in the 386BSD operating system. Any other use is not permitted | |
2308 | * under this copyright. | |
2309 | * | |
2310 | * Redistribution and use in source and binary forms, with or without | |
2311 | * modification, are permitted provided that the following conditions | |
2312 | * are met: | |
2313 | * 1. Redistributions of source code must retain the above copyright | |
2314 | * notice, this list of conditions and the following disclaimer. | |
2315 | * 2. Redistributions in binary form must include information specifying | |
2316 | * that source code for the emulator is freely available and include | |
2317 | * either: | |
2318 | * a) an offer to provide the source code for a nominal distribution | |
2319 | * fee, or | |
2320 | * b) list at least two alternative methods whereby the source | |
2321 | * can be obtained, e.g. a publically accessible bulletin board | |
2322 | * and an anonymous ftp site from which the software can be | |
2323 | * downloaded. | |
2324 | * 3. All advertising materials specifically mentioning features or use of | |
2325 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
2326 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
2327 | * products derived from this software without specific prior written | |
2328 | * permission. | |
2329 | * | |
2330 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
2331 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
2332 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
2333 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
2334 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
2335 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
2336 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
2337 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
2338 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
2339 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
2340 | * | |
2341 | */ | |
2342 | ||
2343 | ||
2344 | #include "param.h" | |
2345 | #include "proc.h" | |
2346 | #include "machine/cpu.h" | |
2347 | #include "machine/pcb.h" | |
2348 | ||
2349 | #include "fpu_emu.h" | |
2350 | #include "fpu_system.h" | |
2351 | #include "exception.h" | |
2352 | #include "status_w.h" | |
2353 | #include "reg_constant.h" | |
2354 | #include "control_w.h" | |
2355 | ||
2356 | static int | |
2357 | trig_arg(FPU_REG * X) | |
2358 | { | |
2359 | FPU_REG tmp, quot; | |
2360 | int rv; | |
2361 | long long q; | |
2362 | int old_cw = control_word; | |
2363 | ||
2364 | control_word &= ~CW_RC; | |
2365 | control_word |= RC_CHOP; | |
2366 | ||
2367 | reg_move(X, "); | |
2368 | reg_div(", &CONST_PI2, ", FULL_PRECISION); | |
2369 | ||
2370 | reg_move(", &tmp); | |
2371 | round_to_int(&tmp); | |
2372 | if (tmp.sigh & 0x80000000) | |
2373 | return -1; /* |Arg| is >= 2^63 */ | |
2374 | tmp.exp = EXP_BIAS + 63; | |
2375 | q = *(long long *) &(tmp.sigl); | |
2376 | normalize(&tmp); | |
2377 | ||
2378 | reg_sub(", &tmp, X, FULL_PRECISION); | |
2379 | rv = q & 7; | |
2380 | ||
2381 | control_word = old_cw; | |
2382 | return rv;; | |
2383 | } | |
2384 | ||
2385 | ||
2386 | /* Convert a long to register */ | |
2387 | void | |
2388 | convert_l2reg(long *arg, FPU_REG * dest) | |
2389 | { | |
2390 | long num = *arg; | |
2391 | ||
2392 | if (num == 0) { | |
2393 | reg_move(&CONST_Z, dest); | |
2394 | return; | |
2395 | } | |
2396 | if (num > 0) | |
2397 | dest->sign = SIGN_POS; | |
2398 | else { | |
2399 | num = -num; | |
2400 | dest->sign = SIGN_NEG; | |
2401 | } | |
2402 | ||
2403 | dest->sigh = num; | |
2404 | dest->sigl = 0; | |
2405 | dest->exp = EXP_BIAS + 31; | |
2406 | dest->tag = TW_Valid; | |
2407 | normalize(dest); | |
2408 | } | |
2409 | ||
2410 | ||
2411 | static void | |
2412 | single_arg_error(void) | |
2413 | { | |
2414 | switch (FPU_st0_tag) { | |
2415 | case TW_NaN: | |
2416 | if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */ | |
2417 | EXCEPTION(EX_Invalid); | |
2418 | /* Convert to a QNaN */ | |
2419 | FPU_st0_ptr->sigh |= 0x40000000; | |
2420 | } | |
2421 | break; /* return with a NaN in st(0) */ | |
2422 | case TW_Empty: | |
2423 | stack_underflow(); /* Puts a QNaN in st(0) */ | |
2424 | break; | |
2425 | #ifdef PARANOID | |
2426 | default: | |
2427 | EXCEPTION(EX_INTERNAL | 0x0112); | |
2428 | #endif /* PARANOID */ | |
2429 | } | |
2430 | } | |
2431 | ||
2432 | ||
2433 | /*---------------------------------------------------------------------------*/ | |
2434 | ||
2435 | static void | |
2436 | f2xm1(void) | |
2437 | { | |
2438 | switch (FPU_st0_tag) { | |
2439 | case TW_Valid: | |
2440 | { | |
2441 | FPU_REG rv, tmp; | |
2442 | ||
2443 | #ifdef DENORM_OPERAND | |
2444 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2445 | return; | |
2446 | #endif /* DENORM_OPERAND */ | |
2447 | ||
2448 | if (FPU_st0_ptr->sign == SIGN_POS) { | |
2449 | /* poly_2xm1(x) requires 0 < x < 1. */ | |
2450 | if (poly_2xm1(FPU_st0_ptr, &rv)) | |
2451 | return; /* error */ | |
2452 | reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); | |
2453 | } else { | |
2454 | /* **** Should change poly_2xm1() to at least handle numbers near 0 */ | |
2455 | /* poly_2xm1(x) doesn't handle negative | |
2456 | * numbers. */ | |
2457 | /* So we compute (poly_2xm1(x+1)-1)/2, for -1 | |
2458 | * < x < 0 */ | |
2459 | reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION); | |
2460 | poly_2xm1(&tmp, &rv); | |
2461 | reg_mul(&rv, &tmp, &tmp, FULL_PRECISION); | |
2462 | reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION); | |
2463 | FPU_st0_ptr->exp--; | |
2464 | if (FPU_st0_ptr->exp <= EXP_UNDER) | |
2465 | arith_underflow(FPU_st0_ptr); | |
2466 | } | |
2467 | return; | |
2468 | } | |
2469 | case TW_Zero: | |
2470 | return; | |
2471 | case TW_Infinity: | |
2472 | if (FPU_st0_ptr->sign == SIGN_NEG) { | |
2473 | /* -infinity gives -1 (p16-10) */ | |
2474 | reg_move(&CONST_1, FPU_st0_ptr); | |
2475 | FPU_st0_ptr->sign = SIGN_NEG; | |
2476 | } | |
2477 | return; | |
2478 | default: | |
2479 | single_arg_error(); | |
2480 | } | |
2481 | } | |
2482 | ||
2483 | static void | |
2484 | fptan(void) | |
2485 | { | |
2486 | FPU_REG *st_new_ptr; | |
2487 | int q; | |
2488 | char arg_sign = FPU_st0_ptr->sign; | |
2489 | ||
2490 | if (STACK_OVERFLOW) { | |
2491 | stack_overflow(); | |
2492 | return; | |
2493 | } | |
2494 | switch (FPU_st0_tag) { | |
2495 | case TW_Valid: | |
2496 | ||
2497 | #ifdef DENORM_OPERAND | |
2498 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2499 | return; | |
2500 | #endif /* DENORM_OPERAND */ | |
2501 | ||
2502 | FPU_st0_ptr->sign = SIGN_POS; | |
2503 | if ((q = trig_arg(FPU_st0_ptr)) != -1) { | |
2504 | if (q & 1) | |
2505 | reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); | |
2506 | ||
2507 | poly_tan(FPU_st0_ptr, FPU_st0_ptr); | |
2508 | ||
2509 | FPU_st0_ptr->sign = (q & 1) ^ arg_sign; | |
2510 | ||
2511 | if (FPU_st0_ptr->exp <= EXP_UNDER) | |
2512 | arith_underflow(FPU_st0_ptr); | |
2513 | ||
2514 | push(); | |
2515 | reg_move(&CONST_1, FPU_st0_ptr); | |
2516 | setcc(0); | |
2517 | } else { | |
2518 | /* Operand is out of range */ | |
2519 | setcc(SW_C2); | |
2520 | FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ | |
2521 | return; | |
2522 | } | |
2523 | break; | |
2524 | case TW_Infinity: | |
2525 | /* Operand is out of range */ | |
2526 | setcc(SW_C2); | |
2527 | FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ | |
2528 | return; | |
2529 | case TW_Zero: | |
2530 | push(); | |
2531 | reg_move(&CONST_1, FPU_st0_ptr); | |
2532 | setcc(0); | |
2533 | break; | |
2534 | default: | |
2535 | single_arg_error(); | |
2536 | break; | |
2537 | } | |
2538 | } | |
2539 | ||
2540 | ||
2541 | static void | |
2542 | fxtract(void) | |
2543 | { | |
2544 | FPU_REG *st_new_ptr; | |
2545 | register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */ | |
2546 | ||
2547 | if (STACK_OVERFLOW) { | |
2548 | stack_overflow(); | |
2549 | return; | |
2550 | } | |
2551 | if (!(FPU_st0_tag ^ TW_Valid)) { | |
2552 | long e; | |
2553 | ||
2554 | #ifdef DENORM_OPERAND | |
2555 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2556 | return; | |
2557 | #endif /* DENORM_OPERAND */ | |
2558 | ||
2559 | push(); | |
2560 | reg_move(st1_ptr, FPU_st0_ptr); | |
2561 | FPU_st0_ptr->exp = EXP_BIAS; | |
2562 | e = st1_ptr->exp - EXP_BIAS; | |
2563 | convert_l2reg(&e, st1_ptr); | |
2564 | return; | |
2565 | } else | |
2566 | if (FPU_st0_tag == TW_Zero) { | |
2567 | char sign = FPU_st0_ptr->sign; | |
2568 | divide_by_zero(SIGN_NEG, FPU_st0_ptr); | |
2569 | push(); | |
2570 | reg_move(&CONST_Z, FPU_st0_ptr); | |
2571 | FPU_st0_ptr->sign = sign; | |
2572 | return; | |
2573 | } else | |
2574 | if (FPU_st0_tag == TW_Infinity) { | |
2575 | char sign = FPU_st0_ptr->sign; | |
2576 | FPU_st0_ptr->sign = SIGN_POS; | |
2577 | push(); | |
2578 | reg_move(&CONST_INF, FPU_st0_ptr); | |
2579 | FPU_st0_ptr->sign = sign; | |
2580 | return; | |
2581 | } else | |
2582 | if (FPU_st0_tag == TW_NaN) { | |
2583 | if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */ | |
2584 | EXCEPTION(EX_Invalid); | |
2585 | /* Convert to a QNaN */ | |
2586 | FPU_st0_ptr->sigh |= 0x40000000; | |
2587 | } | |
2588 | push(); | |
2589 | reg_move(st1_ptr, FPU_st0_ptr); | |
2590 | return; | |
2591 | } else | |
2592 | if (FPU_st0_tag == TW_Empty) { | |
2593 | /* Is this the correct | |
2594 | * behaviour? */ | |
2595 | if (control_word & EX_Invalid) { | |
2596 | stack_underflow(); | |
2597 | push(); | |
2598 | stack_underflow(); | |
2599 | } else | |
2600 | EXCEPTION(EX_StackUnder); | |
2601 | } | |
2602 | #ifdef PARANOID | |
2603 | else | |
2604 | EXCEPTION(EX_INTERNAL | 0x119); | |
2605 | #endif /* PARANOID */ | |
2606 | } | |
2607 | ||
2608 | ||
2609 | static void | |
2610 | fdecstp(void) | |
2611 | { | |
2612 | top--; /* FPU_st0_ptr will be fixed in math_emulate() | |
2613 | * before the next instr */ | |
2614 | } | |
2615 | ||
2616 | static void | |
2617 | fincstp(void) | |
2618 | { | |
2619 | top++; /* FPU_st0_ptr will be fixed in math_emulate() | |
2620 | * before the next instr */ | |
2621 | } | |
2622 | ||
2623 | ||
2624 | static void | |
2625 | fsqrt_(void) | |
2626 | { | |
2627 | if (!(FPU_st0_tag ^ TW_Valid)) { | |
2628 | int expon; | |
2629 | ||
2630 | if (FPU_st0_ptr->sign == SIGN_NEG) { | |
2631 | arith_invalid(FPU_st0_ptr); /* sqrt(negative) is | |
2632 | * invalid */ | |
2633 | return; | |
2634 | } | |
2635 | #ifdef DENORM_OPERAND | |
2636 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2637 | return; | |
2638 | #endif /* DENORM_OPERAND */ | |
2639 | ||
2640 | expon = FPU_st0_ptr->exp - EXP_BIAS; | |
2641 | FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 | |
2642 | * .. 4.0) */ | |
2643 | ||
2644 | wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */ | |
2645 | ||
2646 | FPU_st0_ptr->exp += expon >> 1; | |
2647 | FPU_st0_ptr->sign = SIGN_POS; | |
2648 | } else | |
2649 | if (FPU_st0_tag == TW_Zero) | |
2650 | return; | |
2651 | else | |
2652 | if (FPU_st0_tag == TW_Infinity) { | |
2653 | if (FPU_st0_ptr->sign == SIGN_NEG) | |
2654 | arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is | |
2655 | * invalid */ | |
2656 | return; | |
2657 | } else { | |
2658 | single_arg_error(); | |
2659 | return; | |
2660 | } | |
2661 | ||
2662 | } | |
2663 | ||
2664 | ||
2665 | static void | |
2666 | frndint_(void) | |
2667 | { | |
2668 | if (!(FPU_st0_tag ^ TW_Valid)) { | |
2669 | if (FPU_st0_ptr->exp > EXP_BIAS + 63) | |
2670 | return; | |
2671 | ||
2672 | #ifdef DENORM_OPERAND | |
2673 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2674 | return; | |
2675 | #endif /* DENORM_OPERAND */ | |
2676 | ||
2677 | round_to_int(FPU_st0_ptr); /* Fortunately, this can't | |
2678 | * overflow to 2^64 */ | |
2679 | FPU_st0_ptr->exp = EXP_BIAS + 63; | |
2680 | normalize(FPU_st0_ptr); | |
2681 | return; | |
2682 | } else | |
2683 | if ((FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity)) | |
2684 | return; | |
2685 | else | |
2686 | single_arg_error(); | |
2687 | } | |
2688 | ||
2689 | ||
2690 | static void | |
2691 | fsin(void) | |
2692 | { | |
2693 | char arg_sign = FPU_st0_ptr->sign; | |
2694 | ||
2695 | if (FPU_st0_tag == TW_Valid) { | |
2696 | int q; | |
2697 | FPU_st0_ptr->sign = SIGN_POS; | |
2698 | ||
2699 | #ifdef DENORM_OPERAND | |
2700 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2701 | return; | |
2702 | #endif /* DENORM_OPERAND */ | |
2703 | ||
2704 | if ((q = trig_arg(FPU_st0_ptr)) != -1) { | |
2705 | FPU_REG rv; | |
2706 | ||
2707 | if (q & 1) | |
2708 | reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); | |
2709 | ||
2710 | poly_sine(FPU_st0_ptr, &rv); | |
2711 | ||
2712 | setcc(0); | |
2713 | if (q & 2) | |
2714 | rv.sign ^= SIGN_POS ^ SIGN_NEG; | |
2715 | rv.sign ^= arg_sign; | |
2716 | reg_move(&rv, FPU_st0_ptr); | |
2717 | ||
2718 | if (FPU_st0_ptr->exp <= EXP_UNDER) | |
2719 | arith_underflow(FPU_st0_ptr); | |
2720 | ||
2721 | set_precision_flag_up(); /* We do not really know | |
2722 | * if up or down */ | |
2723 | ||
2724 | return; | |
2725 | } else { | |
2726 | /* Operand is out of range */ | |
2727 | setcc(SW_C2); | |
2728 | FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ | |
2729 | return; | |
2730 | } | |
2731 | } else | |
2732 | if (FPU_st0_tag == TW_Zero) { | |
2733 | setcc(0); | |
2734 | return; | |
2735 | } else | |
2736 | if (FPU_st0_tag == TW_Infinity) { | |
2737 | /* Operand is out of range */ | |
2738 | setcc(SW_C2); | |
2739 | FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ | |
2740 | return; | |
2741 | } else | |
2742 | single_arg_error(); | |
2743 | } | |
2744 | ||
2745 | ||
2746 | static int | |
2747 | f_cos(FPU_REG * arg) | |
2748 | { | |
2749 | char arg_sign = arg->sign; | |
2750 | ||
2751 | if (arg->tag == TW_Valid) { | |
2752 | int q; | |
2753 | ||
2754 | #ifdef DENORM_OPERAND | |
2755 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2756 | return 1; | |
2757 | #endif /* DENORM_OPERAND */ | |
2758 | ||
2759 | arg->sign = SIGN_POS; | |
2760 | if ((q = trig_arg(arg)) != -1) { | |
2761 | FPU_REG rv; | |
2762 | ||
2763 | if (!(q & 1)) | |
2764 | reg_sub(&CONST_1, arg, arg, FULL_PRECISION); | |
2765 | ||
2766 | poly_sine(arg, &rv); | |
2767 | ||
2768 | setcc(0); | |
2769 | if ((q + 1) & 2) | |
2770 | rv.sign ^= SIGN_POS ^ SIGN_NEG; | |
2771 | reg_move(&rv, arg); | |
2772 | ||
2773 | set_precision_flag_up(); /* We do not really know | |
2774 | * if up or down */ | |
2775 | ||
2776 | return 0; | |
2777 | } else { | |
2778 | /* Operand is out of range */ | |
2779 | setcc(SW_C2); | |
2780 | arg->sign = arg_sign; /* restore st(0) */ | |
2781 | return 1; | |
2782 | } | |
2783 | } else | |
2784 | if (arg->tag == TW_Zero) { | |
2785 | reg_move(&CONST_1, arg); | |
2786 | setcc(0); | |
2787 | return 0; | |
2788 | } else | |
2789 | if (FPU_st0_tag == TW_Infinity) { | |
2790 | /* Operand is out of range */ | |
2791 | setcc(SW_C2); | |
2792 | arg->sign = arg_sign; /* restore st(0) */ | |
2793 | return 1; | |
2794 | } else { | |
2795 | single_arg_error(); /* requires arg == | |
2796 | * &st(0) */ | |
2797 | return 1; | |
2798 | } | |
2799 | } | |
2800 | ||
2801 | ||
2802 | static void | |
2803 | fcos(void) | |
2804 | { | |
2805 | f_cos(FPU_st0_ptr); | |
2806 | } | |
2807 | ||
2808 | ||
2809 | static void | |
2810 | fsincos(void) | |
2811 | { | |
2812 | FPU_REG *st_new_ptr; | |
2813 | FPU_REG arg; | |
2814 | ||
2815 | if (STACK_OVERFLOW) { | |
2816 | stack_overflow(); | |
2817 | return; | |
2818 | } | |
2819 | reg_move(FPU_st0_ptr, &arg); | |
2820 | if (!f_cos(&arg)) { | |
2821 | fsin(); | |
2822 | push(); | |
2823 | reg_move(&arg, FPU_st0_ptr); | |
2824 | } | |
2825 | } | |
2826 | ||
2827 | ||
2828 | /*---------------------------------------------------------------------------*/ | |
2829 | /* The following all require two arguments: st(0) and st(1) */ | |
2830 | ||
2831 | /* remainder of st(0) / st(1) */ | |
2832 | /* Assumes that st(0) and st(1) are both TW_Valid */ | |
2833 | static void | |
2834 | fprem_kernel(int round) | |
2835 | { | |
2836 | FPU_REG *st1_ptr = &st(1); | |
2837 | char st1_tag = st1_ptr->tag; | |
2838 | ||
2839 | if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) { | |
2840 | FPU_REG tmp; | |
2841 | int old_cw = control_word; | |
2842 | int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp; | |
2843 | ||
2844 | #ifdef DENORM_OPERAND | |
2845 | if (((FPU_st0_ptr->exp <= EXP_UNDER) || | |
2846 | (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand())) | |
2847 | return; | |
2848 | #endif /* DENORM_OPERAND */ | |
2849 | ||
2850 | control_word &= ~CW_RC; | |
2851 | control_word |= round; | |
2852 | ||
2853 | if (expdif < 64) { | |
2854 | /* This should be the most common case */ | |
2855 | long long q; | |
2856 | int c = 0; | |
2857 | ||
2858 | reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION); | |
2859 | ||
2860 | round_to_int(&tmp); /* Fortunately, this can't | |
2861 | * overflow to 2^64 */ | |
2862 | tmp.exp = EXP_BIAS + 63; | |
2863 | q = *(long long *) &(tmp.sigl); | |
2864 | normalize(&tmp); | |
2865 | ||
2866 | reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION); | |
2867 | reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION); | |
2868 | ||
2869 | if (q & 4) | |
2870 | c |= SW_C3; | |
2871 | if (q & 2) | |
2872 | c |= SW_C1; | |
2873 | if (q & 1) | |
2874 | c |= SW_C0; | |
2875 | ||
2876 | setcc(c); | |
2877 | } else { | |
2878 | /* There is a large exponent difference ( >= 64 ) */ | |
2879 | int N_exp; | |
2880 | ||
2881 | reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION); | |
2882 | /* N is 'a number between 32 and 63' (p26-113) */ | |
2883 | N_exp = (tmp.exp & 31) + 32; | |
2884 | tmp.exp = EXP_BIAS + N_exp; | |
2885 | ||
2886 | round_to_int(&tmp); /* Fortunately, this can't | |
2887 | * overflow to 2^64 */ | |
2888 | tmp.exp = EXP_BIAS + 63; | |
2889 | normalize(&tmp); | |
2890 | ||
2891 | tmp.exp = EXP_BIAS + expdif - N_exp; | |
2892 | ||
2893 | reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION); | |
2894 | reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION); | |
2895 | ||
2896 | setcc(SW_C2); | |
2897 | } | |
2898 | control_word = old_cw; | |
2899 | ||
2900 | if (FPU_st0_ptr->exp <= EXP_UNDER) | |
2901 | arith_underflow(FPU_st0_ptr); | |
2902 | return; | |
2903 | } else | |
2904 | if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) { | |
2905 | stack_underflow(); | |
2906 | return; | |
2907 | } else | |
2908 | if (FPU_st0_tag == TW_Zero) { | |
2909 | if (st1_tag == TW_Valid) { | |
2910 | ||
2911 | #ifdef DENORM_OPERAND | |
2912 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2913 | return; | |
2914 | #endif /* DENORM_OPERAND */ | |
2915 | ||
2916 | setcc(0); | |
2917 | return; | |
2918 | } else | |
2919 | if (st1_tag == TW_Zero) { | |
2920 | arith_invalid(FPU_st0_ptr); | |
2921 | return; | |
2922 | } | |
2923 | /* fprem(?,0) always invalid */ | |
2924 | else | |
2925 | if (st1_tag == TW_Infinity) { | |
2926 | setcc(0); | |
2927 | return; | |
2928 | } | |
2929 | } else | |
2930 | if (FPU_st0_tag == TW_Valid) { | |
2931 | if (st1_tag == TW_Zero) { | |
2932 | arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is | |
2933 | * invalid */ | |
2934 | return; | |
2935 | } else | |
2936 | if (st1_tag != TW_NaN) { | |
2937 | #ifdef DENORM_OPERAND | |
2938 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
2939 | return; | |
2940 | #endif /* DENORM_OPERAND */ | |
2941 | ||
2942 | if (st1_tag == TW_Infinity) { | |
2943 | /* fprem(Valid, | |
2944 | * Infinity) | |
2945 | * is o.k. */ | |
2946 | setcc(0); | |
2947 | return; | |
2948 | } | |
2949 | } | |
2950 | } else | |
2951 | if (FPU_st0_tag == TW_Infinity) { | |
2952 | if (st1_tag != TW_NaN) { | |
2953 | arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is | |
2954 | * invalid */ | |
2955 | return; | |
2956 | } | |
2957 | } | |
2958 | /* One of the registers must contain a NaN is we got here. */ | |
2959 | ||
2960 | #ifdef PARANOID | |
2961 | if ((FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN)) | |
2962 | EXCEPTION(EX_INTERNAL | 0x118); | |
2963 | #endif /* PARANOID */ | |
2964 | ||
2965 | real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); | |
2966 | ||
2967 | } | |
2968 | ||
2969 | ||
2970 | /* ST(1) <- ST(1) * log ST; pop ST */ | |
2971 | static void | |
2972 | fyl2x(void) | |
2973 | { | |
2974 | FPU_REG *st1_ptr = &st(1); | |
2975 | char st1_tag = st1_ptr->tag; | |
2976 | ||
2977 | if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) { | |
2978 | if (FPU_st0_ptr->sign == SIGN_POS) { | |
2979 | int saved_control, saved_status; | |
2980 | ||
2981 | #ifdef DENORM_OPERAND | |
2982 | if (((FPU_st0_ptr->exp <= EXP_UNDER) || | |
2983 | (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand())) | |
2984 | return; | |
2985 | #endif /* DENORM_OPERAND */ | |
2986 | ||
2987 | /* We use the general purpose arithmetic, so we need | |
2988 | * to save these. */ | |
2989 | saved_status = status_word; | |
2990 | saved_control = control_word; | |
2991 | control_word = FULL_PRECISION; | |
2992 | ||
2993 | poly_l2(FPU_st0_ptr, FPU_st0_ptr); | |
2994 | ||
2995 | /* Enough of the basic arithmetic is done now */ | |
2996 | control_word = saved_control; | |
2997 | status_word = saved_status; | |
2998 | ||
2999 | /* Let the multiply set the flags */ | |
3000 | reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); | |
3001 | ||
3002 | pop(); | |
3003 | FPU_st0_ptr = &st(0); | |
3004 | } else { | |
3005 | /* negative */ | |
3006 | pop(); | |
3007 | FPU_st0_ptr = &st(0); | |
3008 | arith_invalid(FPU_st0_ptr); /* st(0) cannot be | |
3009 | * negative */ | |
3010 | return; | |
3011 | } | |
3012 | } else | |
3013 | if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) { | |
3014 | stack_underflow_pop(1); | |
3015 | return; | |
3016 | } else | |
3017 | if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) { | |
3018 | real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); | |
3019 | pop(); | |
3020 | return; | |
3021 | } else | |
3022 | if ((FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero)) { | |
3023 | /* one of the args is zero, the other | |
3024 | * valid, or both zero */ | |
3025 | if (FPU_st0_tag == TW_Zero) { | |
3026 | pop(); | |
3027 | FPU_st0_ptr = &st(0); | |
3028 | if (FPU_st0_ptr->tag == TW_Zero) | |
3029 | arith_invalid(FPU_st0_ptr); /* Both args zero is | |
3030 | * invalid */ | |
3031 | #ifdef PECULIAR_486 | |
3032 | /* This case is not | |
3033 | * specifically covered in the | |
3034 | * manual, but divide-by-zero | |
3035 | * would seem to be the best | |
3036 | * response. However, a real | |
3037 | * 80486 does it this way... */ | |
3038 | else | |
3039 | if (FPU_st0_ptr->tag == TW_Infinity) { | |
3040 | reg_move(&CONST_INF, FPU_st0_ptr); | |
3041 | return; | |
3042 | } | |
3043 | #endif /* PECULIAR_486 */ | |
3044 | else | |
3045 | divide_by_zero(st1_ptr->sign ^ SIGN_NEG ^ SIGN_POS, FPU_st0_ptr); | |
3046 | return; | |
3047 | } else { | |
3048 | /* st(1) contains zero, st(0) | |
3049 | * valid <> 0 */ | |
3050 | /* Zero is the valid answer */ | |
3051 | char sign = st1_ptr->sign; | |
3052 | ||
3053 | #ifdef DENORM_OPERAND | |
3054 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3055 | return; | |
3056 | #endif /* DENORM_OPERAND */ | |
3057 | if (FPU_st0_ptr->sign == SIGN_NEG) { | |
3058 | pop(); | |
3059 | FPU_st0_ptr = &st(0); | |
3060 | arith_invalid(FPU_st0_ptr); /* log(negative) */ | |
3061 | return; | |
3062 | } | |
3063 | if (FPU_st0_ptr->exp < EXP_BIAS) | |
3064 | sign ^= SIGN_NEG ^ SIGN_POS; | |
3065 | pop(); | |
3066 | FPU_st0_ptr = &st(0); | |
3067 | reg_move(&CONST_Z, FPU_st0_ptr); | |
3068 | FPU_st0_ptr->sign = sign; | |
3069 | return; | |
3070 | } | |
3071 | } | |
3072 | /* One or both arg must be an infinity */ | |
3073 | else | |
3074 | if (FPU_st0_tag == TW_Infinity) { | |
3075 | if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) { | |
3076 | pop(); | |
3077 | FPU_st0_ptr = &st(0); | |
3078 | arith_invalid(FPU_st0_ptr); /* log(-infinity) or | |
3079 | * 0*log(infinity) */ | |
3080 | return; | |
3081 | } else { | |
3082 | char sign = st1_ptr->sign; | |
3083 | ||
3084 | #ifdef DENORM_OPERAND | |
3085 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3086 | return; | |
3087 | #endif /* DENORM_OPERAND */ | |
3088 | ||
3089 | pop(); | |
3090 | FPU_st0_ptr = &st(0); | |
3091 | reg_move(&CONST_INF, FPU_st0_ptr); | |
3092 | FPU_st0_ptr->sign = sign; | |
3093 | return; | |
3094 | } | |
3095 | } | |
3096 | /* st(1) must be infinity here */ | |
3097 | else | |
3098 | if ((FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS)) { | |
3099 | if (FPU_st0_ptr->exp >= EXP_BIAS) { | |
3100 | if ((FPU_st0_ptr->exp == EXP_BIAS) && | |
3101 | (FPU_st0_ptr->sigh == 0x80000000) && | |
3102 | (FPU_st0_ptr->sigl == 0)) { | |
3103 | /* st(0 | |
3104 | * ) | |
3105 | * hold | |
3106 | * s | |
3107 | * 1.0 */ | |
3108 | pop(); | |
3109 | FPU_st0_ptr = &st(0); | |
3110 | arith_invalid(FPU_st0_ptr); /* infinity*log(1) */ | |
3111 | return; | |
3112 | } | |
3113 | /* st(0) is | |
3114 | * positive | |
3115 | * and > 1.0 */ | |
3116 | pop(); | |
3117 | } else { | |
3118 | /* st(0) is | |
3119 | * positive | |
3120 | * and < 1.0 */ | |
3121 | ||
3122 | #ifdef DENORM_OPERAND | |
3123 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3124 | return; | |
3125 | #endif /* DENORM_OPERAND */ | |
3126 | ||
3127 | st1_ptr->sign ^= SIGN_NEG; | |
3128 | pop(); | |
3129 | } | |
3130 | return; | |
3131 | } else { | |
3132 | /* st(0) must be zero | |
3133 | * or negative */ | |
3134 | if (FPU_st0_ptr->tag == TW_Zero) { | |
3135 | pop(); | |
3136 | FPU_st0_ptr = st1_ptr; | |
3137 | st1_ptr->sign ^= SIGN_NEG ^ SIGN_POS; | |
3138 | /* This should | |
3139 | * be invalid, | |
3140 | * but a real | |
3141 | * 80486 is | |
3142 | * happy with | |
3143 | * it. */ | |
3144 | #ifndef PECULIAR_486 | |
3145 | divide_by_zero(st1_ptr->sign, FPU_st0_ptr); | |
3146 | #endif /* PECULIAR_486 */ | |
3147 | } else { | |
3148 | pop(); | |
3149 | FPU_st0_ptr = st1_ptr; | |
3150 | arith_invalid(FPU_st0_ptr); /* log(negative) */ | |
3151 | } | |
3152 | return; | |
3153 | } | |
3154 | } | |
3155 | ||
3156 | ||
3157 | static void | |
3158 | fpatan(void) | |
3159 | { | |
3160 | FPU_REG *st1_ptr = &st(1); | |
3161 | char st1_tag = st1_ptr->tag; | |
3162 | ||
3163 | if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) { | |
3164 | int saved_control, saved_status; | |
3165 | FPU_REG sum; | |
3166 | int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign) << 1); | |
3167 | ||
3168 | #ifdef DENORM_OPERAND | |
3169 | if (((FPU_st0_ptr->exp <= EXP_UNDER) || | |
3170 | (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand())) | |
3171 | return; | |
3172 | #endif /* DENORM_OPERAND */ | |
3173 | ||
3174 | /* We use the general purpose arithmetic so we need to save | |
3175 | * these. */ | |
3176 | saved_status = status_word; | |
3177 | saved_control = control_word; | |
3178 | control_word = FULL_PRECISION; | |
3179 | ||
3180 | st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS; | |
3181 | if (compare(st1_ptr) == COMP_A_lt_B) { | |
3182 | quadrant |= 4; | |
3183 | reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION); | |
3184 | } else | |
3185 | reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION); | |
3186 | ||
3187 | poly_atan(&sum); | |
3188 | ||
3189 | if (quadrant & 4) { | |
3190 | reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION); | |
3191 | } | |
3192 | if (quadrant & 2) { | |
3193 | reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION); | |
3194 | } | |
3195 | if (quadrant & 1) | |
3196 | sum.sign ^= SIGN_POS ^ SIGN_NEG; | |
3197 | ||
3198 | /* All of the basic arithmetic is done now */ | |
3199 | control_word = saved_control; | |
3200 | status_word = saved_status; | |
3201 | ||
3202 | reg_move(&sum, st1_ptr); | |
3203 | } else | |
3204 | if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) { | |
3205 | stack_underflow_pop(1); | |
3206 | return; | |
3207 | } else | |
3208 | if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) { | |
3209 | real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); | |
3210 | pop(); | |
3211 | return; | |
3212 | } else | |
3213 | if ((FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) { | |
3214 | char sign = st1_ptr->sign; | |
3215 | if (FPU_st0_tag == TW_Infinity) { | |
3216 | if (st1_tag == TW_Infinity) { | |
3217 | if (FPU_st0_ptr->sign == SIGN_POS) { | |
3218 | reg_move(&CONST_PI4, st1_ptr); | |
3219 | } else | |
3220 | reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION); | |
3221 | } else { | |
3222 | ||
3223 | #ifdef DENORM_OPERAND | |
3224 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3225 | return; | |
3226 | #endif /* DENORM_OPERAND */ | |
3227 | ||
3228 | if (FPU_st0_ptr->sign == SIGN_POS) { | |
3229 | reg_move(&CONST_Z, st1_ptr); | |
3230 | pop(); | |
3231 | return; | |
3232 | } else | |
3233 | reg_move(&CONST_PI, st1_ptr); | |
3234 | } | |
3235 | } else { | |
3236 | /* st(1) is infinity, st(0) | |
3237 | * not infinity */ | |
3238 | #ifdef DENORM_OPERAND | |
3239 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3240 | return; | |
3241 | #endif /* DENORM_OPERAND */ | |
3242 | ||
3243 | reg_move(&CONST_PI2, st1_ptr); | |
3244 | } | |
3245 | st1_ptr->sign = sign; | |
3246 | } else | |
3247 | if (st1_tag == TW_Zero) { | |
3248 | /* st(0) must be valid or zero */ | |
3249 | char sign = st1_ptr->sign; | |
3250 | ||
3251 | #ifdef DENORM_OPERAND | |
3252 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3253 | return; | |
3254 | #endif /* DENORM_OPERAND */ | |
3255 | ||
3256 | if (FPU_st0_ptr->sign == SIGN_POS) { | |
3257 | reg_move(&CONST_Z, st1_ptr); | |
3258 | pop(); | |
3259 | return; | |
3260 | } else | |
3261 | reg_move(&CONST_PI, st1_ptr); | |
3262 | st1_ptr->sign = sign; | |
3263 | } else | |
3264 | if (FPU_st0_tag == TW_Zero) { | |
3265 | /* st(1) must be | |
3266 | * TW_Valid here */ | |
3267 | char sign = st1_ptr->sign; | |
3268 | ||
3269 | #ifdef DENORM_OPERAND | |
3270 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3271 | return; | |
3272 | #endif /* DENORM_OPERAND */ | |
3273 | ||
3274 | reg_move(&CONST_PI2, st1_ptr); | |
3275 | st1_ptr->sign = sign; | |
3276 | } | |
3277 | #ifdef PARANOID | |
3278 | else | |
3279 | EXCEPTION(EX_INTERNAL | 0x220); | |
3280 | #endif /* PARANOID */ | |
3281 | ||
3282 | pop(); | |
3283 | set_precision_flag_up();/* We do not really know if up or down */ | |
3284 | } | |
3285 | ||
3286 | ||
3287 | static void | |
3288 | fprem(void) | |
3289 | { | |
3290 | fprem_kernel(RC_CHOP); | |
3291 | } | |
3292 | ||
3293 | ||
3294 | static void | |
3295 | fprem1(void) | |
3296 | { | |
3297 | fprem_kernel(RC_RND); | |
3298 | } | |
3299 | ||
3300 | ||
3301 | static void | |
3302 | fyl2xp1(void) | |
3303 | { | |
3304 | FPU_REG *st1_ptr = &st(1); | |
3305 | char st1_tag = st1_ptr->tag; | |
3306 | ||
3307 | if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) { | |
3308 | int saved_control, saved_status; | |
3309 | ||
3310 | #ifdef DENORM_OPERAND | |
3311 | if (((FPU_st0_ptr->exp <= EXP_UNDER) || | |
3312 | (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand())) | |
3313 | return; | |
3314 | #endif /* DENORM_OPERAND */ | |
3315 | ||
3316 | /* We use the general purpose arithmetic so we need to save | |
3317 | * these. */ | |
3318 | saved_status = status_word; | |
3319 | saved_control = control_word; | |
3320 | control_word = FULL_PRECISION; | |
3321 | ||
3322 | if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) { | |
3323 | arith_invalid(st1_ptr); /* poly_l2p1() returned | |
3324 | * invalid */ | |
3325 | pop(); | |
3326 | return; | |
3327 | } | |
3328 | /* Enough of the basic arithmetic is done now */ | |
3329 | control_word = saved_control; | |
3330 | status_word = saved_status; | |
3331 | ||
3332 | /* Let the multiply set the flags */ | |
3333 | reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); | |
3334 | ||
3335 | pop(); | |
3336 | } else | |
3337 | if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) { | |
3338 | stack_underflow_pop(1); | |
3339 | return; | |
3340 | } else | |
3341 | if (FPU_st0_tag == TW_Zero) { | |
3342 | if (st1_tag <= TW_Zero) { | |
3343 | ||
3344 | #ifdef DENORM_OPERAND | |
3345 | if ((st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) && | |
3346 | (denormal_operand())) | |
3347 | return; | |
3348 | #endif /* DENORM_OPERAND */ | |
3349 | ||
3350 | st1_ptr->sign ^= FPU_st0_ptr->sign; | |
3351 | reg_move(FPU_st0_ptr, st1_ptr); | |
3352 | } else | |
3353 | if (st1_tag == TW_Infinity) { | |
3354 | arith_invalid(st1_ptr); /* Infinity*log(1) */ | |
3355 | pop(); | |
3356 | return; | |
3357 | } else | |
3358 | if (st1_tag == TW_NaN) { | |
3359 | real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); | |
3360 | pop(); | |
3361 | return; | |
3362 | } | |
3363 | #ifdef PARANOID | |
3364 | else { | |
3365 | EXCEPTION(EX_INTERNAL | 0x116); | |
3366 | return; | |
3367 | } | |
3368 | #endif /* PARANOID */ | |
3369 | pop(); | |
3370 | return; | |
3371 | } else | |
3372 | if (FPU_st0_tag == TW_Valid) { | |
3373 | if (st1_tag == TW_Zero) { | |
3374 | if (FPU_st0_ptr->sign == SIGN_NEG) { | |
3375 | if (FPU_st0_ptr->exp >= EXP_BIAS) { | |
3376 | /* st(0) holds | |
3377 | * <= -1.0 */ | |
3378 | arith_invalid(st1_ptr); /* infinity*log(1) */ | |
3379 | pop(); | |
3380 | return; | |
3381 | } | |
3382 | #ifdef DENORM_OPERAND | |
3383 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3384 | return; | |
3385 | #endif /* DENORM_OPERAND */ | |
3386 | st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG; | |
3387 | pop(); | |
3388 | return; | |
3389 | } | |
3390 | #ifdef DENORM_OPERAND | |
3391 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3392 | return; | |
3393 | #endif /* DENORM_OPERAND */ | |
3394 | pop(); | |
3395 | return; | |
3396 | } | |
3397 | if (st1_tag == TW_Infinity) { | |
3398 | if (FPU_st0_ptr->sign == SIGN_NEG) { | |
3399 | if ((FPU_st0_ptr->exp >= EXP_BIAS) && | |
3400 | !((FPU_st0_ptr->sigh == 0x80000000) && | |
3401 | (FPU_st0_ptr->sigl == 0))) { | |
3402 | /* st(0) holds | |
3403 | * < -1.0 */ | |
3404 | arith_invalid(st1_ptr); | |
3405 | pop(); | |
3406 | return; | |
3407 | } | |
3408 | #ifdef DENORM_OPERAND | |
3409 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3410 | return; | |
3411 | #endif /* DENORM_OPERAND */ | |
3412 | st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG; | |
3413 | pop(); | |
3414 | return; | |
3415 | } | |
3416 | #ifdef DENORM_OPERAND | |
3417 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3418 | return; | |
3419 | #endif /* DENORM_OPERAND */ | |
3420 | pop(); | |
3421 | return; | |
3422 | } | |
3423 | if (st1_tag == TW_NaN) { | |
3424 | real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); | |
3425 | pop(); | |
3426 | return; | |
3427 | } | |
3428 | } else | |
3429 | if (FPU_st0_tag == TW_NaN) { | |
3430 | real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); | |
3431 | pop(); | |
3432 | return; | |
3433 | } else | |
3434 | if (FPU_st0_tag == TW_Infinity) { | |
3435 | if (st1_tag == TW_NaN) { | |
3436 | real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr); | |
3437 | pop(); | |
3438 | return; | |
3439 | } else | |
3440 | if ((FPU_st0_ptr->sign == SIGN_NEG) || | |
3441 | (st1_tag == TW_Zero)) { | |
3442 | arith_invalid(st1_ptr); /* log(infinity) */ | |
3443 | pop(); | |
3444 | return; | |
3445 | } | |
3446 | /* st(1) must be valid | |
3447 | * here. */ | |
3448 | ||
3449 | #ifdef DENORM_OPERAND | |
3450 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3451 | return; | |
3452 | #endif /* DENORM_OPERAND */ | |
3453 | ||
3454 | /* The Manual says | |
3455 | * that log(Infinity) | |
3456 | * is invalid, but a | |
3457 | * real 80486 sensibly | |
3458 | * says that it is | |
3459 | * o.k. */ | |
3460 | { | |
3461 | char sign = st1_ptr->sign; | |
3462 | reg_move(&CONST_INF, st1_ptr); | |
3463 | st1_ptr->sign = sign; | |
3464 | } | |
3465 | pop(); | |
3466 | return; | |
3467 | } | |
3468 | #ifdef PARANOID | |
3469 | else { | |
3470 | EXCEPTION(EX_INTERNAL | 0x117); | |
3471 | } | |
3472 | #endif /* PARANOID */ | |
3473 | } | |
3474 | ||
3475 | ||
3476 | static void | |
3477 | fscale(void) | |
3478 | { | |
3479 | FPU_REG *st1_ptr = &st(1); | |
3480 | char st1_tag = st1_ptr->tag; | |
3481 | int old_cw = control_word; | |
3482 | ||
3483 | if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) { | |
3484 | long scale; | |
3485 | FPU_REG tmp; | |
3486 | ||
3487 | #ifdef DENORM_OPERAND | |
3488 | if (((FPU_st0_ptr->exp <= EXP_UNDER) || | |
3489 | (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand())) | |
3490 | return; | |
3491 | #endif /* DENORM_OPERAND */ | |
3492 | ||
3493 | if (st1_ptr->exp > EXP_BIAS + 30) { | |
3494 | /* 2^31 is far too large, would require 2^(2^30) or | |
3495 | * 2^(-2^30) */ | |
3496 | char sign; | |
3497 | ||
3498 | if (st1_ptr->sign == SIGN_POS) { | |
3499 | EXCEPTION(EX_Overflow); | |
3500 | sign = FPU_st0_ptr->sign; | |
3501 | reg_move(&CONST_INF, FPU_st0_ptr); | |
3502 | FPU_st0_ptr->sign = sign; | |
3503 | } else { | |
3504 | EXCEPTION(EX_Underflow); | |
3505 | sign = FPU_st0_ptr->sign; | |
3506 | reg_move(&CONST_Z, FPU_st0_ptr); | |
3507 | FPU_st0_ptr->sign = sign; | |
3508 | } | |
3509 | return; | |
3510 | } | |
3511 | control_word &= ~CW_RC; | |
3512 | control_word |= RC_CHOP; | |
3513 | reg_move(st1_ptr, &tmp); | |
3514 | round_to_int(&tmp); /* This can never overflow here */ | |
3515 | control_word = old_cw; | |
3516 | scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl; | |
3517 | scale += FPU_st0_ptr->exp; | |
3518 | FPU_st0_ptr->exp = scale; | |
3519 | ||
3520 | /* Use round_reg() to properly detect under/overflow etc */ | |
3521 | round_reg(FPU_st0_ptr, 0, control_word); | |
3522 | ||
3523 | return; | |
3524 | } else | |
3525 | if (FPU_st0_tag == TW_Valid) { | |
3526 | if (st1_tag == TW_Zero) { | |
3527 | ||
3528 | #ifdef DENORM_OPERAND | |
3529 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3530 | return; | |
3531 | #endif /* DENORM_OPERAND */ | |
3532 | ||
3533 | return; | |
3534 | } | |
3535 | if (st1_tag == TW_Infinity) { | |
3536 | char sign = st1_ptr->sign; | |
3537 | ||
3538 | #ifdef DENORM_OPERAND | |
3539 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3540 | return; | |
3541 | #endif /* DENORM_OPERAND */ | |
3542 | ||
3543 | if (sign == SIGN_POS) { | |
3544 | reg_move(&CONST_INF, FPU_st0_ptr); | |
3545 | } else | |
3546 | reg_move(&CONST_Z, FPU_st0_ptr); | |
3547 | FPU_st0_ptr->sign = sign; | |
3548 | return; | |
3549 | } | |
3550 | if (st1_tag == TW_NaN) { | |
3551 | real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); | |
3552 | return; | |
3553 | } | |
3554 | } else | |
3555 | if (FPU_st0_tag == TW_Zero) { | |
3556 | if (st1_tag == TW_Valid) { | |
3557 | ||
3558 | #ifdef DENORM_OPERAND | |
3559 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3560 | return; | |
3561 | #endif /* DENORM_OPERAND */ | |
3562 | ||
3563 | return; | |
3564 | } else | |
3565 | if (st1_tag == TW_Zero) { | |
3566 | return; | |
3567 | } else | |
3568 | if (st1_tag == TW_Infinity) { | |
3569 | if (st1_ptr->sign == SIGN_NEG) | |
3570 | return; | |
3571 | else { | |
3572 | arith_invalid(FPU_st0_ptr); /* Zero scaled by | |
3573 | * +Infinity */ | |
3574 | return; | |
3575 | } | |
3576 | } else | |
3577 | if (st1_tag == TW_NaN) { | |
3578 | real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); | |
3579 | return; | |
3580 | } | |
3581 | } else | |
3582 | if (FPU_st0_tag == TW_Infinity) { | |
3583 | if (st1_tag == TW_Valid) { | |
3584 | ||
3585 | #ifdef DENORM_OPERAND | |
3586 | if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
3587 | return; | |
3588 | #endif /* DENORM_OPERAND */ | |
3589 | ||
3590 | return; | |
3591 | } | |
3592 | if (((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS)) | |
3593 | || (st1_tag == TW_Zero)) | |
3594 | return; | |
3595 | else | |
3596 | if (st1_tag == TW_Infinity) { | |
3597 | arith_invalid(FPU_st0_ptr); /* Infinity scaled by | |
3598 | * -Infinity */ | |
3599 | return; | |
3600 | } else | |
3601 | if (st1_tag == TW_NaN) { | |
3602 | real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); | |
3603 | return; | |
3604 | } | |
3605 | } else | |
3606 | if (FPU_st0_tag == TW_NaN) { | |
3607 | if (st1_tag != TW_Empty) { | |
3608 | real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); | |
3609 | return; | |
3610 | } | |
3611 | } | |
3612 | #ifdef PARANOID | |
3613 | if (!((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty))) { | |
3614 | EXCEPTION(EX_INTERNAL | 0x115); | |
3615 | return; | |
3616 | } | |
3617 | #endif | |
3618 | ||
3619 | /* At least one of st(0), st(1) must be empty */ | |
3620 | stack_underflow(); | |
3621 | ||
3622 | } | |
3623 | ||
3624 | ||
3625 | /*---------------------------------------------------------------------------*/ | |
3626 | ||
3627 | static FUNC trig_table_a[] = { | |
3628 | f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp | |
3629 | }; | |
3630 | ||
3631 | void | |
3632 | trig_a(void) | |
3633 | { | |
3634 | (trig_table_a[FPU_rm]) (); | |
3635 | } | |
3636 | ||
3637 | ||
3638 | static FUNC trig_table_b[] = | |
3639 | { | |
3640 | fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos | |
3641 | }; | |
3642 | ||
3643 | void | |
3644 | trig_b(void) | |
3645 | { | |
3646 | (trig_table_b[FPU_rm]) (); | |
3647 | } | |
3648 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/get_address.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 13050 5462320160 13213\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
3649 | * get_address.c | |
3650 | * | |
3651 | * Get the effective address from an FPU instruction. | |
3652 | * | |
3653 | * | |
3654 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
3655 | * Vic 3163, Australia. | |
3656 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
3657 | * All rights reserved. | |
3658 | * | |
3659 | * This copyright notice covers the redistribution and use of the | |
3660 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
3661 | * in the 386BSD operating system. Any other use is not permitted | |
3662 | * under this copyright. | |
3663 | * | |
3664 | * Redistribution and use in source and binary forms, with or without | |
3665 | * modification, are permitted provided that the following conditions | |
3666 | * are met: | |
3667 | * 1. Redistributions of source code must retain the above copyright | |
3668 | * notice, this list of conditions and the following disclaimer. | |
3669 | * 2. Redistributions in binary form must include information specifying | |
3670 | * that source code for the emulator is freely available and include | |
3671 | * either: | |
3672 | * a) an offer to provide the source code for a nominal distribution | |
3673 | * fee, or | |
3674 | * b) list at least two alternative methods whereby the source | |
3675 | * can be obtained, e.g. a publically accessible bulletin board | |
3676 | * and an anonymous ftp site from which the software can be | |
3677 | * downloaded. | |
3678 | * 3. All advertising materials specifically mentioning features or use of | |
3679 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
3680 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
3681 | * products derived from this software without specific prior written | |
3682 | * permission. | |
3683 | * | |
3684 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
3685 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
3686 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
3687 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
3688 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
3689 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
3690 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
3691 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
3692 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
3693 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
3694 | * | |
3695 | */ | |
3696 | ||
3697 | /*---------------------------------------------------------------------------+ | |
3698 | | Note: | | |
3699 | | The file contains code which accesses user memory. | | |
3700 | | Emulator static data may change when user memory is accessed, due to | | |
3701 | | other processes using the emulator while swapping is in progress. | | |
3702 | +---------------------------------------------------------------------------*/ | |
3703 | ||
3704 | #include "param.h" | |
3705 | #include "proc.h" | |
3706 | #include "systm.h" | |
3707 | #include "machine/cpu.h" | |
3708 | #include "machine/pcb.h" | |
3709 | #include "machine/reg.h" | |
3710 | ||
3711 | #include "fpu_emu.h" | |
3712 | #include "fpu_system.h" | |
3713 | #include "exception.h" | |
3714 | ||
3715 | static int reg_offset[] = { | |
3716 | tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI}; | |
3717 | #define REG_(x) (*(((int*)FPU_info) + reg_offset[(x)])) | |
3718 | ||
3719 | void *FPU_data_address; | |
3720 | ||
3721 | ||
3722 | /* Decode the SIB byte. This function assumes mod != 0 */ | |
3723 | static void * | |
3724 | sib(int mod) | |
3725 | { | |
3726 | unsigned char ss, index, base; | |
3727 | long offset; | |
3728 | ||
3729 | REENTRANT_CHECK(OFF); | |
3730 | base = fubyte((char *) FPU_EIP); /* The SIB byte */ | |
3731 | REENTRANT_CHECK(ON); | |
3732 | FPU_EIP++; | |
3733 | ss = base >> 6; | |
3734 | index = (base >> 3) & 7; | |
3735 | base &= 7; | |
3736 | ||
3737 | if ((mod == 0) && (base == 5)) | |
3738 | offset = 0; /* No base register */ | |
3739 | else | |
3740 | offset = REG_(base); | |
3741 | ||
3742 | if (index == 4) { | |
3743 | /* No index register */ | |
3744 | /* A non-zero ss is illegal */ | |
3745 | if (ss) | |
3746 | EXCEPTION(EX_Invalid); | |
3747 | } else { | |
3748 | offset += (REG_(index)) << ss; | |
3749 | } | |
3750 | ||
3751 | if (mod == 1) { | |
3752 | /* 8 bit signed displacement */ | |
3753 | REENTRANT_CHECK(OFF); | |
3754 | offset += (signed char) fubyte((char *) FPU_EIP); | |
3755 | REENTRANT_CHECK(ON); | |
3756 | FPU_EIP++; | |
3757 | } else | |
3758 | if (mod == 2 || base == 5) { /* The second condition also | |
3759 | * has mod==0 */ | |
3760 | /* 32 bit displacment */ | |
3761 | REENTRANT_CHECK(OFF); | |
3762 | offset += (signed) fuword((unsigned long *) FPU_EIP); | |
3763 | REENTRANT_CHECK(ON); | |
3764 | FPU_EIP += 4; | |
3765 | } | |
3766 | return (void *) offset; | |
3767 | } | |
3768 | ||
3769 | ||
3770 | /* | |
3771 | MOD R/M byte: MOD == 3 has a special use for the FPU | |
3772 | SIB byte used iff R/M = 100b | |
3773 | ||
3774 | 7 6 5 4 3 2 1 0 | |
3775 | ..... ......... ......... | |
3776 | MOD OPCODE(2) R/M | |
3777 | ||
3778 | ||
3779 | SIB byte | |
3780 | ||
3781 | 7 6 5 4 3 2 1 0 | |
3782 | ..... ......... ......... | |
3783 | SS INDEX BASE | |
3784 | ||
3785 | */ | |
3786 | ||
3787 | void | |
3788 | get_address(unsigned char FPU_modrm) | |
3789 | { | |
3790 | unsigned char mod; | |
3791 | long *cpu_reg_ptr; | |
3792 | int offset = 0; /* Initialized just to stop compiler warnings. */ | |
3793 | ||
3794 | mod = (FPU_modrm >> 6) & 3; | |
3795 | ||
3796 | if (FPU_rm == 4 && mod != 3) { | |
3797 | FPU_data_address = sib(mod); | |
3798 | return; | |
3799 | } | |
3800 | cpu_reg_ptr = (long *) ®_(FPU_rm); | |
3801 | switch (mod) { | |
3802 | case 0: | |
3803 | if (FPU_rm == 5) { | |
3804 | /* Special case: disp32 */ | |
3805 | REENTRANT_CHECK(OFF); | |
3806 | offset = fuword((unsigned long *) FPU_EIP); | |
3807 | REENTRANT_CHECK(ON); | |
3808 | FPU_EIP += 4; | |
3809 | FPU_data_address = (void *) offset; | |
3810 | return; | |
3811 | } else { | |
3812 | FPU_data_address = (void *) *cpu_reg_ptr; /* Just return the | |
3813 | * contents of the cpu | |
3814 | * register */ | |
3815 | return; | |
3816 | } | |
3817 | case 1: | |
3818 | /* 8 bit signed displacement */ | |
3819 | REENTRANT_CHECK(OFF); | |
3820 | offset = (signed char) fubyte((char *) FPU_EIP); | |
3821 | REENTRANT_CHECK(ON); | |
3822 | FPU_EIP++; | |
3823 | break; | |
3824 | case 2: | |
3825 | /* 32 bit displacement */ | |
3826 | REENTRANT_CHECK(OFF); | |
3827 | offset = (signed) fuword((unsigned long *) FPU_EIP); | |
3828 | REENTRANT_CHECK(ON); | |
3829 | FPU_EIP += 4; | |
3830 | break; | |
3831 | case 3: | |
3832 | /* Not legal for the FPU */ | |
3833 | EXCEPTION(EX_Invalid); | |
3834 | } | |
3835 | ||
3836 | FPU_data_address = offset + (char *) *cpu_reg_ptr; | |
3837 | } | |
3838 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/load_store.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 20476 5462501712 13100\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
3839 | * load_store.c | |
3840 | * | |
3841 | * This file contains most of the code to interpret the FPU instructions | |
3842 | * which load and store from user memory. | |
3843 | * | |
3844 | * | |
3845 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
3846 | * Vic 3163, Australia. | |
3847 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
3848 | * All rights reserved. | |
3849 | * | |
3850 | * This copyright notice covers the redistribution and use of the | |
3851 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
3852 | * in the 386BSD operating system. Any other use is not permitted | |
3853 | * under this copyright. | |
3854 | * | |
3855 | * Redistribution and use in source and binary forms, with or without | |
3856 | * modification, are permitted provided that the following conditions | |
3857 | * are met: | |
3858 | * 1. Redistributions of source code must retain the above copyright | |
3859 | * notice, this list of conditions and the following disclaimer. | |
3860 | * 2. Redistributions in binary form must include information specifying | |
3861 | * that source code for the emulator is freely available and include | |
3862 | * either: | |
3863 | * a) an offer to provide the source code for a nominal distribution | |
3864 | * fee, or | |
3865 | * b) list at least two alternative methods whereby the source | |
3866 | * can be obtained, e.g. a publically accessible bulletin board | |
3867 | * and an anonymous ftp site from which the software can be | |
3868 | * downloaded. | |
3869 | * 3. All advertising materials specifically mentioning features or use of | |
3870 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
3871 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
3872 | * products derived from this software without specific prior written | |
3873 | * permission. | |
3874 | * | |
3875 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
3876 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
3877 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
3878 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
3879 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
3880 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
3881 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
3882 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
3883 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
3884 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
3885 | * | |
3886 | */ | |
3887 | ||
3888 | /*---------------------------------------------------------------------------+ | |
3889 | | Note: | | |
3890 | | The file contains code which accesses user memory. | | |
3891 | | Emulator static data may change when user memory is accessed, due to | | |
3892 | | other processes using the emulator while swapping is in progress. | | |
3893 | +---------------------------------------------------------------------------*/ | |
3894 | ||
3895 | #include "param.h" | |
3896 | #include "proc.h" | |
3897 | #include "systm.h" | |
3898 | #include "machine/cpu.h" | |
3899 | #include "machine/pcb.h" | |
3900 | ||
3901 | #include "fpu_emu.h" | |
3902 | #include "fpu_system.h" | |
3903 | #include "exception.h" | |
3904 | #include "status_w.h" | |
3905 | ||
3906 | ||
3907 | #define _NONE_ 0 /* FPU_st0_ptr etc not needed */ | |
3908 | #define _REG0_ 1 /* Will be storing st(0) */ | |
3909 | #define _PUSH_ 3 /* Need to check for space to push onto stack */ | |
3910 | #define _null_ 4 /* Function illegal or not implemented */ | |
3911 | ||
3912 | #define pop_0() { pop_ptr->tag = TW_Empty; top++; } | |
3913 | ||
3914 | ||
3915 | static unsigned char type_table[32] = { | |
3916 | _PUSH_, _PUSH_, _PUSH_, _PUSH_, | |
3917 | _null_, _null_, _null_, _null_, | |
3918 | _REG0_, _REG0_, _REG0_, _REG0_, | |
3919 | _REG0_, _REG0_, _REG0_, _REG0_, | |
3920 | _NONE_, _null_, _NONE_, _PUSH_, | |
3921 | _NONE_, _PUSH_, _null_, _PUSH_, | |
3922 | _NONE_, _null_, _NONE_, _REG0_, | |
3923 | _NONE_, _REG0_, _NONE_, _REG0_ | |
3924 | }; | |
3925 | ||
3926 | void | |
3927 | load_store_instr(char type) | |
3928 | { | |
3929 | FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which | |
3930 | * won't change. */ | |
3931 | ||
3932 | pop_ptr = NULL; /* Initialized just to stop compiler warnings. */ | |
3933 | ||
3934 | ||
3935 | switch (type_table[(int) (unsigned) type]) { | |
3936 | case _NONE_: | |
3937 | break; | |
3938 | case _REG0_: | |
3939 | pop_ptr = &st(0); /* Some of these instructions pop | |
3940 | * after storing */ | |
3941 | ||
3942 | FPU_st0_ptr = pop_ptr; /* Set the global variables. */ | |
3943 | FPU_st0_tag = FPU_st0_ptr->tag; | |
3944 | break; | |
3945 | case _PUSH_: | |
3946 | { | |
3947 | pop_ptr = &st(-1); | |
3948 | if (pop_ptr->tag != TW_Empty) { | |
3949 | stack_overflow(); | |
3950 | return; | |
3951 | } | |
3952 | top--; | |
3953 | } | |
3954 | break; | |
3955 | case _null_: | |
3956 | return Un_impl(); | |
3957 | #ifdef PARANOID | |
3958 | default: | |
3959 | return EXCEPTION(EX_INTERNAL); | |
3960 | #endif /* PARANOID */ | |
3961 | } | |
3962 | ||
3963 | switch (type) { | |
3964 | case 000: /* fld m32real */ | |
3965 | reg_load_single(); | |
3966 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
3967 | reg_move(&FPU_loaded_data, pop_ptr); | |
3968 | break; | |
3969 | case 001: /* fild m32int */ | |
3970 | reg_load_int32(); | |
3971 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
3972 | reg_move(&FPU_loaded_data, pop_ptr); | |
3973 | break; | |
3974 | case 002: /* fld m64real */ | |
3975 | reg_load_double(); | |
3976 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
3977 | reg_move(&FPU_loaded_data, pop_ptr); | |
3978 | break; | |
3979 | case 003: /* fild m16int */ | |
3980 | reg_load_int16(); | |
3981 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
3982 | reg_move(&FPU_loaded_data, pop_ptr); | |
3983 | break; | |
3984 | case 010: /* fst m32real */ | |
3985 | reg_store_single(); | |
3986 | break; | |
3987 | case 011: /* fist m32int */ | |
3988 | reg_store_int32(); | |
3989 | break; | |
3990 | case 012: /* fst m64real */ | |
3991 | reg_store_double(); | |
3992 | break; | |
3993 | case 013: /* fist m16int */ | |
3994 | reg_store_int16(); | |
3995 | break; | |
3996 | case 014: /* fstp m32real */ | |
3997 | if (reg_store_single()) | |
3998 | pop_0();/* pop only if the number was actually stored | |
3999 | * (see the 80486 manual p16-28) */ | |
4000 | break; | |
4001 | case 015: /* fistp m32int */ | |
4002 | if (reg_store_int32()) | |
4003 | pop_0();/* pop only if the number was actually stored | |
4004 | * (see the 80486 manual p16-28) */ | |
4005 | break; | |
4006 | case 016: /* fstp m64real */ | |
4007 | if (reg_store_double()) | |
4008 | pop_0();/* pop only if the number was actually stored | |
4009 | * (see the 80486 manual p16-28) */ | |
4010 | break; | |
4011 | case 017: /* fistp m16int */ | |
4012 | if (reg_store_int16()) | |
4013 | pop_0();/* pop only if the number was actually stored | |
4014 | * (see the 80486 manual p16-28) */ | |
4015 | break; | |
4016 | case 020: /* fldenv m14/28byte */ | |
4017 | fldenv(); | |
4018 | break; | |
4019 | case 022: /* frstor m94/108byte */ | |
4020 | frstor(); | |
4021 | break; | |
4022 | case 023: /* fbld m80dec */ | |
4023 | reg_load_bcd(); | |
4024 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
4025 | reg_move(&FPU_loaded_data, pop_ptr); | |
4026 | break; | |
4027 | case 024: /* fldcw */ | |
4028 | REENTRANT_CHECK(OFF); | |
4029 | control_word = fuword((unsigned short *) FPU_data_address); | |
4030 | REENTRANT_CHECK(ON); | |
4031 | #ifdef NO_UNDERFLOW_TRAP | |
4032 | if (!(control_word & EX_Underflow)) { | |
4033 | control_word |= EX_Underflow; | |
4034 | } | |
4035 | #endif | |
4036 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
4037 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
4038 | break; | |
4039 | case 025: /* fld m80real */ | |
4040 | reg_load_extended(); | |
4041 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
4042 | reg_move(&FPU_loaded_data, pop_ptr); | |
4043 | break; | |
4044 | case 027: /* fild m64int */ | |
4045 | reg_load_int64(); | |
4046 | setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */ | |
4047 | reg_move(&FPU_loaded_data, pop_ptr); | |
4048 | break; | |
4049 | case 030: /* fstenv m14/28byte */ | |
4050 | fstenv(); | |
4051 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
4052 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
4053 | break; | |
4054 | case 032: /* fsave */ | |
4055 | fsave(); | |
4056 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
4057 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
4058 | break; | |
4059 | case 033: /* fbstp m80dec */ | |
4060 | if (reg_store_bcd()) | |
4061 | pop_0();/* pop only if the number was actually stored | |
4062 | * (see the 80486 manual p16-28) */ | |
4063 | break; | |
4064 | case 034: /* fstcw m16int */ | |
4065 | REENTRANT_CHECK(OFF); | |
4066 | /* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/ | |
4067 | suword( (short *) FPU_data_address,control_word); | |
4068 | REENTRANT_CHECK(ON); | |
4069 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
4070 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
4071 | break; | |
4072 | case 035: /* fstp m80real */ | |
4073 | if (reg_store_extended()) | |
4074 | pop_0();/* pop only if the number was actually stored | |
4075 | * (see the 80486 manual p16-28) */ | |
4076 | break; | |
4077 | case 036: /* fstsw m2byte */ | |
4078 | status_word &= ~SW_Top; | |
4079 | status_word |= (top & 7) << SW_Top_Shift; | |
4080 | REENTRANT_CHECK(OFF); | |
4081 | /* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/ | |
4082 | suword( (short *) FPU_data_address,status_word); | |
4083 | REENTRANT_CHECK(ON); | |
4084 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
4085 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
4086 | break; | |
4087 | case 037: /* fistp m64int */ | |
4088 | if (reg_store_int64()) | |
4089 | pop_0();/* pop only if the number was actually stored | |
4090 | * (see the 80486 manual p16-28) */ | |
4091 | break; | |
4092 | } | |
4093 | } | |
4094 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/math_emu.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 1331 5462505406 12522\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0#ifndef _MATH_EMU_H | |
4095 | #define _MATH_EMU_H | |
4096 | ||
4097 | struct fpu_reg { | |
4098 | char sign; | |
4099 | char tag; | |
4100 | long exp; | |
4101 | u_long sigl; | |
4102 | u_long sigh; | |
4103 | }; | |
4104 | ||
4105 | union i387_union { | |
4106 | struct i387_hard_struct { | |
4107 | long cwd; | |
4108 | long swd; | |
4109 | long twd; | |
4110 | long fip; | |
4111 | long fcs; | |
4112 | long foo; | |
4113 | long fos; | |
4114 | long st_space[20]; /* 8*10 bytes for each FP-reg = 80 | |
4115 | * bytes */ | |
4116 | } hard; | |
4117 | struct i387_soft_struct { | |
4118 | long cwd; | |
4119 | long swd; | |
4120 | long twd; | |
4121 | long fip; | |
4122 | long fcs; | |
4123 | long foo; | |
4124 | long fos; | |
4125 | long top; | |
4126 | struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 | |
4127 | * bytes */ | |
4128 | unsigned char lookahead; | |
4129 | struct trapframe *frame; | |
4130 | unsigned long entry_eip; | |
4131 | int orig_eip; | |
4132 | } soft; | |
4133 | }; | |
4134 | #endif | |
4135 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_2xm1.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 10352 5462473734 12603\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
4136 | * poly_2xm1.c | |
4137 | * | |
4138 | * Function to compute 2^x-1 by a polynomial approximation. | |
4139 | * | |
4140 | * | |
4141 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
4142 | * Vic 3163, Australia. | |
4143 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
4144 | * All rights reserved. | |
4145 | * | |
4146 | * This copyright notice covers the redistribution and use of the | |
4147 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
4148 | * in the 386BSD operating system. Any other use is not permitted | |
4149 | * under this copyright. | |
4150 | * | |
4151 | * Redistribution and use in source and binary forms, with or without | |
4152 | * modification, are permitted provided that the following conditions | |
4153 | * are met: | |
4154 | * 1. Redistributions of source code must retain the above copyright | |
4155 | * notice, this list of conditions and the following disclaimer. | |
4156 | * 2. Redistributions in binary form must include information specifying | |
4157 | * that source code for the emulator is freely available and include | |
4158 | * either: | |
4159 | * a) an offer to provide the source code for a nominal distribution | |
4160 | * fee, or | |
4161 | * b) list at least two alternative methods whereby the source | |
4162 | * can be obtained, e.g. a publically accessible bulletin board | |
4163 | * and an anonymous ftp site from which the software can be | |
4164 | * downloaded. | |
4165 | * 3. All advertising materials specifically mentioning features or use of | |
4166 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
4167 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
4168 | * products derived from this software without specific prior written | |
4169 | * permission. | |
4170 | * | |
4171 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
4172 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
4173 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
4174 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
4175 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
4176 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
4177 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
4178 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
4179 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
4180 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
4181 | * | |
4182 | */ | |
4183 | ||
4184 | #include "exception.h" | |
4185 | #include "reg_constant.h" | |
4186 | #include "fpu_emu.h" | |
4187 | ||
4188 | ||
4189 | ||
4190 | #define HIPOWER 13 | |
4191 | static unsigned short lterms[HIPOWER][4] = | |
4192 | { | |
4193 | {0x79b5, 0xd1cf, 0x17f7, 0xb172}, | |
4194 | {0x1b56, 0x058b, 0x7bff, 0x3d7f}, | |
4195 | {0x8bb0, 0x8250, 0x846b, 0x0e35}, | |
4196 | {0xbc65, 0xf747, 0x556d, 0x0276}, | |
4197 | {0x17cb, 0x9e39, 0x61ff, 0x0057}, | |
4198 | {0xe018, 0x9776, 0x1848, 0x000a}, | |
4199 | {0x66f2, 0xff30, 0xffe5, 0x0000}, | |
4200 | {0x682f, 0xffb6, 0x162b, 0x0000}, | |
4201 | {0xb7ca, 0x2956, 0x01b5, 0x0000}, | |
4202 | {0xcd3e, 0x4817, 0x001e, 0x0000}, | |
4203 | {0xb7e2, 0xecbe, 0x0001, 0x0000}, | |
4204 | {0x0ed5, 0x1a27, 0x0000, 0x0000}, | |
4205 | {0x101d, 0x0222, 0x0000, 0x0000}, | |
4206 | }; | |
4207 | ||
4208 | ||
4209 | /*--- poly_2xm1() -----------------------------------------------------------+ | |
4210 | | | | |
4211 | +---------------------------------------------------------------------------*/ | |
4212 | int | |
4213 | poly_2xm1(FPU_REG * arg, FPU_REG * result) | |
4214 | { | |
4215 | short exponent; | |
4216 | long long Xll; | |
4217 | FPU_REG accum; | |
4218 | ||
4219 | ||
4220 | exponent = arg->exp - EXP_BIAS; | |
4221 | ||
4222 | if (arg->tag == TW_Zero) { | |
4223 | /* Return 0.0 */ | |
4224 | reg_move(&CONST_Z, result); | |
4225 | return 0; | |
4226 | } | |
4227 | if (exponent >= 0) { /* Can't hack a number >= 1.0 */ | |
4228 | arith_invalid(result); /* Number too large */ | |
4229 | return 1; | |
4230 | } | |
4231 | if (arg->sign != SIGN_POS) { /* Can't hack a number < 0.0 */ | |
4232 | arith_invalid(result); /* Number negative */ | |
4233 | return 1; | |
4234 | } | |
4235 | if (exponent < -64) { | |
4236 | reg_move(&CONST_LN2, result); | |
4237 | return 0; | |
4238 | } | |
4239 | *(unsigned *) &Xll = arg->sigl; | |
4240 | *(((unsigned *) &Xll) + 1) = arg->sigh; | |
4241 | if (exponent < -1) { | |
4242 | /* shift the argument right by the required places */ | |
4243 | if (shrx(&Xll, -1 - exponent) >= (unsigned)0x80000000) | |
4244 | Xll++; /* round up */ | |
4245 | } | |
4246 | *(short *) &(accum.sign) = 0; /* will be a valid positive nr with | |
4247 | * expon = 0 */ | |
4248 | accum.exp = 0; | |
4249 | ||
4250 | /* Do the basic fixed point polynomial evaluation */ | |
4251 | polynomial((unsigned *) &accum.sigl, (unsigned *) &Xll, lterms, HIPOWER - 1); | |
4252 | ||
4253 | /* Convert to 64 bit signed-compatible */ | |
4254 | accum.exp += EXP_BIAS - 1; | |
4255 | ||
4256 | reg_move(&accum, result); | |
4257 | ||
4258 | normalize(result); | |
4259 | ||
4260 | return 0; | |
4261 | ||
4262 | } | |
4263 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/Changelog\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 2477 5462534134 12400\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0This file contains the changes made to W. Metzenthem's 387 FPU | |
4264 | emulator to make it work under NetBSD. | |
4265 | ||
4266 | a, Changes to make it compile: | |
4267 | ||
4268 | 1 - Changed the #include's to get the appropriate .h files. | |
4269 | 2 - Renamed .S to .s, to satisfy the kernel Makefile. | |
4270 | 3 - Changed the C++ style // comments to /* */ | |
4271 | 4 - Changed the FPU_ORIG_EIP macro. A letter from bde included | |
4272 | in the package suggested using tf_isp for using instead | |
4273 | of the linux __orig_eip. This later turned out to interfere | |
4274 | with the user stack, so i created a separate variable, stored | |
4275 | in the i387_union. | |
4276 | 5 - Changed the get_fs_.. put_fs_.. fns to fubyte,fuword,subyte, | |
4277 | suword. | |
4278 | 6 - Removed the verify_area fns. I don't really know what they do, | |
4279 | i suppose they verify access to memory. The sufu routines | |
4280 | should do this. | |
4281 | ||
4282 | b, Changes to make it work: | |
4283 | ||
4284 | 1 - Made math_emulate() to return 0 when successful, so trap() won't | |
4285 | try to generate a signal. | |
4286 | 2 - Changed the size of the save87 struct in /sys/arch/i387/include/ | |
4287 | npx.h to accomodate the i387_union. | |
4288 | ||
4289 | d, Other changes: | |
4290 | ||
4291 | 1 - Removed obsolate and/or linux specific stuff. | |
4292 | 2 - Changed the RE_ENTRANT_CHECK_[ON|OFF] macro to | |
4293 | REENTRANT_CHECK([ON|OFF]) so indent can grok it. | |
4294 | 3 - Re-indented to Berkeley style. | |
4295 | 4 - Limited max no of lookaheads. LOOKAHEAD_LIMIT in fpu_entry.c | |
4296 | ||
4297 | ||
4298 | Szabolcs Szigeti (pink@fsz.bme.hu) | |
4299 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_atan.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 16553 5462473734 12750\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
4300 | * p_atan.c | |
4301 | * | |
4302 | * Compute the tan of a FPU_REG, using a polynomial approximation. | |
4303 | * | |
4304 | * | |
4305 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
4306 | * Vic 3163, Australia. | |
4307 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
4308 | * All rights reserved. | |
4309 | * | |
4310 | * This copyright notice covers the redistribution and use of the | |
4311 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
4312 | * in the 386BSD operating system. Any other use is not permitted | |
4313 | * under this copyright. | |
4314 | * | |
4315 | * Redistribution and use in source and binary forms, with or without | |
4316 | * modification, are permitted provided that the following conditions | |
4317 | * are met: | |
4318 | * 1. Redistributions of source code must retain the above copyright | |
4319 | * notice, this list of conditions and the following disclaimer. | |
4320 | * 2. Redistributions in binary form must include information specifying | |
4321 | * that source code for the emulator is freely available and include | |
4322 | * either: | |
4323 | * a) an offer to provide the source code for a nominal distribution | |
4324 | * fee, or | |
4325 | * b) list at least two alternative methods whereby the source | |
4326 | * can be obtained, e.g. a publically accessible bulletin board | |
4327 | * and an anonymous ftp site from which the software can be | |
4328 | * downloaded. | |
4329 | * 3. All advertising materials specifically mentioning features or use of | |
4330 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
4331 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
4332 | * products derived from this software without specific prior written | |
4333 | * permission. | |
4334 | * | |
4335 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
4336 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
4337 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
4338 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
4339 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
4340 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
4341 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
4342 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
4343 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
4344 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
4345 | * | |
4346 | */ | |
4347 | ||
4348 | #include "exception.h" | |
4349 | #include "reg_constant.h" | |
4350 | #include "fpu_emu.h" | |
4351 | #include "control_w.h" | |
4352 | ||
4353 | ||
4354 | #define HIPOWERon 6 /* odd poly, negative terms */ | |
4355 | static unsigned oddnegterms[HIPOWERon][2] = | |
4356 | { | |
4357 | {0x00000000, 0x00000000}, /* for + 1.0 */ | |
4358 | {0x763b6f3d, 0x1adc4428}, | |
4359 | {0x20f0630b, 0x0502909d}, | |
4360 | {0x4e825578, 0x0198ce38}, | |
4361 | {0x22b7cb87, 0x008da6e3}, | |
4362 | {0x9b30ca03, 0x00239c79} | |
4363 | }; | |
4364 | #define HIPOWERop 6 /* odd poly, positive terms */ | |
4365 | static unsigned oddplterms[HIPOWERop][2] = | |
4366 | { | |
4367 | {0xa6f67cb8, 0x94d910bd}, | |
4368 | {0xa02ffab4, 0x0a43cb45}, | |
4369 | {0x04265e6b, 0x02bf5655}, | |
4370 | {0x0a728914, 0x00f280f7}, | |
4371 | {0x6d640e01, 0x004d6556}, | |
4372 | {0xf1dd2dbf, 0x000a530a} | |
4373 | }; | |
4374 | ||
4375 | ||
4376 | static unsigned denomterm[2] = | |
4377 | {0xfc4bd208, 0xea2e6612}; | |
4378 | ||
4379 | ||
4380 | ||
4381 | /*--- poly_atan() -----------------------------------------------------------+ | |
4382 | | | | |
4383 | +---------------------------------------------------------------------------*/ | |
4384 | void | |
4385 | poly_atan(FPU_REG * arg) | |
4386 | { | |
4387 | char recursions = 0; | |
4388 | short exponent; | |
4389 | FPU_REG odd_poly, even_poly, pos_poly, neg_poly; | |
4390 | FPU_REG argSq; | |
4391 | long long arg_signif, argSqSq; | |
4392 | ||
4393 | ||
4394 | #ifdef PARANOID | |
4395 | if (arg->sign != 0) { /* Can't hack a number < 0.0 */ | |
4396 | arith_invalid(arg); | |
4397 | return; | |
4398 | } /* Need a positive number */ | |
4399 | #endif /* PARANOID */ | |
4400 | ||
4401 | exponent = arg->exp - EXP_BIAS; | |
4402 | ||
4403 | if (arg->tag == TW_Zero) { | |
4404 | /* Return 0.0 */ | |
4405 | reg_move(&CONST_Z, arg); | |
4406 | return; | |
4407 | } | |
4408 | if (exponent >= -2) { | |
4409 | /* argument is in the range [0.25 .. 1.0] */ | |
4410 | if (exponent >= 0) { | |
4411 | #ifdef PARANOID | |
4412 | if ((exponent == 0) && | |
4413 | (arg->sigl == 0) && (arg->sigh == 0x80000000)) | |
4414 | #endif /* PARANOID */ | |
4415 | { | |
4416 | reg_move(&CONST_PI4, arg); | |
4417 | return; | |
4418 | } | |
4419 | #ifdef PARANOID | |
4420 | EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic | |
4421 | * error */ | |
4422 | #endif /* PARANOID */ | |
4423 | } | |
4424 | /* If the argument is greater than sqrt(2)-1 (=0.414213562...) */ | |
4425 | /* convert the argument by an identity for atan */ | |
4426 | if ((exponent >= -1) || (arg->sigh > 0xd413ccd0)) { | |
4427 | FPU_REG numerator, denom; | |
4428 | ||
4429 | recursions++; | |
4430 | ||
4431 | arg_signif = *(long long *) &(arg->sigl); | |
4432 | if (exponent < -1) { | |
4433 | if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000) | |
4434 | arg_signif++; /* round up */ | |
4435 | } | |
4436 | *(long long *) &(numerator.sigl) = -arg_signif; | |
4437 | numerator.exp = EXP_BIAS - 1; | |
4438 | normalize(&numerator); /* 1 - arg */ | |
4439 | ||
4440 | arg_signif = *(long long *) &(arg->sigl); | |
4441 | if (shrx(&arg_signif, -exponent) >= (unsigned)0x80000000) | |
4442 | arg_signif++; /* round up */ | |
4443 | *(long long *) &(denom.sigl) = arg_signif; | |
4444 | denom.sigh |= 0x80000000; /* 1 + arg */ | |
4445 | ||
4446 | arg->exp = numerator.exp; | |
4447 | reg_u_div(&numerator, &denom, arg, FULL_PRECISION); | |
4448 | ||
4449 | exponent = arg->exp - EXP_BIAS; | |
4450 | } | |
4451 | } | |
4452 | *(long long *) &arg_signif = *(long long *) &(arg->sigl); | |
4453 | ||
4454 | #ifdef PARANOID | |
4455 | /* This must always be true */ | |
4456 | if (exponent >= -1) { | |
4457 | EXCEPTION(EX_INTERNAL | 0x120); /* There must be a logic error */ | |
4458 | } | |
4459 | #endif /* PARANOID */ | |
4460 | ||
4461 | /* shift the argument right by the required places */ | |
4462 | if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000) | |
4463 | arg_signif++; /* round up */ | |
4464 | ||
4465 | /* Now have arg_signif with binary point at the left .1xxxxxxxx */ | |
4466 | mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl)); | |
4467 | mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq); | |
4468 | ||
4469 | /* will be a valid positive nr with expon = 0 */ | |
4470 | *(short *) &(pos_poly.sign) = 0; | |
4471 | pos_poly.exp = EXP_BIAS; | |
4472 | ||
4473 | /* Do the basic fixed point polynomial evaluation */ | |
4474 | polynomial(&pos_poly.sigl, (unsigned *) &argSqSq, | |
4475 | (unsigned short (*)[4]) oddplterms, HIPOWERop - 1); | |
4476 | mul64((long long *) (&argSq.sigl), (long long *) (&pos_poly.sigl), | |
4477 | (long long *) (&pos_poly.sigl)); | |
4478 | ||
4479 | /* will be a valid positive nr with expon = 0 */ | |
4480 | *(short *) &(neg_poly.sign) = 0; | |
4481 | neg_poly.exp = EXP_BIAS; | |
4482 | ||
4483 | /* Do the basic fixed point polynomial evaluation */ | |
4484 | polynomial(&neg_poly.sigl, (unsigned *) &argSqSq, | |
4485 | (unsigned short (*)[4]) oddnegterms, HIPOWERon - 1); | |
4486 | ||
4487 | /* Subtract the mantissas */ | |
4488 | *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl)); | |
4489 | ||
4490 | reg_move(&pos_poly, &odd_poly); | |
4491 | poly_add_1(&odd_poly); | |
4492 | ||
4493 | /* The complete odd polynomial */ | |
4494 | reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION); | |
4495 | ||
4496 | /* will be a valid positive nr with expon = 0 */ | |
4497 | *(short *) &(even_poly.sign) = 0; | |
4498 | ||
4499 | mul64((long long *) (&argSq.sigl), | |
4500 | (long long *) (&denomterm), (long long *) (&even_poly.sigl)); | |
4501 | ||
4502 | poly_add_1(&even_poly); | |
4503 | ||
4504 | reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION); | |
4505 | ||
4506 | if (recursions) | |
4507 | reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION); | |
4508 | } | |
4509 | ||
4510 | ||
4511 | /* The argument to this function must be polynomial() compatible, | |
4512 | i.e. have an exponent (not checked) of EXP_BIAS-1 but need not | |
4513 | be normalized. | |
4514 | This function adds 1.0 to the (assumed positive) argument. */ | |
4515 | void | |
4516 | poly_add_1(FPU_REG * src) | |
4517 | { | |
4518 | /* Rounding in a consistent direction produces better results | |
4519 | for the use of this function in poly_atan. Simple truncation | |
4520 | is used here instead of round-to-nearest. */ | |
4521 | ||
4522 | #ifdef OBSOLETE | |
4523 | char round = (src->sigl & 3) == 3; | |
4524 | #endif /* OBSOLETE */ | |
4525 | ||
4526 | shrx(&src->sigl, 1); | |
4527 | ||
4528 | #ifdef OBSOLETE | |
4529 | if (round) | |
4530 | (*(long long *) &src->sigl)++; /* Round to even */ | |
4531 | #endif /* OBSOLETE */ | |
4532 | ||
4533 | src->sigh |= 0x80000000; | |
4534 | ||
4535 | src->exp = EXP_BIAS; | |
4536 | ||
4537 | } | |
4538 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_l2.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 21727 5462320163 12351\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
4539 | * poly_l2.c | |
4540 | * | |
4541 | * Compute the base 2 log of a FPU_REG, using a polynomial approximation. | |
4542 | * | |
4543 | * | |
4544 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
4545 | * Vic 3163, Australia. | |
4546 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
4547 | * All rights reserved. | |
4548 | * | |
4549 | * This copyright notice covers the redistribution and use of the | |
4550 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
4551 | * in the 386BSD operating system. Any other use is not permitted | |
4552 | * under this copyright. | |
4553 | * | |
4554 | * Redistribution and use in source and binary forms, with or without | |
4555 | * modification, are permitted provided that the following conditions | |
4556 | * are met: | |
4557 | * 1. Redistributions of source code must retain the above copyright | |
4558 | * notice, this list of conditions and the following disclaimer. | |
4559 | * 2. Redistributions in binary form must include information specifying | |
4560 | * that source code for the emulator is freely available and include | |
4561 | * either: | |
4562 | * a) an offer to provide the source code for a nominal distribution | |
4563 | * fee, or | |
4564 | * b) list at least two alternative methods whereby the source | |
4565 | * can be obtained, e.g. a publically accessible bulletin board | |
4566 | * and an anonymous ftp site from which the software can be | |
4567 | * downloaded. | |
4568 | * 3. All advertising materials specifically mentioning features or use of | |
4569 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
4570 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
4571 | * products derived from this software without specific prior written | |
4572 | * permission. | |
4573 | * | |
4574 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
4575 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
4576 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
4577 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
4578 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
4579 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
4580 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
4581 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
4582 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
4583 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
4584 | * | |
4585 | */ | |
4586 | ||
4587 | ||
4588 | #include "exception.h" | |
4589 | #include "reg_constant.h" | |
4590 | #include "fpu_emu.h" | |
4591 | #include "control_w.h" | |
4592 | ||
4593 | ||
4594 | ||
4595 | #define HIPOWER 9 | |
4596 | static unsigned short lterms[HIPOWER][4] = | |
4597 | { | |
4598 | /* Ideal computation with these coeffs gives about 64.6 bit rel | |
4599 | * accuracy. */ | |
4600 | {0xe177, 0xb82f, 0x7652, 0x7154}, | |
4601 | {0xee0f, 0xe80f, 0x2770, 0x7b1c}, | |
4602 | {0x0fc0, 0xbe87, 0xb143, 0x49dd}, | |
4603 | {0x78b9, 0xdadd, 0xec54, 0x34c2}, | |
4604 | {0x003a, 0x5de9, 0x628b, 0x2909}, | |
4605 | {0x5588, 0xed16, 0x4abf, 0x2193}, | |
4606 | {0xb461, 0x85f7, 0x347a, 0x1c6a}, | |
4607 | {0x0975, 0x87b3, 0xd5bf, 0x1876}, | |
4608 | {0xe85c, 0xcec9, 0x84e7, 0x187d} | |
4609 | }; | |
4610 | ||
4611 | ||
4612 | ||
4613 | ||
4614 | /*--- poly_l2() -------------------------------------------------------------+ | |
4615 | | Base 2 logarithm by a polynomial approximation. | | |
4616 | +---------------------------------------------------------------------------*/ | |
4617 | void | |
4618 | poly_l2(FPU_REG * arg, FPU_REG * result) | |
4619 | { | |
4620 | short exponent; | |
4621 | char zero; /* flag for an Xx == 0 */ | |
4622 | unsigned short bits, shift; | |
4623 | long long Xsq; | |
4624 | FPU_REG accum, denom, num, Xx; | |
4625 | ||
4626 | ||
4627 | exponent = arg->exp - EXP_BIAS; | |
4628 | ||
4629 | accum.tag = TW_Valid; /* set the tags to Valid */ | |
4630 | ||
4631 | if (arg->sigh > (unsigned) 0xb504f334) { | |
4632 | /* This is good enough for the computation of the polynomial | |
4633 | * sum, but actually results in a loss of precision for the | |
4634 | * computation of Xx. This will matter only if exponent | |
4635 | * becomes zero. */ | |
4636 | exponent++; | |
4637 | accum.sign = 1; /* sign to negative */ | |
4638 | num.exp = EXP_BIAS; /* needed to prevent errors in div | |
4639 | * routine */ | |
4640 | reg_u_div(&CONST_1, arg, &num, FULL_PRECISION); | |
4641 | } else { | |
4642 | accum.sign = 0; /* set the sign to positive */ | |
4643 | num.sigl = arg->sigl; /* copy the mantissa */ | |
4644 | num.sigh = arg->sigh; | |
4645 | } | |
4646 | ||
4647 | ||
4648 | /* shift num left, lose the ms bit */ | |
4649 | num.sigh <<= 1; | |
4650 | if (num.sigl & 0x80000000) | |
4651 | num.sigh |= 1; | |
4652 | num.sigl <<= 1; | |
4653 | ||
4654 | denom.sigl = num.sigl; | |
4655 | denom.sigh = num.sigh; | |
4656 | poly_div4((long long *) &(denom.sigl)); | |
4657 | denom.sigh += 0x80000000; /* set the msb */ | |
4658 | Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */ | |
4659 | reg_u_div(&num, &denom, &Xx, FULL_PRECISION); | |
4660 | ||
4661 | zero = !(Xx.sigh | Xx.sigl); | |
4662 | ||
4663 | mul64((long long *) &Xx.sigl, (long long *) &Xx.sigl, &Xsq); | |
4664 | poly_div16(&Xsq); | |
4665 | ||
4666 | accum.exp = -1; /* exponent of accum */ | |
4667 | ||
4668 | /* Do the basic fixed point polynomial evaluation */ | |
4669 | polynomial((unsigned *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1); | |
4670 | ||
4671 | if (!exponent) { | |
4672 | /* If the exponent is zero, then we would lose precision by | |
4673 | * sticking to fixed point computation here */ | |
4674 | /* We need to re-compute Xx because of loss of precision. */ | |
4675 | FPU_REG lXx; | |
4676 | char sign; | |
4677 | ||
4678 | sign = accum.sign; | |
4679 | accum.sign = 0; | |
4680 | ||
4681 | /* make accum compatible and normalize */ | |
4682 | accum.exp = EXP_BIAS + accum.exp; | |
4683 | normalize(&accum); | |
4684 | ||
4685 | if (zero) { | |
4686 | reg_move(&CONST_Z, result); | |
4687 | } else { | |
4688 | /* we need to re-compute lXx to better accuracy */ | |
4689 | num.tag = TW_Valid; /* set the tags to Vaild */ | |
4690 | num.sign = 0; /* set the sign to positive */ | |
4691 | num.exp = EXP_BIAS - 1; | |
4692 | if (sign) { | |
4693 | /* The argument is of the form 1-x */ | |
4694 | /* Use 1-1/(1-x) = x/(1-x) */ | |
4695 | *((long long *) &num.sigl) = -*((long long *) &(arg->sigl)); | |
4696 | normalize(&num); | |
4697 | reg_div(&num, arg, &num, FULL_PRECISION); | |
4698 | } else { | |
4699 | normalize(&num); | |
4700 | } | |
4701 | ||
4702 | denom.tag = TW_Valid; /* set the tags to Valid */ | |
4703 | denom.sign = SIGN_POS; /* set the sign to positive */ | |
4704 | denom.exp = EXP_BIAS; | |
4705 | ||
4706 | reg_div(&num, &denom, &lXx, FULL_PRECISION); | |
4707 | ||
4708 | reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION); | |
4709 | ||
4710 | reg_u_add(&lXx, &accum, result, FULL_PRECISION); | |
4711 | ||
4712 | normalize(result); | |
4713 | } | |
4714 | ||
4715 | result->sign = sign; | |
4716 | return; | |
4717 | } | |
4718 | mul64((long long *) &accum.sigl, | |
4719 | (long long *) &Xx.sigl, (long long *) &accum.sigl); | |
4720 | ||
4721 | *((long long *) (&accum.sigl)) += *((long long *) (&Xx.sigl)); | |
4722 | ||
4723 | if (Xx.sigh > accum.sigh) { | |
4724 | /* There was an overflow */ | |
4725 | ||
4726 | poly_div2((long long *) &accum.sigl); | |
4727 | accum.sigh |= 0x80000000; | |
4728 | accum.exp++; | |
4729 | } | |
4730 | /* When we add the exponent to the accum result later, we will require | |
4731 | * that their signs are the same. Here we ensure that this is so. */ | |
4732 | if (exponent && ((exponent < 0) ^ (accum.sign))) { | |
4733 | /* signs are different */ | |
4734 | ||
4735 | accum.sign = !accum.sign; | |
4736 | ||
4737 | /* An exceptional case is when accum is zero */ | |
4738 | if (accum.sigl | accum.sigh) { | |
4739 | /* find 1-accum */ | |
4740 | /* Shift to get exponent == 0 */ | |
4741 | if (accum.exp < 0) { | |
4742 | poly_div2((long long *) &accum.sigl); | |
4743 | accum.exp++; | |
4744 | } | |
4745 | /* Just negate, but throw away the sign */ | |
4746 | *((long long *) &(accum.sigl)) = -*((long long *) &(accum.sigl)); | |
4747 | if (exponent < 0) | |
4748 | exponent++; | |
4749 | else | |
4750 | exponent--; | |
4751 | } | |
4752 | } | |
4753 | shift = exponent >= 0 ? exponent : -exponent; | |
4754 | bits = 0; | |
4755 | if (shift) { | |
4756 | if (accum.exp) { | |
4757 | accum.exp++; | |
4758 | poly_div2((long long *) &accum.sigl); | |
4759 | } | |
4760 | while (shift) { | |
4761 | poly_div2((long long *) &accum.sigl); | |
4762 | if (shift & 1) | |
4763 | accum.sigh |= 0x80000000; | |
4764 | shift >>= 1; | |
4765 | bits++; | |
4766 | } | |
4767 | } | |
4768 | /* Convert to 64 bit signed-compatible */ | |
4769 | accum.exp += bits + EXP_BIAS - 1; | |
4770 | ||
4771 | reg_move(&accum, result); | |
4772 | normalize(result); | |
4773 | ||
4774 | return; | |
4775 | } | |
4776 | ||
4777 | ||
4778 | /*--- poly_l2p1() -----------------------------------------------------------+ | |
4779 | | Base 2 logarithm by a polynomial approximation. | | |
4780 | | log2(x+1) | | |
4781 | +---------------------------------------------------------------------------*/ | |
4782 | int | |
4783 | poly_l2p1(FPU_REG * arg, FPU_REG * result) | |
4784 | { | |
4785 | char sign = 0; | |
4786 | long long Xsq; | |
4787 | FPU_REG arg_pl1, denom, accum, local_arg, poly_arg; | |
4788 | ||
4789 | ||
4790 | sign = arg->sign; | |
4791 | ||
4792 | reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION); | |
4793 | ||
4794 | if ((arg_pl1.sign) | (arg_pl1.tag)) { /* We need a valid positive | |
4795 | * number! */ | |
4796 | return 1; | |
4797 | } | |
4798 | reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION); | |
4799 | reg_div(arg, &denom, &local_arg, FULL_PRECISION); | |
4800 | local_arg.sign = 0; /* Make the sign positive */ | |
4801 | ||
4802 | /* Now we need to check that |local_arg| is less than 3-2*sqrt(2) = | |
4803 | * 0.17157.. = .0xafb0ccc0 * 2^-2 */ | |
4804 | ||
4805 | if (local_arg.exp >= EXP_BIAS - 3) { | |
4806 | if ((local_arg.exp > EXP_BIAS - 3) || | |
4807 | (local_arg.sigh > (unsigned) 0xafb0ccc0)) { | |
4808 | /* The argument is large */ | |
4809 | poly_l2(&arg_pl1, result); | |
4810 | return 0; | |
4811 | } | |
4812 | } | |
4813 | /* Make a copy of local_arg */ | |
4814 | reg_move(&local_arg, &poly_arg); | |
4815 | ||
4816 | /* Get poly_arg bits aligned as required */ | |
4817 | shrx((unsigned *) &(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3)); | |
4818 | ||
4819 | mul64((long long *) &(poly_arg.sigl), (long long *) &(poly_arg.sigl), &Xsq); | |
4820 | poly_div16(&Xsq); | |
4821 | ||
4822 | /* Do the basic fixed point polynomial evaluation */ | |
4823 | polynomial(&(accum.sigl), (unsigned *) &Xsq, lterms, HIPOWER - 1); | |
4824 | ||
4825 | accum.tag = TW_Valid; /* set the tags to Valid */ | |
4826 | accum.sign = SIGN_POS; /* and make accum positive */ | |
4827 | ||
4828 | /* make accum compatible and normalize */ | |
4829 | accum.exp = EXP_BIAS - 1; | |
4830 | normalize(&accum); | |
4831 | ||
4832 | reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION); | |
4833 | ||
4834 | reg_u_add(&local_arg, &accum, result, FULL_PRECISION); | |
4835 | ||
4836 | /* Multiply the result by 2 */ | |
4837 | result->exp++; | |
4838 | ||
4839 | result->sign = sign; | |
4840 | ||
4841 | return 0; | |
4842 | } | |
4843 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_sin.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 13632 5462473735 12612\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
4844 | * poly_sin.c | |
4845 | * | |
4846 | * Computation of an approximation of the sin function by a polynomial | |
4847 | * | |
4848 | * | |
4849 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
4850 | * Vic 3163, Australia. | |
4851 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
4852 | * All rights reserved. | |
4853 | * | |
4854 | * This copyright notice covers the redistribution and use of the | |
4855 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
4856 | * in the 386BSD operating system. Any other use is not permitted | |
4857 | * under this copyright. | |
4858 | * | |
4859 | * Redistribution and use in source and binary forms, with or without | |
4860 | * modification, are permitted provided that the following conditions | |
4861 | * are met: | |
4862 | * 1. Redistributions of source code must retain the above copyright | |
4863 | * notice, this list of conditions and the following disclaimer. | |
4864 | * 2. Redistributions in binary form must include information specifying | |
4865 | * that source code for the emulator is freely available and include | |
4866 | * either: | |
4867 | * a) an offer to provide the source code for a nominal distribution | |
4868 | * fee, or | |
4869 | * b) list at least two alternative methods whereby the source | |
4870 | * can be obtained, e.g. a publically accessible bulletin board | |
4871 | * and an anonymous ftp site from which the software can be | |
4872 | * downloaded. | |
4873 | * 3. All advertising materials specifically mentioning features or use of | |
4874 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
4875 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
4876 | * products derived from this software without specific prior written | |
4877 | * permission. | |
4878 | * | |
4879 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
4880 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
4881 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
4882 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
4883 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
4884 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
4885 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
4886 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
4887 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
4888 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
4889 | * | |
4890 | */ | |
4891 | ||
4892 | ||
4893 | #include "exception.h" | |
4894 | #include "reg_constant.h" | |
4895 | #include "fpu_emu.h" | |
4896 | #include "control_w.h" | |
4897 | ||
4898 | ||
4899 | #define HIPOWER 5 | |
4900 | static unsigned short lterms[HIPOWER][4] = | |
4901 | { | |
4902 | {0x846a, 0x42d1, 0xb544, 0x921f}, | |
4903 | {0xe110, 0x75aa, 0xbc67, 0x1466}, | |
4904 | {0x503d, 0xa43f, 0x83c1, 0x000a}, | |
4905 | {0x8f9d, 0x7a19, 0x00f4, 0x0000}, | |
4906 | {0xda03, 0x06aa, 0x0000, 0x0000}, | |
4907 | }; | |
4908 | ||
4909 | static unsigned short negterms[HIPOWER][4] = | |
4910 | { | |
4911 | {0x95ed, 0x2df2, 0xe731, 0xa55d}, | |
4912 | {0xd159, 0xe62b, 0xd2cc, 0x0132}, | |
4913 | {0x6342, 0xe9fb, 0x3c60, 0x0000}, | |
4914 | {0x6256, 0xdf5a, 0x0002, 0x0000}, | |
4915 | {0xf279, 0x000b, 0x0000, 0x0000}, | |
4916 | }; | |
4917 | ||
4918 | ||
4919 | /*--- poly_sine() -----------------------------------------------------------+ | |
4920 | | | | |
4921 | +---------------------------------------------------------------------------*/ | |
4922 | void | |
4923 | poly_sine(FPU_REG * arg, FPU_REG * result) | |
4924 | { | |
4925 | short exponent; | |
4926 | FPU_REG Xx, Xx2, Xx4, accum, negaccum; | |
4927 | ||
4928 | ||
4929 | exponent = arg->exp - EXP_BIAS; | |
4930 | ||
4931 | if (arg->tag == TW_Zero) { | |
4932 | /* Return 0.0 */ | |
4933 | reg_move(&CONST_Z, result); | |
4934 | return; | |
4935 | } | |
4936 | #ifdef PARANOID | |
4937 | if (arg->sign != 0) { /* Can't hack a number < 0.0 */ | |
4938 | EXCEPTION(EX_Invalid); | |
4939 | reg_move(&CONST_QNaN, result); | |
4940 | return; | |
4941 | } | |
4942 | if (exponent >= 0) { /* Can't hack a number > 1.0 */ | |
4943 | if ((exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000)) { | |
4944 | reg_move(&CONST_1, result); | |
4945 | return; | |
4946 | } | |
4947 | EXCEPTION(EX_Invalid); | |
4948 | reg_move(&CONST_QNaN, result); | |
4949 | return; | |
4950 | } | |
4951 | #endif /* PARANOID */ | |
4952 | ||
4953 | Xx.sigl = arg->sigl; | |
4954 | Xx.sigh = arg->sigh; | |
4955 | if (exponent < -1) { | |
4956 | /* shift the argument right by the required places */ | |
4957 | if (shrx(&(Xx.sigl), -1 - exponent) >= (unsigned)0x80000000) | |
4958 | (*((long long *) (&(Xx.sigl))))++; /* round up */ | |
4959 | } | |
4960 | mul64((long long *) &(Xx.sigl), (long long *) &(Xx.sigl), | |
4961 | (long long *) &(Xx2.sigl)); | |
4962 | mul64((long long *) &(Xx2.sigl), (long long *) &(Xx2.sigl), | |
4963 | (long long *) &(Xx4.sigl)); | |
4964 | ||
4965 | /* will be a valid positive nr with expon = 0 */ | |
4966 | *(short *) &(accum.sign) = 0; | |
4967 | accum.exp = 0; | |
4968 | ||
4969 | /* Do the basic fixed point polynomial evaluation */ | |
4970 | polynomial(&(accum.sigl), &(Xx4.sigl), lterms, HIPOWER - 1); | |
4971 | ||
4972 | /* will be a valid positive nr with expon = 0 */ | |
4973 | *(short *) &(negaccum.sign) = 0; | |
4974 | negaccum.exp = 0; | |
4975 | ||
4976 | /* Do the basic fixed point polynomial evaluation */ | |
4977 | polynomial(&(negaccum.sigl), &(Xx4.sigl), negterms, HIPOWER - 1); | |
4978 | mul64((long long *) &(Xx2.sigl), (long long *) &(negaccum.sigl), | |
4979 | (long long *) &(negaccum.sigl)); | |
4980 | ||
4981 | /* Subtract the mantissas */ | |
4982 | *((long long *) (&(accum.sigl))) -= *((long long *) (&(negaccum.sigl))); | |
4983 | ||
4984 | /* Convert to 64 bit signed-compatible */ | |
4985 | accum.exp = EXP_BIAS - 1 + accum.exp; | |
4986 | ||
4987 | *(short *) &(result->sign) = *(short *) &(accum.sign); | |
4988 | result->exp = accum.exp; | |
4989 | result->sigl = accum.sigl; | |
4990 | result->sigh = accum.sigh; | |
4991 | ||
4992 | normalize(result); | |
4993 | ||
4994 | reg_mul(result, arg, result, FULL_PRECISION); | |
4995 | reg_u_add(result, arg, result, FULL_PRECISION); | |
4996 | ||
4997 | /* A small overflow may be possible... but an illegal result. */ | |
4998 | if (result->exp >= EXP_BIAS) { | |
4999 | if ((result->exp > EXP_BIAS) /* Larger or equal 2.0 */ | |
5000 | ||(result->sigl > 1) /* Larger than 1.0+msb */ | |
5001 | ||(result->sigh != 0x80000000) /* Much > 1.0 */ | |
5002 | ) { | |
5003 | #ifdef DEBUGGING | |
5004 | RE_ENTRANT_CHECK_OFF | |
5005 | printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp, | |
5006 | result->sigh, result->sigl); | |
5007 | RE_ENTRANT_CHECK_ON | |
5008 | #endif /* DEBUGGING */ | |
5009 | EXCEPTION(EX_INTERNAL | 0x103); | |
5010 | } | |
5011 | #ifdef DEBUGGING | |
5012 | RE_ENTRANT_CHECK_OFF | |
5013 | printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n"); | |
5014 | printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp, | |
5015 | result->sigh, result->sigl); | |
5016 | RE_ENTRANT_CHECK_ON | |
5017 | #endif /* DEBUGGING */ | |
5018 | ||
5019 | result->sigl = 0; /* Truncate the result to 1.00 */ | |
5020 | } | |
5021 | } | |
5022 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_tan.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 16221 5462473735 12600\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
5023 | * poly_tan.c | |
5024 | * | |
5025 | * Compute the tan of a FPU_REG, using a polynomial approximation. | |
5026 | * | |
5027 | * | |
5028 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
5029 | * Vic 3163, Australia. | |
5030 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
5031 | * All rights reserved. | |
5032 | * | |
5033 | * This copyright notice covers the redistribution and use of the | |
5034 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
5035 | * in the 386BSD operating system. Any other use is not permitted | |
5036 | * under this copyright. | |
5037 | * | |
5038 | * Redistribution and use in source and binary forms, with or without | |
5039 | * modification, are permitted provided that the following conditions | |
5040 | * are met: | |
5041 | * 1. Redistributions of source code must retain the above copyright | |
5042 | * notice, this list of conditions and the following disclaimer. | |
5043 | * 2. Redistributions in binary form must include information specifying | |
5044 | * that source code for the emulator is freely available and include | |
5045 | * either: | |
5046 | * a) an offer to provide the source code for a nominal distribution | |
5047 | * fee, or | |
5048 | * b) list at least two alternative methods whereby the source | |
5049 | * can be obtained, e.g. a publically accessible bulletin board | |
5050 | * and an anonymous ftp site from which the software can be | |
5051 | * downloaded. | |
5052 | * 3. All advertising materials specifically mentioning features or use of | |
5053 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
5054 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
5055 | * products derived from this software without specific prior written | |
5056 | * permission. | |
5057 | * | |
5058 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
5059 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
5060 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
5061 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
5062 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
5063 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
5064 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
5065 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
5066 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
5067 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
5068 | * | |
5069 | */ | |
5070 | ||
5071 | #include "exception.h" | |
5072 | #include "reg_constant.h" | |
5073 | #include "fpu_emu.h" | |
5074 | #include "control_w.h" | |
5075 | ||
5076 | ||
5077 | #define HIPOWERop 3 /* odd poly, positive terms */ | |
5078 | static unsigned short oddplterms[HIPOWERop][4] = | |
5079 | { | |
5080 | {0x846a, 0x42d1, 0xb544, 0x921f}, | |
5081 | {0x6fb2, 0x0215, 0x95c0, 0x099c}, | |
5082 | {0xfce6, 0x0cc8, 0x1c9a, 0x0000} | |
5083 | }; | |
5084 | #define HIPOWERon 2 /* odd poly, negative terms */ | |
5085 | static unsigned short oddnegterms[HIPOWERon][4] = | |
5086 | { | |
5087 | {0x6906, 0xe205, 0x25c8, 0x8838}, | |
5088 | {0x1dd7, 0x3fe3, 0x944e, 0x002c} | |
5089 | }; | |
5090 | #define HIPOWERep 2 /* even poly, positive terms */ | |
5091 | static unsigned short evenplterms[HIPOWERep][4] = | |
5092 | { | |
5093 | {0xdb8f, 0x3761, 0x1432, 0x2acf}, | |
5094 | {0x16eb, 0x13c1, 0x3099, 0x0003} | |
5095 | }; | |
5096 | #define HIPOWERen 2 /* even poly, negative terms */ | |
5097 | static unsigned short evennegterms[HIPOWERen][4] = | |
5098 | { | |
5099 | {0x3a7c, 0xe4c5, 0x7f87, 0x2945}, | |
5100 | {0x572b, 0x664c, 0xc543, 0x018c} | |
5101 | }; | |
5102 | ||
5103 | ||
5104 | /*--- poly_tan() ------------------------------------------------------------+ | |
5105 | | | | |
5106 | +---------------------------------------------------------------------------*/ | |
5107 | void | |
5108 | poly_tan(FPU_REG * arg, FPU_REG * y_reg) | |
5109 | { | |
5110 | char invert = 0; | |
5111 | short exponent; | |
5112 | FPU_REG odd_poly, even_poly, pos_poly, neg_poly; | |
5113 | FPU_REG argSq; | |
5114 | long long arg_signif, argSqSq; | |
5115 | ||
5116 | ||
5117 | exponent = arg->exp - EXP_BIAS; | |
5118 | ||
5119 | if (arg->tag == TW_Zero) { | |
5120 | /* Return 0.0 */ | |
5121 | reg_move(&CONST_Z, y_reg); | |
5122 | return; | |
5123 | } | |
5124 | if (exponent >= -1) { | |
5125 | /* argument is in the range [0.5 .. 1.0] */ | |
5126 | if (exponent >= 0) { | |
5127 | #ifdef PARANOID | |
5128 | if ((exponent == 0) && | |
5129 | (arg->sigl == 0) && (arg->sigh == 0x80000000)) | |
5130 | #endif /* PARANOID */ | |
5131 | { | |
5132 | arith_overflow(y_reg); | |
5133 | return; | |
5134 | } | |
5135 | #ifdef PARANOID | |
5136 | EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic | |
5137 | * error */ | |
5138 | return; | |
5139 | #endif /* PARANOID */ | |
5140 | } | |
5141 | /* The argument is in the range [0.5 .. 1.0) */ | |
5142 | /* Convert the argument to a number in the range (0.0 .. 0.5] */ | |
5143 | *((long long *) (&arg->sigl)) = -*((long long *) (&arg->sigl)); | |
5144 | normalize(arg); /* Needed later */ | |
5145 | exponent = arg->exp - EXP_BIAS; | |
5146 | invert = 1; | |
5147 | } | |
5148 | #ifdef PARANOID | |
5149 | if (arg->sign != 0) { /* Can't hack a number < 0.0 */ | |
5150 | arith_invalid(y_reg); | |
5151 | return; | |
5152 | } /* Need a positive number */ | |
5153 | #endif /* PARANOID */ | |
5154 | ||
5155 | *(long long *) &arg_signif = *(long long *) &(arg->sigl); | |
5156 | if (exponent < -1) { | |
5157 | /* shift the argument right by the required places */ | |
5158 | if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000) | |
5159 | arg_signif++; /* round up */ | |
5160 | } | |
5161 | mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl)); | |
5162 | mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq); | |
5163 | ||
5164 | /* will be a valid positive nr with expon = 0 */ | |
5165 | *(short *) &(pos_poly.sign) = 0; | |
5166 | pos_poly.exp = EXP_BIAS; | |
5167 | ||
5168 | /* Do the basic fixed point polynomial evaluation */ | |
5169 | polynomial(&pos_poly.sigl, (unsigned *) &argSqSq, oddplterms, HIPOWERop - 1); | |
5170 | ||
5171 | /* will be a valid positive nr with expon = 0 */ | |
5172 | *(short *) &(neg_poly.sign) = 0; | |
5173 | neg_poly.exp = EXP_BIAS; | |
5174 | ||
5175 | /* Do the basic fixed point polynomial evaluation */ | |
5176 | polynomial(&neg_poly.sigl, (unsigned *) &argSqSq, oddnegterms, HIPOWERon - 1); | |
5177 | mul64((long long *) (&argSq.sigl), (long long *) (&neg_poly.sigl), | |
5178 | (long long *) (&neg_poly.sigl)); | |
5179 | ||
5180 | /* Subtract the mantissas */ | |
5181 | *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl)); | |
5182 | ||
5183 | /* Convert to 64 bit signed-compatible */ | |
5184 | pos_poly.exp -= 1; | |
5185 | ||
5186 | reg_move(&pos_poly, &odd_poly); | |
5187 | normalize(&odd_poly); | |
5188 | ||
5189 | reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION); | |
5190 | reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION); /* This is just the odd | |
5191 | * polynomial */ | |
5192 | ||
5193 | ||
5194 | /* will be a valid positive nr with expon = 0 */ | |
5195 | *(short *) &(pos_poly.sign) = 0; | |
5196 | pos_poly.exp = EXP_BIAS; | |
5197 | ||
5198 | /* Do the basic fixed point polynomial evaluation */ | |
5199 | polynomial(&pos_poly.sigl, (unsigned *) &argSqSq, evenplterms, HIPOWERep - 1); | |
5200 | mul64((long long *) (&argSq.sigl), | |
5201 | (long long *) (&pos_poly.sigl), (long long *) (&pos_poly.sigl)); | |
5202 | ||
5203 | /* will be a valid positive nr with expon = 0 */ | |
5204 | *(short *) &(neg_poly.sign) = 0; | |
5205 | neg_poly.exp = EXP_BIAS; | |
5206 | ||
5207 | /* Do the basic fixed point polynomial evaluation */ | |
5208 | polynomial(&neg_poly.sigl, (unsigned *) &argSqSq, evennegterms, HIPOWERen - 1); | |
5209 | ||
5210 | /* Subtract the mantissas */ | |
5211 | *((long long *) (&neg_poly.sigl)) -= *((long long *) (&pos_poly.sigl)); | |
5212 | /* and multiply by argSq */ | |
5213 | ||
5214 | /* Convert argSq to a valid reg number */ | |
5215 | *(short *) &(argSq.sign) = 0; | |
5216 | argSq.exp = EXP_BIAS - 1; | |
5217 | normalize(&argSq); | |
5218 | ||
5219 | /* Convert to 64 bit signed-compatible */ | |
5220 | neg_poly.exp -= 1; | |
5221 | ||
5222 | reg_move(&neg_poly, &even_poly); | |
5223 | normalize(&even_poly); | |
5224 | ||
5225 | reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION); | |
5226 | reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION); | |
5227 | reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION); /* This is just the even | |
5228 | * polynomial */ | |
5229 | ||
5230 | /* Now ready to copy the results */ | |
5231 | if (invert) { | |
5232 | reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION); | |
5233 | } else { | |
5234 | reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION); | |
5235 | } | |
5236 | ||
5237 | } | |
5238 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_emu.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 13703 5462320156 12406\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
5239 | * fpu_emu.h | |
5240 | * | |
5241 | * | |
5242 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
5243 | * Vic 3163, Australia. | |
5244 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
5245 | * All rights reserved. | |
5246 | * | |
5247 | * This copyright notice covers the redistribution and use of the | |
5248 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
5249 | * in the 386BSD operating system. Any other use is not permitted | |
5250 | * under this copyright. | |
5251 | * | |
5252 | * Redistribution and use in source and binary forms, with or without | |
5253 | * modification, are permitted provided that the following conditions | |
5254 | * are met: | |
5255 | * 1. Redistributions of source code must retain the above copyright | |
5256 | * notice, this list of conditions and the following disclaimer. | |
5257 | * 2. Redistributions in binary form must include information specifying | |
5258 | * that source code for the emulator is freely available and include | |
5259 | * either: | |
5260 | * a) an offer to provide the source code for a nominal distribution | |
5261 | * fee, or | |
5262 | * b) list at least two alternative methods whereby the source | |
5263 | * can be obtained, e.g. a publically accessible bulletin board | |
5264 | * and an anonymous ftp site from which the software can be | |
5265 | * downloaded. | |
5266 | * 3. All advertising materials specifically mentioning features or use of | |
5267 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
5268 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
5269 | * products derived from this software without specific prior written | |
5270 | * permission. | |
5271 | * | |
5272 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
5273 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
5274 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
5275 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
5276 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
5277 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
5278 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
5279 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
5280 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
5281 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
5282 | * | |
5283 | */ | |
5284 | ||
5285 | ||
5286 | #ifndef _FPU_EMU_H_ | |
5287 | #define _FPU_EMU_H_ | |
5288 | ||
5289 | /* | |
5290 | * Define DENORM_OPERAND to make the emulator detect denormals | |
5291 | * and use the denormal flag of the status word. Note: this only | |
5292 | * affects the flag and corresponding interrupt, the emulator | |
5293 | * will always generate denormals and operate upon them as required. | |
5294 | */ | |
5295 | #define DENORM_OPERAND | |
5296 | ||
5297 | /* | |
5298 | * Define PECULIAR_486 to get a closer approximation to 80486 behaviour, | |
5299 | * rather than behaviour which appears to be cleaner. | |
5300 | * This is a matter of opinion: for all I know, the 80486 may simply | |
5301 | * be complying with the IEEE spec. Maybe one day I'll get to see the | |
5302 | * spec... | |
5303 | */ | |
5304 | #define PECULIAR_486 | |
5305 | ||
5306 | #ifdef LOCORE | |
5307 | #include "fpu_asm.h" | |
5308 | #define Const(x) $/**/x | |
5309 | #else | |
5310 | #define Const(x) x | |
5311 | #endif | |
5312 | ||
5313 | #define EXP_BIAS Const(0) | |
5314 | #define EXP_OVER Const(0x4000) /* smallest invalid large exponent */ | |
5315 | #define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */ | |
5316 | ||
5317 | #define SIGN_POS Const(0) | |
5318 | #define SIGN_NEG Const(1) | |
5319 | ||
5320 | /* Keep the order TW_Valid, TW_Zero, TW_Denormal */ | |
5321 | #define TW_Valid Const(0)/* valid */ | |
5322 | #define TW_Zero Const(1)/* zero */ | |
5323 | /* The following fold to 2 (Special) in the Tag Word */ | |
5324 | #define TW_Denormal Const(4)/* De-normal */ | |
5325 | #define TW_Infinity Const(5)/* + or - infinity */ | |
5326 | #define TW_NaN Const(6)/* Not a Number */ | |
5327 | ||
5328 | #define TW_Empty Const(7)/* empty */ | |
5329 | ||
5330 | /* #define TW_FPU_Interrupt Const(0x80) *//* Signals an interrupt */ | |
5331 | ||
5332 | ||
5333 | #ifndef LOCORE | |
5334 | ||
5335 | #include "types.h" | |
5336 | #include "math_emu.h" | |
5337 | ||
5338 | #ifdef PARANOID | |
5339 | extern char emulating; | |
5340 | #define REENTRANT_CHECK(state) emulating = (state) | |
5341 | #define ON 1 | |
5342 | #define OFF 0 | |
5343 | #else | |
5344 | #define REENTRANT_CHECK(state) | |
5345 | #endif /* PARANOID */ | |
5346 | ||
5347 | typedef void (*FUNC) (void); | |
5348 | typedef struct fpu_reg FPU_REG; | |
5349 | ||
5350 | #define st(x) ( regs[((top+x) &7 )] ) | |
5351 | ||
5352 | #define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty) | |
5353 | #define NOT_EMPTY(i) (st(i).tag != TW_Empty) | |
5354 | #define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty) | |
5355 | ||
5356 | extern unsigned char FPU_rm; | |
5357 | ||
5358 | extern char FPU_st0_tag; | |
5359 | extern FPU_REG *FPU_st0_ptr; | |
5360 | ||
5361 | extern void *FPU_data_address; | |
5362 | ||
5363 | extern FPU_REG FPU_loaded_data; | |
5364 | ||
5365 | #define pop() { FPU_st0_ptr->tag = TW_Empty; top++; } | |
5366 | ||
5367 | /* push() does not affect the tags */ | |
5368 | #define push() { top--; FPU_st0_ptr = st_new_ptr; } | |
5369 | ||
5370 | ||
5371 | #define reg_move(x, y) { \ | |
5372 | *(short *)&((y)->sign) = *(short *)&((x)->sign); \ | |
5373 | *(long *)&((y)->exp) = *(long *)&((x)->exp); \ | |
5374 | *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); } | |
5375 | ||
5376 | ||
5377 | /*----- Prototypes for functions written in assembler -----*/ | |
5378 | /* extern void reg_move(FPU_REG *a, FPU_REG *b); */ | |
5379 | ||
5380 | extern void mul64(long long *a, long long *b, long long *result); | |
5381 | extern void poly_div2(long long *x); | |
5382 | extern void poly_div4(long long *x); | |
5383 | extern void poly_div16(long long *x); | |
5384 | extern void | |
5385 | polynomial(unsigned accum[], unsigned x[], | |
5386 | unsigned short terms[][4], int n); | |
5387 | extern void normalize(FPU_REG * x); | |
5388 | extern void normalize_nuo(FPU_REG * x); | |
5389 | extern void reg_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ, | |
5390 | unsigned int control_w); | |
5391 | extern void reg_u_sub(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ, | |
5392 | unsigned int control_w); | |
5393 | extern void reg_u_mul(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ, | |
5394 | unsigned int control_w); | |
5395 | extern void reg_u_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ, | |
5396 | unsigned int control_w); | |
5397 | extern void reg_u_add(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ, | |
5398 | unsigned int control_w); | |
5399 | extern void wm_sqrt(FPU_REG * n, unsigned int control_w); | |
5400 | extern unsigned shrx(void *l, unsigned x); | |
5401 | extern unsigned shrxs(void *v, unsigned x); | |
5402 | extern unsigned long div_small(unsigned long long *x, unsigned long y); | |
5403 | extern void round_reg(FPU_REG * arg, unsigned int extent, | |
5404 | unsigned int control_w); | |
5405 | ||
5406 | #ifndef MAKING_PROTO | |
5407 | #include "fpu_proto.h" | |
5408 | #endif | |
5409 | ||
5410 | #endif /* LOCORE */ | |
5411 | ||
5412 | #endif /* _FPU_EMU_H_ */ | |
5413 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_compare.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 21642 5462320164 13224\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
5414 | * reg_compare.c | |
5415 | * | |
5416 | * Compare two floating point registers | |
5417 | * | |
5418 | * | |
5419 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
5420 | * Vic 3163, Australia. | |
5421 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
5422 | * All rights reserved. | |
5423 | * | |
5424 | * This copyright notice covers the redistribution and use of the | |
5425 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
5426 | * in the 386BSD operating system. Any other use is not permitted | |
5427 | * under this copyright. | |
5428 | * | |
5429 | * Redistribution and use in source and binary forms, with or without | |
5430 | * modification, are permitted provided that the following conditions | |
5431 | * are met: | |
5432 | * 1. Redistributions of source code must retain the above copyright | |
5433 | * notice, this list of conditions and the following disclaimer. | |
5434 | * 2. Redistributions in binary form must include information specifying | |
5435 | * that source code for the emulator is freely available and include | |
5436 | * either: | |
5437 | * a) an offer to provide the source code for a nominal distribution | |
5438 | * fee, or | |
5439 | * b) list at least two alternative methods whereby the source | |
5440 | * can be obtained, e.g. a publically accessible bulletin board | |
5441 | * and an anonymous ftp site from which the software can be | |
5442 | * downloaded. | |
5443 | * 3. All advertising materials specifically mentioning features or use of | |
5444 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
5445 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
5446 | * products derived from this software without specific prior written | |
5447 | * permission. | |
5448 | * | |
5449 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
5450 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
5451 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
5452 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
5453 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
5454 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
5455 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
5456 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
5457 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
5458 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
5459 | * | |
5460 | */ | |
5461 | ||
5462 | /*---------------------------------------------------------------------------+ | |
5463 | | compare() is the core FPU_REG comparison function | | |
5464 | +---------------------------------------------------------------------------*/ | |
5465 | #include "param.h" | |
5466 | #include "proc.h" | |
5467 | #include "systm.h" | |
5468 | #include "machine/cpu.h" | |
5469 | #include "machine/pcb.h" | |
5470 | ||
5471 | #include "fpu_emu.h" | |
5472 | #include "fpu_system.h" | |
5473 | #include "exception.h" | |
5474 | #include "control_w.h" | |
5475 | #include "status_w.h" | |
5476 | ||
5477 | ||
5478 | int | |
5479 | compare(FPU_REG * b) | |
5480 | { | |
5481 | int diff; | |
5482 | ||
5483 | if (FPU_st0_ptr->tag | b->tag) { | |
5484 | if (FPU_st0_ptr->tag == TW_Zero) { | |
5485 | if (b->tag == TW_Zero) | |
5486 | return COMP_A_eq_B; | |
5487 | if (b->tag == TW_Valid) { | |
5488 | #ifdef DENORM_OPERAND | |
5489 | if ((b->exp <= EXP_UNDER) && (denormal_operand())) | |
5490 | return COMP_Denormal; | |
5491 | #endif /* DENORM_OPERAND */ | |
5492 | return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B; | |
5493 | } | |
5494 | } else | |
5495 | if (b->tag == TW_Zero) { | |
5496 | if (FPU_st0_ptr->tag == TW_Valid) { | |
5497 | #ifdef DENORM_OPERAND | |
5498 | if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand())) | |
5499 | return COMP_Denormal; | |
5500 | #endif /* DENORM_OPERAND */ | |
5501 | return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B; | |
5502 | } | |
5503 | } | |
5504 | if (FPU_st0_ptr->tag == TW_Infinity) { | |
5505 | if ((b->tag == TW_Valid) || (b->tag == TW_Zero)) { | |
5506 | #ifdef DENORM_OPERAND | |
5507 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) | |
5508 | && (denormal_operand())) | |
5509 | return COMP_Denormal; | |
5510 | #endif /* DENORM_OPERAND */ | |
5511 | return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B; | |
5512 | } else | |
5513 | if (b->tag == TW_Infinity) { | |
5514 | /* The 80486 book says that infinities | |
5515 | * can be equal! */ | |
5516 | return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B : | |
5517 | ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); | |
5518 | } | |
5519 | /* Fall through to the NaN code */ | |
5520 | } else | |
5521 | if (b->tag == TW_Infinity) { | |
5522 | if ((FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero)) { | |
5523 | #ifdef DENORM_OPERAND | |
5524 | if ((FPU_st0_ptr->tag == TW_Valid) | |
5525 | && (FPU_st0_ptr->exp <= EXP_UNDER) | |
5526 | && (denormal_operand())) | |
5527 | return COMP_Denormal; | |
5528 | #endif /* DENORM_OPERAND */ | |
5529 | return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B; | |
5530 | } | |
5531 | /* Fall through to the NaN code */ | |
5532 | } | |
5533 | /* The only possibility now should be that one of the | |
5534 | * arguments is a NaN */ | |
5535 | if ((FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN)) { | |
5536 | if (((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000)) | |
5537 | || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000))) | |
5538 | /* At least one arg is a signaling NaN */ | |
5539 | return COMP_No_Comp | COMP_SNaN | COMP_NaN; | |
5540 | else | |
5541 | /* Neither is a signaling NaN */ | |
5542 | return COMP_No_Comp | COMP_NaN; | |
5543 | } | |
5544 | EXCEPTION(EX_Invalid); | |
5545 | } | |
5546 | #ifdef PARANOID | |
5547 | if (!(FPU_st0_ptr->sigh & 0x80000000)) | |
5548 | EXCEPTION(EX_Invalid); | |
5549 | if (!(b->sigh & 0x80000000)) | |
5550 | EXCEPTION(EX_Invalid); | |
5551 | #endif /* PARANOID */ | |
5552 | ||
5553 | #ifdef DENORM_OPERAND | |
5554 | if (((FPU_st0_ptr->exp <= EXP_UNDER) || | |
5555 | (b->exp <= EXP_UNDER)) && (denormal_operand())) | |
5556 | return COMP_Denormal; | |
5557 | #endif /* DENORM_OPERAND */ | |
5558 | ||
5559 | if (FPU_st0_ptr->sign != b->sign) | |
5560 | return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B; | |
5561 | ||
5562 | diff = FPU_st0_ptr->exp - b->exp; | |
5563 | if (diff == 0) { | |
5564 | diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits | |
5565 | * are identical */ | |
5566 | if (diff == 0) { | |
5567 | diff = FPU_st0_ptr->sigl > b->sigl; | |
5568 | if (diff == 0) | |
5569 | diff = -(FPU_st0_ptr->sigl < b->sigl); | |
5570 | } | |
5571 | } | |
5572 | if (diff > 0) | |
5573 | return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B; | |
5574 | if (diff < 0) | |
5575 | return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B; | |
5576 | return COMP_A_eq_B; | |
5577 | ||
5578 | } | |
5579 | ||
5580 | ||
5581 | /* This function requires that st(0) is not empty */ | |
5582 | int | |
5583 | compare_st_data(void) | |
5584 | { | |
5585 | int f, c; | |
5586 | ||
5587 | c = compare(&FPU_loaded_data); | |
5588 | ||
5589 | if (c & (COMP_NaN | COMP_Denormal)) { | |
5590 | if (c & COMP_NaN) { | |
5591 | EXCEPTION(EX_Invalid); | |
5592 | f = SW_C3 | SW_C2 | SW_C0; | |
5593 | } else { | |
5594 | /* One of the operands is a de-normal */ | |
5595 | return 0; | |
5596 | } | |
5597 | } else | |
5598 | switch (c) { | |
5599 | case COMP_A_lt_B: | |
5600 | f = SW_C0; | |
5601 | break; | |
5602 | case COMP_A_eq_B: | |
5603 | f = SW_C3; | |
5604 | break; | |
5605 | case COMP_A_gt_B: | |
5606 | f = 0; | |
5607 | break; | |
5608 | case COMP_No_Comp: | |
5609 | f = SW_C3 | SW_C2 | SW_C0; | |
5610 | break; | |
5611 | #ifdef PARANOID | |
5612 | default: | |
5613 | EXCEPTION(EX_INTERNAL | 0x121); | |
5614 | f = SW_C3 | SW_C2 | SW_C0; | |
5615 | break; | |
5616 | #endif /* PARANOID */ | |
5617 | } | |
5618 | setcc(f); | |
5619 | return 1; | |
5620 | } | |
5621 | ||
5622 | ||
5623 | static int | |
5624 | compare_st_st(int nr) | |
5625 | { | |
5626 | int f, c; | |
5627 | ||
5628 | if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) { | |
5629 | setcc(SW_C3 | SW_C2 | SW_C0); | |
5630 | /* Stack fault */ | |
5631 | EXCEPTION(EX_StackUnder); | |
5632 | return control_word & CW_Invalid; | |
5633 | } | |
5634 | c = compare(&st(nr)); | |
5635 | if (c & (COMP_NaN | COMP_Denormal)) { | |
5636 | if (c & COMP_NaN) { | |
5637 | setcc(SW_C3 | SW_C2 | SW_C0); | |
5638 | EXCEPTION(EX_Invalid); | |
5639 | return control_word & CW_Invalid; | |
5640 | } else { | |
5641 | /* One of the operands is a de-normal */ | |
5642 | return control_word & CW_Denormal; | |
5643 | } | |
5644 | } else | |
5645 | switch (c) { | |
5646 | case COMP_A_lt_B: | |
5647 | f = SW_C0; | |
5648 | break; | |
5649 | case COMP_A_eq_B: | |
5650 | f = SW_C3; | |
5651 | break; | |
5652 | case COMP_A_gt_B: | |
5653 | f = 0; | |
5654 | break; | |
5655 | case COMP_No_Comp: | |
5656 | f = SW_C3 | SW_C2 | SW_C0; | |
5657 | break; | |
5658 | #ifdef PARANOID | |
5659 | default: | |
5660 | EXCEPTION(EX_INTERNAL | 0x122); | |
5661 | f = SW_C3 | SW_C2 | SW_C0; | |
5662 | break; | |
5663 | #endif /* PARANOID */ | |
5664 | } | |
5665 | setcc(f); | |
5666 | return 1; | |
5667 | } | |
5668 | ||
5669 | ||
5670 | static int | |
5671 | compare_u_st_st(int nr) | |
5672 | { | |
5673 | int f, c; | |
5674 | ||
5675 | if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) { | |
5676 | setcc(SW_C3 | SW_C2 | SW_C0); | |
5677 | /* Stack fault */ | |
5678 | EXCEPTION(EX_StackUnder); | |
5679 | return control_word & CW_Invalid; | |
5680 | } | |
5681 | c = compare(&st(nr)); | |
5682 | if (c & (COMP_NaN | COMP_Denormal)) { | |
5683 | if (c & COMP_NaN) { | |
5684 | setcc(SW_C3 | SW_C2 | SW_C0); | |
5685 | if (c & COMP_SNaN) { /* This is the only difference | |
5686 | * between un-ordered and | |
5687 | * ordinary comparisons */ | |
5688 | EXCEPTION(EX_Invalid); | |
5689 | return control_word & CW_Invalid; | |
5690 | } | |
5691 | return 1; | |
5692 | } else { | |
5693 | /* One of the operands is a de-normal */ | |
5694 | return control_word & CW_Denormal; | |
5695 | } | |
5696 | } else | |
5697 | switch (c) { | |
5698 | case COMP_A_lt_B: | |
5699 | f = SW_C0; | |
5700 | break; | |
5701 | case COMP_A_eq_B: | |
5702 | f = SW_C3; | |
5703 | break; | |
5704 | case COMP_A_gt_B: | |
5705 | f = 0; | |
5706 | break; | |
5707 | case COMP_No_Comp: | |
5708 | f = SW_C3 | SW_C2 | SW_C0; | |
5709 | break; | |
5710 | #ifdef PARANOID | |
5711 | default: | |
5712 | EXCEPTION(EX_INTERNAL | 0x123); | |
5713 | f = SW_C3 | SW_C2 | SW_C0; | |
5714 | break; | |
5715 | #endif /* PARANOID */ | |
5716 | } | |
5717 | setcc(f); | |
5718 | return 1; | |
5719 | } | |
5720 | /*---------------------------------------------------------------------------*/ | |
5721 | ||
5722 | void | |
5723 | fcom_st() | |
5724 | { | |
5725 | /* fcom st(i) */ | |
5726 | compare_st_st(FPU_rm); | |
5727 | } | |
5728 | ||
5729 | ||
5730 | void | |
5731 | fcompst() | |
5732 | { | |
5733 | /* fcomp st(i) */ | |
5734 | if (compare_st_st(FPU_rm)) | |
5735 | pop(); | |
5736 | } | |
5737 | ||
5738 | ||
5739 | void | |
5740 | fcompp() | |
5741 | { | |
5742 | /* fcompp */ | |
5743 | if (FPU_rm != 1) | |
5744 | return Un_impl(); | |
5745 | if (compare_st_st(1)) { | |
5746 | pop(); | |
5747 | FPU_st0_ptr = &st(0); | |
5748 | pop(); | |
5749 | } | |
5750 | } | |
5751 | ||
5752 | ||
5753 | void | |
5754 | fucom_() | |
5755 | { | |
5756 | /* fucom st(i) */ | |
5757 | compare_u_st_st(FPU_rm); | |
5758 | ||
5759 | } | |
5760 | ||
5761 | ||
5762 | void | |
5763 | fucomp() | |
5764 | { | |
5765 | /* fucomp st(i) */ | |
5766 | if (compare_u_st_st(FPU_rm)) | |
5767 | pop(); | |
5768 | } | |
5769 | ||
5770 | ||
5771 | void | |
5772 | fucompp() | |
5773 | { | |
5774 | /* fucompp */ | |
5775 | if (FPU_rm == 1) { | |
5776 | if (compare_u_st_st(1)) { | |
5777 | pop(); | |
5778 | FPU_st0_ptr = &st(0); | |
5779 | pop(); | |
5780 | } | |
5781 | } else | |
5782 | Un_impl(); | |
5783 | } | |
5784 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_constant.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 10724 5462320165 13427\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
5785 | * reg_constant.c | |
5786 | * | |
5787 | * All of the constant FPU_REGs | |
5788 | * | |
5789 | * | |
5790 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
5791 | * Vic 3163, Australia. | |
5792 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
5793 | * All rights reserved. | |
5794 | * | |
5795 | * This copyright notice covers the redistribution and use of the | |
5796 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
5797 | * in the 386BSD operating system. Any other use is not permitted | |
5798 | * under this copyright. | |
5799 | * | |
5800 | * Redistribution and use in source and binary forms, with or without | |
5801 | * modification, are permitted provided that the following conditions | |
5802 | * are met: | |
5803 | * 1. Redistributions of source code must retain the above copyright | |
5804 | * notice, this list of conditions and the following disclaimer. | |
5805 | * 2. Redistributions in binary form must include information specifying | |
5806 | * that source code for the emulator is freely available and include | |
5807 | * either: | |
5808 | * a) an offer to provide the source code for a nominal distribution | |
5809 | * fee, or | |
5810 | * b) list at least two alternative methods whereby the source | |
5811 | * can be obtained, e.g. a publically accessible bulletin board | |
5812 | * and an anonymous ftp site from which the software can be | |
5813 | * downloaded. | |
5814 | * 3. All advertising materials specifically mentioning features or use of | |
5815 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
5816 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
5817 | * products derived from this software without specific prior written | |
5818 | * permission. | |
5819 | * | |
5820 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
5821 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
5822 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
5823 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
5824 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
5825 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
5826 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
5827 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
5828 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
5829 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
5830 | * | |
5831 | */ | |
5832 | #include "param.h" | |
5833 | #include "proc.h" | |
5834 | #include "systm.h" | |
5835 | #include "machine/cpu.h" | |
5836 | #include "machine/pcb.h" | |
5837 | ||
5838 | #include "fpu_emu.h" | |
5839 | #include "fpu_system.h" | |
5840 | #include "status_w.h" | |
5841 | #include "reg_constant.h" | |
5842 | ||
5843 | ||
5844 | FPU_REG CONST_1 = {SIGN_POS, TW_Valid, EXP_BIAS, | |
5845 | 0x00000000, 0x80000000}; | |
5846 | FPU_REG CONST_2 = {SIGN_POS, TW_Valid, EXP_BIAS + 1, | |
5847 | 0x00000000, 0x80000000}; | |
5848 | FPU_REG CONST_HALF = {SIGN_POS, TW_Valid, EXP_BIAS - 1, | |
5849 | 0x00000000, 0x80000000}; | |
5850 | FPU_REG CONST_L2T = {SIGN_POS, TW_Valid, EXP_BIAS + 1, | |
5851 | 0xcd1b8afe, 0xd49a784b}; | |
5852 | FPU_REG CONST_L2E = {SIGN_POS, TW_Valid, EXP_BIAS, | |
5853 | 0x5c17f0bc, 0xb8aa3b29}; | |
5854 | FPU_REG CONST_PI = {SIGN_POS, TW_Valid, EXP_BIAS + 1, | |
5855 | 0x2168c235, 0xc90fdaa2}; | |
5856 | FPU_REG CONST_PI2 = {SIGN_POS, TW_Valid, EXP_BIAS, | |
5857 | 0x2168c235, 0xc90fdaa2}; | |
5858 | FPU_REG CONST_PI4 = {SIGN_POS, TW_Valid, EXP_BIAS - 1, | |
5859 | 0x2168c235, 0xc90fdaa2}; | |
5860 | FPU_REG CONST_LG2 = {SIGN_POS, TW_Valid, EXP_BIAS - 2, | |
5861 | 0xfbcff799, 0x9a209a84}; | |
5862 | FPU_REG CONST_LN2 = {SIGN_POS, TW_Valid, EXP_BIAS - 1, | |
5863 | 0xd1cf79ac, 0xb17217f7}; | |
5864 | /* Only the sign (and tag) is used in internal zeroes */ | |
5865 | FPU_REG CONST_Z = {SIGN_POS, TW_Zero, 0, 0x0, 0x0}; | |
5866 | /* Only the sign and significand (and tag) are used in internal NaNs */ | |
5867 | /* The 80486 never generates one of these | |
5868 | FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 }; | |
5869 | */ | |
5870 | /* This is the real indefinite QNaN */ | |
5871 | FPU_REG CONST_QNaN = {SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000}; | |
5872 | /* Only the sign (and tag) is used in internal infinities */ | |
5873 | FPU_REG CONST_INF = {SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000}; | |
5874 | ||
5875 | ||
5876 | ||
5877 | static void | |
5878 | fld_const(FPU_REG * c) | |
5879 | { | |
5880 | FPU_REG *st_new_ptr; | |
5881 | ||
5882 | if (STACK_OVERFLOW) { | |
5883 | stack_overflow(); | |
5884 | return; | |
5885 | } | |
5886 | push(); | |
5887 | reg_move(c, FPU_st0_ptr); | |
5888 | status_word &= ~SW_C1; | |
5889 | } | |
5890 | ||
5891 | ||
5892 | static void | |
5893 | fld1(void) | |
5894 | { | |
5895 | fld_const(&CONST_1); | |
5896 | } | |
5897 | ||
5898 | static void | |
5899 | fldl2t(void) | |
5900 | { | |
5901 | fld_const(&CONST_L2T); | |
5902 | } | |
5903 | ||
5904 | static void | |
5905 | fldl2e(void) | |
5906 | { | |
5907 | fld_const(&CONST_L2E); | |
5908 | } | |
5909 | ||
5910 | static void | |
5911 | fldpi(void) | |
5912 | { | |
5913 | fld_const(&CONST_PI); | |
5914 | } | |
5915 | ||
5916 | static void | |
5917 | fldlg2(void) | |
5918 | { | |
5919 | fld_const(&CONST_LG2); | |
5920 | } | |
5921 | ||
5922 | static void | |
5923 | fldln2(void) | |
5924 | { | |
5925 | fld_const(&CONST_LN2); | |
5926 | } | |
5927 | ||
5928 | static void | |
5929 | fldz(void) | |
5930 | { | |
5931 | fld_const(&CONST_Z); | |
5932 | } | |
5933 | ||
5934 | static FUNC constants_table[] = { | |
5935 | fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, Un_impl | |
5936 | }; | |
5937 | ||
5938 | void | |
5939 | fconst(void) | |
5940 | { | |
5941 | (constants_table[FPU_rm]) (); | |
5942 | } | |
5943 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_constant.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 5332 5462320165 13440\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
5944 | * reg_constant.h | |
5945 | * | |
5946 | * | |
5947 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
5948 | * Vic 3163, Australia. | |
5949 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
5950 | * All rights reserved. | |
5951 | * | |
5952 | * This copyright notice covers the redistribution and use of the | |
5953 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
5954 | * in the 386BSD operating system. Any other use is not permitted | |
5955 | * under this copyright. | |
5956 | * | |
5957 | * Redistribution and use in source and binary forms, with or without | |
5958 | * modification, are permitted provided that the following conditions | |
5959 | * are met: | |
5960 | * 1. Redistributions of source code must retain the above copyright | |
5961 | * notice, this list of conditions and the following disclaimer. | |
5962 | * 2. Redistributions in binary form must include information specifying | |
5963 | * that source code for the emulator is freely available and include | |
5964 | * either: | |
5965 | * a) an offer to provide the source code for a nominal distribution | |
5966 | * fee, or | |
5967 | * b) list at least two alternative methods whereby the source | |
5968 | * can be obtained, e.g. a publically accessible bulletin board | |
5969 | * and an anonymous ftp site from which the software can be | |
5970 | * downloaded. | |
5971 | * 3. All advertising materials specifically mentioning features or use of | |
5972 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
5973 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
5974 | * products derived from this software without specific prior written | |
5975 | * permission. | |
5976 | * | |
5977 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
5978 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
5979 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
5980 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
5981 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
5982 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
5983 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
5984 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
5985 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
5986 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
5987 | * | |
5988 | */ | |
5989 | ||
5990 | #ifndef _REG_CONSTANT_H_ | |
5991 | #define _REG_CONSTANT_H_ | |
5992 | ||
5993 | #include "fpu_emu.h" | |
5994 | ||
5995 | extern FPU_REG CONST_1; | |
5996 | extern FPU_REG CONST_2; | |
5997 | extern FPU_REG CONST_HALF; | |
5998 | extern FPU_REG CONST_L2T; | |
5999 | extern FPU_REG CONST_L2E; | |
6000 | extern FPU_REG CONST_PI; | |
6001 | extern FPU_REG CONST_PI2; | |
6002 | extern FPU_REG CONST_PI4; | |
6003 | extern FPU_REG CONST_LG2; | |
6004 | extern FPU_REG CONST_LN2; | |
6005 | extern FPU_REG CONST_Z; | |
6006 | extern FPU_REG CONST_PINF; | |
6007 | extern FPU_REG CONST_INF; | |
6008 | extern FPU_REG CONST_MINF; | |
6009 | extern FPU_REG CONST_QNaN; | |
6010 | ||
6011 | #endif /* _REG_CONSTANT_H_ */ | |
6012 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_ld_str.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 104454 5462474522 13120\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
6013 | * reg_ld_str.c | |
6014 | * | |
6015 | * All of the functions which transfer data between user memory and FPU_REGs. | |
6016 | * | |
6017 | * | |
6018 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
6019 | * Vic 3163, Australia. | |
6020 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
6021 | * All rights reserved. | |
6022 | * | |
6023 | * This copyright notice covers the redistribution and use of the | |
6024 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
6025 | * in the 386BSD operating system. Any other use is not permitted | |
6026 | * under this copyright. | |
6027 | * | |
6028 | * Redistribution and use in source and binary forms, with or without | |
6029 | * modification, are permitted provided that the following conditions | |
6030 | * are met: | |
6031 | * 1. Redistributions of source code must retain the above copyright | |
6032 | * notice, this list of conditions and the following disclaimer. | |
6033 | * 2. Redistributions in binary form must include information specifying | |
6034 | * that source code for the emulator is freely available and include | |
6035 | * either: | |
6036 | * a) an offer to provide the source code for a nominal distribution | |
6037 | * fee, or | |
6038 | * b) list at least two alternative methods whereby the source | |
6039 | * can be obtained, e.g. a publically accessible bulletin board | |
6040 | * and an anonymous ftp site from which the software can be | |
6041 | * downloaded. | |
6042 | * 3. All advertising materials specifically mentioning features or use of | |
6043 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
6044 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
6045 | * products derived from this software without specific prior written | |
6046 | * permission. | |
6047 | * | |
6048 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
6049 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
6050 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
6051 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
6052 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
6053 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
6054 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
6055 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
6056 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
6057 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
6058 | * | |
6059 | */ | |
6060 | ||
6061 | ||
6062 | /*---------------------------------------------------------------------------+ | |
6063 | | Note: | | |
6064 | | The file contains code which accesses user memory. | | |
6065 | | Emulator static data may change when user memory is accessed, due to | | |
6066 | | other processes using the emulator while swapping is in progress. | | |
6067 | +---------------------------------------------------------------------------*/ | |
6068 | #include "param.h" | |
6069 | #include "proc.h" | |
6070 | #include "systm.h" | |
6071 | #include "machine/cpu.h" | |
6072 | #include "machine/pcb.h" | |
6073 | ||
6074 | #include "fpu_emu.h" | |
6075 | #include "fpu_system.h" | |
6076 | #include "exception.h" | |
6077 | #include "reg_constant.h" | |
6078 | #include "control_w.h" | |
6079 | #include "status_w.h" | |
6080 | ||
6081 | ||
6082 | #define EXTENDED_Emax 0x3fff /* largest valid exponent */ | |
6083 | #define EXTENDED_Ebias 0x3fff | |
6084 | #define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ | |
6085 | ||
6086 | #define DOUBLE_Emax 1023 /* largest valid exponent */ | |
6087 | #define DOUBLE_Ebias 1023 | |
6088 | #define DOUBLE_Emin (-1022) /* smallest valid exponent */ | |
6089 | ||
6090 | #define SINGLE_Emax 127 /* largest valid exponent */ | |
6091 | #define SINGLE_Ebias 127 | |
6092 | #define SINGLE_Emin (-126) /* smallest valid exponent */ | |
6093 | ||
6094 | #define LOST_UP (EX_Precision | SW_C1) | |
6095 | #define LOST_DOWN EX_Precision | |
6096 | ||
6097 | FPU_REG FPU_loaded_data; | |
6098 | ||
6099 | ||
6100 | /* Get a long double from user memory */ | |
6101 | void | |
6102 | reg_load_extended(void) | |
6103 | { | |
6104 | long double *s = (long double *) FPU_data_address; | |
6105 | unsigned long sigl, sigh, exp; | |
6106 | ||
6107 | REENTRANT_CHECK(OFF); | |
6108 | /* Use temporary variables here because FPU_loaded data is static and | |
6109 | * hence re-entrancy problems can arise */ | |
6110 | sigl = fuword((unsigned long *) s); | |
6111 | sigh = fuword(1 + (unsigned long *) s); | |
6112 | exp = fuword(4 + (unsigned short *) s); | |
6113 | REENTRANT_CHECK(ON); | |
6114 | ||
6115 | FPU_loaded_data.sigl = sigl; | |
6116 | FPU_loaded_data.sigh = sigh; | |
6117 | FPU_loaded_data.exp = exp; | |
6118 | ||
6119 | if (FPU_loaded_data.exp & 0x8000) | |
6120 | FPU_loaded_data.sign = SIGN_NEG; | |
6121 | else | |
6122 | FPU_loaded_data.sign = SIGN_POS; | |
6123 | if ((FPU_loaded_data.exp &= 0x7fff) == 0) { | |
6124 | if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) { | |
6125 | FPU_loaded_data.tag = TW_Zero; | |
6126 | return; | |
6127 | } | |
6128 | /* The number is a de-normal or pseudodenormal. */ | |
6129 | /* The 80486 doesn't regard pseudodenormals as denormals here. */ | |
6130 | if (!(FPU_loaded_data.sigh & 0x80000000)) | |
6131 | EXCEPTION(EX_Denormal); | |
6132 | FPU_loaded_data.exp++; | |
6133 | ||
6134 | /* The default behaviour will now take care of it. */ | |
6135 | } else | |
6136 | if (FPU_loaded_data.exp == 0x7fff) { | |
6137 | FPU_loaded_data.exp = EXTENDED_Emax; | |
6138 | if ((FPU_loaded_data.sigh == 0x80000000) | |
6139 | && (FPU_loaded_data.sigl == 0)) { | |
6140 | FPU_loaded_data.tag = TW_Infinity; | |
6141 | return; | |
6142 | } else | |
6143 | if (!(FPU_loaded_data.sigh & 0x80000000)) { | |
6144 | /* Unsupported NaN data type */ | |
6145 | EXCEPTION(EX_Invalid); | |
6146 | FPU_loaded_data.tag = TW_NaN; | |
6147 | return; | |
6148 | } | |
6149 | FPU_loaded_data.tag = TW_NaN; | |
6150 | return; | |
6151 | } | |
6152 | FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias | |
6153 | + EXP_BIAS; | |
6154 | FPU_loaded_data.tag = TW_Valid; | |
6155 | ||
6156 | if (!(sigh & 0x80000000)) { | |
6157 | /* Unsupported data type */ | |
6158 | EXCEPTION(EX_Invalid); | |
6159 | normalize_nuo(&FPU_loaded_data); | |
6160 | } | |
6161 | } | |
6162 | ||
6163 | ||
6164 | /* Get a double from user memory */ | |
6165 | void | |
6166 | reg_load_double(void) | |
6167 | { | |
6168 | double *dfloat = (double *) FPU_data_address; | |
6169 | int exp; | |
6170 | unsigned m64, l64; | |
6171 | ||
6172 | REENTRANT_CHECK(OFF); | |
6173 | m64 = fuword(1 + (unsigned long *) dfloat); | |
6174 | l64 = fuword((unsigned long *) dfloat); | |
6175 | REENTRANT_CHECK(ON); | |
6176 | ||
6177 | if (m64 & 0x80000000) | |
6178 | FPU_loaded_data.sign = SIGN_NEG; | |
6179 | else | |
6180 | FPU_loaded_data.sign = SIGN_POS; | |
6181 | exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias; | |
6182 | m64 &= 0xfffff; | |
6183 | if (exp > DOUBLE_Emax) { | |
6184 | /* Infinity or NaN */ | |
6185 | if ((m64 == 0) && (l64 == 0)) { | |
6186 | /* +- infinity */ | |
6187 | FPU_loaded_data.exp = EXTENDED_Emax; | |
6188 | FPU_loaded_data.tag = TW_Infinity; | |
6189 | return; | |
6190 | } else { | |
6191 | /* Must be a signaling or quiet NaN */ | |
6192 | FPU_loaded_data.exp = EXTENDED_Emax; | |
6193 | FPU_loaded_data.tag = TW_NaN; | |
6194 | FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; | |
6195 | FPU_loaded_data.sigh |= l64 >> 21; | |
6196 | FPU_loaded_data.sigl = l64 << 11; | |
6197 | return; | |
6198 | } | |
6199 | } else | |
6200 | if (exp < DOUBLE_Emin) { | |
6201 | /* Zero or de-normal */ | |
6202 | if ((m64 == 0) && (l64 == 0)) { | |
6203 | /* Zero */ | |
6204 | int c = FPU_loaded_data.sign; | |
6205 | reg_move(&CONST_Z, &FPU_loaded_data); | |
6206 | FPU_loaded_data.sign = c; | |
6207 | return; | |
6208 | } else { | |
6209 | /* De-normal */ | |
6210 | EXCEPTION(EX_Denormal); | |
6211 | FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS; | |
6212 | FPU_loaded_data.tag = TW_Valid; | |
6213 | FPU_loaded_data.sigh = m64 << 11; | |
6214 | FPU_loaded_data.sigh |= l64 >> 21; | |
6215 | FPU_loaded_data.sigl = l64 << 11; | |
6216 | normalize_nuo(&FPU_loaded_data); | |
6217 | return; | |
6218 | } | |
6219 | } else { | |
6220 | FPU_loaded_data.exp = exp + EXP_BIAS; | |
6221 | FPU_loaded_data.tag = TW_Valid; | |
6222 | FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; | |
6223 | FPU_loaded_data.sigh |= l64 >> 21; | |
6224 | FPU_loaded_data.sigl = l64 << 11; | |
6225 | ||
6226 | return; | |
6227 | } | |
6228 | } | |
6229 | ||
6230 | ||
6231 | /* Get a float from user memory */ | |
6232 | void | |
6233 | reg_load_single(void) | |
6234 | { | |
6235 | float *single = (float *) FPU_data_address; | |
6236 | unsigned m32; | |
6237 | int exp; | |
6238 | ||
6239 | REENTRANT_CHECK(OFF); | |
6240 | m32 = fuword((unsigned long *) single); | |
6241 | REENTRANT_CHECK(ON); | |
6242 | ||
6243 | if (m32 & 0x80000000) | |
6244 | FPU_loaded_data.sign = SIGN_NEG; | |
6245 | else | |
6246 | FPU_loaded_data.sign = SIGN_POS; | |
6247 | if (!(m32 & 0x7fffffff)) { | |
6248 | /* Zero */ | |
6249 | int c = FPU_loaded_data.sign; | |
6250 | reg_move(&CONST_Z, &FPU_loaded_data); | |
6251 | FPU_loaded_data.sign = c; | |
6252 | return; | |
6253 | } | |
6254 | exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; | |
6255 | m32 = (m32 & 0x7fffff) << 8; | |
6256 | if (exp < SINGLE_Emin) { | |
6257 | /* De-normals */ | |
6258 | EXCEPTION(EX_Denormal); | |
6259 | FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS; | |
6260 | FPU_loaded_data.tag = TW_Valid; | |
6261 | FPU_loaded_data.sigh = m32; | |
6262 | FPU_loaded_data.sigl = 0; | |
6263 | normalize_nuo(&FPU_loaded_data); | |
6264 | return; | |
6265 | } else | |
6266 | if (exp > SINGLE_Emax) { | |
6267 | /* Infinity or NaN */ | |
6268 | if (m32 == 0) { | |
6269 | /* +- infinity */ | |
6270 | FPU_loaded_data.exp = EXTENDED_Emax; | |
6271 | FPU_loaded_data.tag = TW_Infinity; | |
6272 | return; | |
6273 | } else { | |
6274 | /* Must be a signaling or quiet NaN */ | |
6275 | FPU_loaded_data.exp = EXTENDED_Emax; | |
6276 | FPU_loaded_data.tag = TW_NaN; | |
6277 | FPU_loaded_data.sigh = m32 | 0x80000000; | |
6278 | FPU_loaded_data.sigl = 0; | |
6279 | return; | |
6280 | } | |
6281 | } else { | |
6282 | FPU_loaded_data.exp = exp + EXP_BIAS; | |
6283 | FPU_loaded_data.sigh = m32 | 0x80000000; | |
6284 | FPU_loaded_data.sigl = 0; | |
6285 | FPU_loaded_data.tag = TW_Valid; | |
6286 | } | |
6287 | } | |
6288 | ||
6289 | ||
6290 | /* Get a long long from user memory */ | |
6291 | void | |
6292 | reg_load_int64(void) | |
6293 | { | |
6294 | long long *_s = (long long *) FPU_data_address; | |
6295 | int e; | |
6296 | long long s; | |
6297 | ||
6298 | REENTRANT_CHECK(OFF); | |
6299 | ((unsigned long *) &s)[0] = fuword((unsigned long *) _s); | |
6300 | ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s); | |
6301 | REENTRANT_CHECK(ON); | |
6302 | ||
6303 | if (s == 0) { | |
6304 | reg_move(&CONST_Z, &FPU_loaded_data); | |
6305 | return; | |
6306 | } | |
6307 | if (s > 0) | |
6308 | FPU_loaded_data.sign = SIGN_POS; | |
6309 | else { | |
6310 | s = -s; | |
6311 | FPU_loaded_data.sign = SIGN_NEG; | |
6312 | } | |
6313 | ||
6314 | e = EXP_BIAS + 63; | |
6315 | *((long long *) &FPU_loaded_data.sigl) = s; | |
6316 | FPU_loaded_data.exp = e; | |
6317 | FPU_loaded_data.tag = TW_Valid; | |
6318 | normalize_nuo(&FPU_loaded_data); | |
6319 | } | |
6320 | ||
6321 | ||
6322 | /* Get a long from user memory */ | |
6323 | void | |
6324 | reg_load_int32(void) | |
6325 | { | |
6326 | long *_s = (long *) FPU_data_address; | |
6327 | long s; | |
6328 | int e; | |
6329 | ||
6330 | REENTRANT_CHECK(OFF); | |
6331 | s = (long) fuword((unsigned long *) _s); | |
6332 | REENTRANT_CHECK(ON); | |
6333 | ||
6334 | if (s == 0) { | |
6335 | reg_move(&CONST_Z, &FPU_loaded_data); | |
6336 | return; | |
6337 | } | |
6338 | if (s > 0) | |
6339 | FPU_loaded_data.sign = SIGN_POS; | |
6340 | else { | |
6341 | s = -s; | |
6342 | FPU_loaded_data.sign = SIGN_NEG; | |
6343 | } | |
6344 | ||
6345 | e = EXP_BIAS + 31; | |
6346 | FPU_loaded_data.sigh = s; | |
6347 | FPU_loaded_data.sigl = 0; | |
6348 | FPU_loaded_data.exp = e; | |
6349 | FPU_loaded_data.tag = TW_Valid; | |
6350 | normalize_nuo(&FPU_loaded_data); | |
6351 | } | |
6352 | ||
6353 | ||
6354 | /* Get a short from user memory */ | |
6355 | void | |
6356 | reg_load_int16(void) | |
6357 | { | |
6358 | short *_s = (short *) FPU_data_address; | |
6359 | int s, e; | |
6360 | ||
6361 | REENTRANT_CHECK(OFF); | |
6362 | /* Cast as short to get the sign extended. */ | |
6363 | s = (short) fuword((unsigned short *) _s); | |
6364 | REENTRANT_CHECK(ON); | |
6365 | ||
6366 | if (s == 0) { | |
6367 | reg_move(&CONST_Z, &FPU_loaded_data); | |
6368 | return; | |
6369 | } | |
6370 | if (s > 0) | |
6371 | FPU_loaded_data.sign = SIGN_POS; | |
6372 | else { | |
6373 | s = -s; | |
6374 | FPU_loaded_data.sign = SIGN_NEG; | |
6375 | } | |
6376 | ||
6377 | e = EXP_BIAS + 15; | |
6378 | FPU_loaded_data.sigh = s << 16; | |
6379 | ||
6380 | FPU_loaded_data.sigl = 0; | |
6381 | FPU_loaded_data.exp = e; | |
6382 | FPU_loaded_data.tag = TW_Valid; | |
6383 | normalize_nuo(&FPU_loaded_data); | |
6384 | } | |
6385 | ||
6386 | ||
6387 | /* Get a packed bcd array from user memory */ | |
6388 | void | |
6389 | reg_load_bcd(void) | |
6390 | { | |
6391 | char *s = (char *) FPU_data_address; | |
6392 | int pos; | |
6393 | unsigned char bcd; | |
6394 | long long l = 0; | |
6395 | ||
6396 | for (pos = 8; pos >= 0; pos--) { | |
6397 | l *= 10; | |
6398 | REENTRANT_CHECK(OFF); | |
6399 | bcd = (unsigned char) fubyte((unsigned char *) s + pos); | |
6400 | REENTRANT_CHECK(ON); | |
6401 | l += bcd >> 4; | |
6402 | l *= 10; | |
6403 | l += bcd & 0x0f; | |
6404 | } | |
6405 | ||
6406 | /* Finish all access to user memory before putting stuff into the | |
6407 | * static FPU_loaded_data */ | |
6408 | REENTRANT_CHECK(OFF); | |
6409 | FPU_loaded_data.sign = | |
6410 | ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ? | |
6411 | SIGN_NEG : SIGN_POS; | |
6412 | REENTRANT_CHECK(ON); | |
6413 | ||
6414 | if (l == 0) { | |
6415 | char sign = FPU_loaded_data.sign; | |
6416 | reg_move(&CONST_Z, &FPU_loaded_data); | |
6417 | FPU_loaded_data.sign = sign; | |
6418 | } else { | |
6419 | *((long long *) &FPU_loaded_data.sigl) = l; | |
6420 | FPU_loaded_data.exp = EXP_BIAS + 63; | |
6421 | FPU_loaded_data.tag = TW_Valid; | |
6422 | normalize_nuo(&FPU_loaded_data); | |
6423 | } | |
6424 | } | |
6425 | /*===========================================================================*/ | |
6426 | ||
6427 | /* Put a long double into user memory */ | |
6428 | int | |
6429 | reg_store_extended(void) | |
6430 | { | |
6431 | long double *d = (long double *) FPU_data_address; | |
6432 | long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias; | |
6433 | unsigned short sign = FPU_st0_ptr->sign * 0x8000; | |
6434 | unsigned long ls, ms; | |
6435 | ||
6436 | ||
6437 | if (FPU_st0_tag == TW_Valid) { | |
6438 | if (e >= 0x7fff) { | |
6439 | EXCEPTION(EX_Overflow); /* Overflow */ | |
6440 | /* This is a special case: see sec 16.2.5.1 of the | |
6441 | * 80486 book */ | |
6442 | if (control_word & EX_Overflow) { | |
6443 | /* Overflow to infinity */ | |
6444 | ls = 0; | |
6445 | ms = 0x80000000; | |
6446 | e = 0x7fff; | |
6447 | } else | |
6448 | return 0; | |
6449 | } else | |
6450 | if (e <= 0) { | |
6451 | if (e > -63) { | |
6452 | /* Correctly format the de-normal */ | |
6453 | int precision_loss; | |
6454 | FPU_REG tmp; | |
6455 | ||
6456 | EXCEPTION(EX_Denormal); | |
6457 | reg_move(FPU_st0_ptr, &tmp); | |
6458 | tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */ | |
6459 | if ((precision_loss = round_to_int(&tmp))) { | |
6460 | EXCEPTION(EX_Underflow | precision_loss); | |
6461 | /* This is a special case: see | |
6462 | * sec 16.2.5.1 of the 80486 | |
6463 | * book */ | |
6464 | if (!(control_word & EX_Underflow)) | |
6465 | return 0; | |
6466 | } | |
6467 | e = 0; | |
6468 | ls = tmp.sigl; | |
6469 | ms = tmp.sigh; | |
6470 | } else { | |
6471 | /* ****** ??? This should not be | |
6472 | * possible */ | |
6473 | EXCEPTION(EX_Underflow); /* Underflow */ | |
6474 | /* This is a special case: see sec | |
6475 | * 16.2.5.1 of the 80486 book */ | |
6476 | if (control_word & EX_Underflow) { | |
6477 | /* Underflow to zero */ | |
6478 | ls = 0; | |
6479 | ms = 0; | |
6480 | e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff; | |
6481 | } else | |
6482 | return 0; | |
6483 | } | |
6484 | } else { | |
6485 | ls = FPU_st0_ptr->sigl; | |
6486 | ms = FPU_st0_ptr->sigh; | |
6487 | } | |
6488 | } else | |
6489 | if (FPU_st0_tag == TW_Zero) { | |
6490 | ls = ms = 0; | |
6491 | e = 0; | |
6492 | } else | |
6493 | if (FPU_st0_tag == TW_Infinity) { | |
6494 | ls = 0; | |
6495 | ms = 0x80000000; | |
6496 | e = 0x7fff; | |
6497 | } else | |
6498 | if (FPU_st0_tag == TW_NaN) { | |
6499 | ls = FPU_st0_ptr->sigl; | |
6500 | ms = FPU_st0_ptr->sigh; | |
6501 | e = 0x7fff; | |
6502 | } else | |
6503 | if (FPU_st0_tag == TW_Empty) { | |
6504 | /* Empty register (stack | |
6505 | * underflow) */ | |
6506 | EXCEPTION(EX_StackUnder); | |
6507 | if (control_word & EX_Invalid) { | |
6508 | /* The masked response */ | |
6509 | /* Put out the QNaN | |
6510 | * indefinite */ | |
6511 | ls = 0; | |
6512 | ms = 0xc0000000; | |
6513 | e = 0xffff; | |
6514 | } else | |
6515 | return 0; | |
6516 | } else { | |
6517 | /* We don't use TW_Denormal | |
6518 | * yet ... perhaps never! */ | |
6519 | EXCEPTION(EX_Invalid); | |
6520 | /* Store a NaN */ | |
6521 | e = 0x7fff; | |
6522 | ls = 1; | |
6523 | ms = 0x80000000; | |
6524 | } | |
6525 | REENTRANT_CHECK(OFF); | |
6526 | /* verify_area(VERIFY_WRITE, d, 10); */ | |
6527 | suword((unsigned long *) d, ls); | |
6528 | suword(1 + (unsigned long *) d, ms); | |
6529 | suword(4 + (short *) d, (unsigned short) e | sign); | |
6530 | REENTRANT_CHECK(ON); | |
6531 | ||
6532 | return 1; | |
6533 | ||
6534 | } | |
6535 | ||
6536 | ||
6537 | /* Put a double into user memory */ | |
6538 | int | |
6539 | reg_store_double(void) | |
6540 | { | |
6541 | double *dfloat = (double *) FPU_data_address; | |
6542 | unsigned long l[2]; | |
6543 | if (FPU_st0_tag == TW_Valid) { | |
6544 | int exp; | |
6545 | FPU_REG tmp; | |
6546 | ||
6547 | reg_move(FPU_st0_ptr, &tmp); | |
6548 | exp = tmp.exp - EXP_BIAS; | |
6549 | ||
6550 | if (exp < DOUBLE_Emin) { /* It may be a denormal */ | |
6551 | /* Make a de-normal */ | |
6552 | int precision_loss; | |
6553 | ||
6554 | if (exp <= -EXTENDED_Ebias) | |
6555 | EXCEPTION(EX_Denormal); | |
6556 | ||
6557 | tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */ | |
6558 | ||
6559 | if ((precision_loss = round_to_int(&tmp))) { | |
6560 | #ifdef PECULIAR_486 | |
6561 | /* Did it round to a non-denormal ? */ | |
6562 | /* This behaviour might be regarded as | |
6563 | * peculiar, it appears that the 80486 rounds | |
6564 | * to the dest precision, then converts to | |
6565 | * decide underflow. */ | |
6566 | if ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && | |
6567 | (FPU_st0_ptr->sigl & 0x000007ff)) | |
6568 | EXCEPTION(precision_loss); | |
6569 | else | |
6570 | #endif /* PECULIAR_486 */ | |
6571 | { | |
6572 | EXCEPTION(EX_Underflow | precision_loss); | |
6573 | /* This is a special case: see sec | |
6574 | * 16.2.5.1 of the 80486 book */ | |
6575 | if (!(control_word & EX_Underflow)) | |
6576 | return 0; | |
6577 | } | |
6578 | } | |
6579 | l[0] = tmp.sigl; | |
6580 | l[1] = tmp.sigh; | |
6581 | } else { | |
6582 | if (tmp.sigl & 0x000007ff) { | |
6583 | unsigned long increment = 0; /* avoid gcc warnings */ | |
6584 | ||
6585 | switch (control_word & CW_RC) { | |
6586 | case RC_RND: | |
6587 | /* Rounding can get a little messy.. */ | |
6588 | increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */ | |
6589 | ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */ | |
6590 | break; | |
6591 | case RC_DOWN: /* towards -infinity */ | |
6592 | increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff; | |
6593 | break; | |
6594 | case RC_UP: /* towards +infinity */ | |
6595 | increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0; | |
6596 | break; | |
6597 | case RC_CHOP: | |
6598 | increment = 0; | |
6599 | break; | |
6600 | } | |
6601 | ||
6602 | /* Truncate the mantissa */ | |
6603 | tmp.sigl &= 0xfffff800; | |
6604 | ||
6605 | if (increment) { | |
6606 | set_precision_flag_up(); | |
6607 | ||
6608 | if (tmp.sigl >= 0xfffff800) { | |
6609 | /* the sigl part overflows */ | |
6610 | if (tmp.sigh == 0xffffffff) { | |
6611 | /* The sigh part | |
6612 | * overflows */ | |
6613 | tmp.sigh = 0x80000000; | |
6614 | exp++; | |
6615 | if (exp >= EXP_OVER) | |
6616 | goto overflow; | |
6617 | } else { | |
6618 | tmp.sigh++; | |
6619 | } | |
6620 | tmp.sigl = 0x00000000; | |
6621 | } else { | |
6622 | /* We only need to increment | |
6623 | * sigl */ | |
6624 | tmp.sigl += 0x00000800; | |
6625 | } | |
6626 | } else | |
6627 | set_precision_flag_down(); | |
6628 | } | |
6629 | l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21); | |
6630 | l[1] = ((tmp.sigh >> 11) & 0xfffff); | |
6631 | ||
6632 | if (exp > DOUBLE_Emax) { | |
6633 | overflow: | |
6634 | EXCEPTION(EX_Overflow); | |
6635 | /* This is a special case: see sec 16.2.5.1 of | |
6636 | * the 80486 book */ | |
6637 | if (control_word & EX_Overflow) { | |
6638 | /* Overflow to infinity */ | |
6639 | l[0] = 0x00000000; /* Set to */ | |
6640 | l[1] = 0x7ff00000; /* + INF */ | |
6641 | } else | |
6642 | return 0; | |
6643 | } else { | |
6644 | /* Add the exponent */ | |
6645 | l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20); | |
6646 | } | |
6647 | } | |
6648 | } else | |
6649 | if (FPU_st0_tag == TW_Zero) { | |
6650 | /* Number is zero */ | |
6651 | l[0] = 0; | |
6652 | l[1] = 0; | |
6653 | } else | |
6654 | if (FPU_st0_tag == TW_Infinity) { | |
6655 | l[0] = 0; | |
6656 | l[1] = 0x7ff00000; | |
6657 | } else | |
6658 | if (FPU_st0_tag == TW_NaN) { | |
6659 | /* See if we can get a valid NaN from | |
6660 | * the FPU_REG */ | |
6661 | l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21); | |
6662 | l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); | |
6663 | if (!(l[0] | l[1])) { | |
6664 | /* This case does not seem to | |
6665 | * be handled by the 80486 | |
6666 | * specs */ | |
6667 | EXCEPTION(EX_Invalid); | |
6668 | /* Make the quiet NaN "real | |
6669 | * indefinite" */ | |
6670 | goto put_indefinite; | |
6671 | } | |
6672 | l[1] |= 0x7ff00000; | |
6673 | } else | |
6674 | if (FPU_st0_tag == TW_Empty) { | |
6675 | /* Empty register (stack | |
6676 | * underflow) */ | |
6677 | EXCEPTION(EX_StackUnder); | |
6678 | if (control_word & EX_Invalid) { | |
6679 | /* The masked response */ | |
6680 | /* Put out the QNaN | |
6681 | * indefinite */ | |
6682 | put_indefinite: | |
6683 | REENTRANT_CHECK(OFF); | |
6684 | /* verify_area(VERIFY_W | |
6685 | * RITE, (void *) | |
6686 | * dfloat, 8); */ | |
6687 | suword((unsigned long *) dfloat, 0); | |
6688 | suword(1 + (unsigned long *) dfloat, 0xfff80000); | |
6689 | REENTRANT_CHECK(ON); | |
6690 | return 1; | |
6691 | } else | |
6692 | return 0; | |
6693 | } | |
6694 | #if 0 /* TW_Denormal is not used yet, and probably | |
6695 | * won't be */ | |
6696 | else | |
6697 | if (FPU_st0_tag == TW_Denormal) { | |
6698 | /* Extended real -> | |
6699 | * double real will | |
6700 | * always underflow */ | |
6701 | l[0] = l[1] = 0; | |
6702 | EXCEPTION(EX_Underflow); | |
6703 | } | |
6704 | #endif | |
6705 | if (FPU_st0_ptr->sign) | |
6706 | l[1] |= 0x80000000; | |
6707 | ||
6708 | REENTRANT_CHECK(OFF); | |
6709 | /* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/ | |
6710 | suword((u_long *) dfloat, l[0]); | |
6711 | suword((u_long *) dfloat + 1, l[1]); | |
6712 | /* | |
6713 | suword(l[0], (unsigned long *) dfloat); | |
6714 | suword(l[1], 1 + (unsigned long *) dfloat);*/ | |
6715 | REENTRANT_CHECK(ON); | |
6716 | ||
6717 | return 1; | |
6718 | } | |
6719 | ||
6720 | ||
6721 | /* Put a float into user memory */ | |
6722 | int | |
6723 | reg_store_single(void) | |
6724 | { | |
6725 | float *single = (float *) FPU_data_address; | |
6726 | long templ; | |
6727 | ||
6728 | if (FPU_st0_tag == TW_Valid) { | |
6729 | int exp; | |
6730 | FPU_REG tmp; | |
6731 | ||
6732 | reg_move(FPU_st0_ptr, &tmp); | |
6733 | exp = tmp.exp - EXP_BIAS; | |
6734 | ||
6735 | if (exp < SINGLE_Emin) { | |
6736 | /* Make a de-normal */ | |
6737 | int precision_loss; | |
6738 | ||
6739 | if (exp <= -EXTENDED_Ebias) | |
6740 | EXCEPTION(EX_Denormal); | |
6741 | ||
6742 | tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */ | |
6743 | ||
6744 | if ((precision_loss = round_to_int(&tmp))) { | |
6745 | #ifdef PECULIAR_486 | |
6746 | /* Did it round to a non-denormal ? */ | |
6747 | /* This behaviour might be regarded as | |
6748 | * peculiar, it appears that the 80486 rounds | |
6749 | * to the dest precision, then converts to | |
6750 | * decide underflow. */ | |
6751 | if ((tmp.sigl == 0x00800000) && | |
6752 | ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) | |
6753 | EXCEPTION(precision_loss); | |
6754 | else | |
6755 | #endif /* PECULIAR_486 */ | |
6756 | { | |
6757 | EXCEPTION(EX_Underflow | precision_loss); | |
6758 | /* This is a special case: see sec | |
6759 | * 16.2.5.1 of the 80486 book */ | |
6760 | if (!(control_word & EX_Underflow)) | |
6761 | return 0; | |
6762 | } | |
6763 | } | |
6764 | templ = tmp.sigl; | |
6765 | } else { | |
6766 | if (tmp.sigl | (tmp.sigh & 0x000000ff)) { | |
6767 | unsigned long increment = 0; /* avoid gcc warnings */ | |
6768 | unsigned long sigh = tmp.sigh; | |
6769 | unsigned long sigl = tmp.sigl; | |
6770 | ||
6771 | switch (control_word & CW_RC) { | |
6772 | case RC_RND: | |
6773 | increment = ((sigh & 0xff) > 0x80) /* more than half */ | |
6774 | ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */ | |
6775 | ||((sigh & 0x180) == 0x180); /* round to even */ | |
6776 | break; | |
6777 | case RC_DOWN: /* towards -infinity */ | |
6778 | increment = (tmp.sign == SIGN_POS) | |
6779 | ? 0 : (sigl | (sigh & 0xff)); | |
6780 | break; | |
6781 | case RC_UP: /* towards +infinity */ | |
6782 | increment = (tmp.sign == SIGN_POS) | |
6783 | ? (sigl | (sigh & 0xff)) : 0; | |
6784 | break; | |
6785 | case RC_CHOP: | |
6786 | increment = 0; | |
6787 | break; | |
6788 | } | |
6789 | ||
6790 | /* Truncate part of the mantissa */ | |
6791 | tmp.sigl = 0; | |
6792 | ||
6793 | if (increment) { | |
6794 | set_precision_flag_up(); | |
6795 | ||
6796 | if (sigh >= 0xffffff00) { | |
6797 | /* The sigh part overflows */ | |
6798 | tmp.sigh = 0x80000000; | |
6799 | exp++; | |
6800 | if (exp >= EXP_OVER) | |
6801 | goto overflow; | |
6802 | } else { | |
6803 | tmp.sigh &= 0xffffff00; | |
6804 | tmp.sigh += 0x100; | |
6805 | } | |
6806 | } else { | |
6807 | set_precision_flag_down(); | |
6808 | tmp.sigh &= 0xffffff00; /* Finish the truncation */ | |
6809 | } | |
6810 | } | |
6811 | templ = (tmp.sigh >> 8) & 0x007fffff; | |
6812 | ||
6813 | if (exp > SINGLE_Emax) { | |
6814 | overflow: | |
6815 | EXCEPTION(EX_Overflow); | |
6816 | /* This is a special case: see sec 16.2.5.1 of | |
6817 | * the 80486 book */ | |
6818 | if (control_word & EX_Overflow) { | |
6819 | /* Overflow to infinity */ | |
6820 | templ = 0x7f800000; | |
6821 | } else | |
6822 | return 0; | |
6823 | } else | |
6824 | templ |= ((exp + SINGLE_Ebias) & 0xff) << 23; | |
6825 | } | |
6826 | } else | |
6827 | if (FPU_st0_tag == TW_Zero) { | |
6828 | templ = 0; | |
6829 | } else | |
6830 | if (FPU_st0_tag == TW_Infinity) { | |
6831 | templ = 0x7f800000; | |
6832 | } else | |
6833 | if (FPU_st0_tag == TW_NaN) { | |
6834 | /* See if we can get a valid NaN from | |
6835 | * the FPU_REG */ | |
6836 | templ = FPU_st0_ptr->sigh >> 8; | |
6837 | if (!(templ & 0x3fffff)) { | |
6838 | /* This case does not seem to | |
6839 | * be handled by the 80486 | |
6840 | * specs */ | |
6841 | EXCEPTION(EX_Invalid); | |
6842 | /* Make the quiet NaN "real | |
6843 | * indefinite" */ | |
6844 | goto put_indefinite; | |
6845 | } | |
6846 | templ |= 0x7f800000; | |
6847 | } else | |
6848 | if (FPU_st0_tag == TW_Empty) { | |
6849 | /* Empty register (stack | |
6850 | * underflow) */ | |
6851 | EXCEPTION(EX_StackUnder); | |
6852 | if (control_word & EX_Invalid) { | |
6853 | /* The masked response */ | |
6854 | /* Put out the QNaN | |
6855 | * indefinite */ | |
6856 | put_indefinite: | |
6857 | REENTRANT_CHECK(OFF); | |
6858 | /* verify_area(VERIFY_WRITE, (void *) single, 4); */ | |
6859 | suword((unsigned long *) single, 0xffc00000); | |
6860 | REENTRANT_CHECK(ON); | |
6861 | return 1; | |
6862 | } else | |
6863 | return 0; | |
6864 | } | |
6865 | #if 0 /* TW_Denormal is not used yet, and probably | |
6866 | * won't be */ | |
6867 | else | |
6868 | if (FPU_st0_tag == TW_Denormal) { | |
6869 | /* Extended real -> | |
6870 | * real will always | |
6871 | * underflow */ | |
6872 | templ = 0; | |
6873 | EXCEPTION(EX_Underflow); | |
6874 | } | |
6875 | #endif | |
6876 | #ifdef PARANOID | |
6877 | else { | |
6878 | EXCEPTION(EX_INTERNAL | 0x106); | |
6879 | return 0; | |
6880 | } | |
6881 | #endif | |
6882 | if (FPU_st0_ptr->sign) | |
6883 | templ |= 0x80000000; | |
6884 | ||
6885 | REENTRANT_CHECK(OFF); | |
6886 | /* verify_area(VERIFY_WRITE, (void *) single, 4); */ | |
6887 | suword((unsigned long *) single, templ); | |
6888 | REENTRANT_CHECK(ON); | |
6889 | ||
6890 | return 1; | |
6891 | } | |
6892 | ||
6893 | ||
6894 | /* Put a long long into user memory */ | |
6895 | int | |
6896 | reg_store_int64(void) | |
6897 | { | |
6898 | long long *d = (long long *) FPU_data_address; | |
6899 | FPU_REG t; | |
6900 | long long tll; | |
6901 | ||
6902 | if (FPU_st0_tag == TW_Empty) { | |
6903 | /* Empty register (stack underflow) */ | |
6904 | EXCEPTION(EX_StackUnder); | |
6905 | if (control_word & EX_Invalid) { | |
6906 | /* The masked response */ | |
6907 | /* Put out the QNaN indefinite */ | |
6908 | goto put_indefinite; | |
6909 | } else | |
6910 | return 0; | |
6911 | } | |
6912 | reg_move(FPU_st0_ptr, &t); | |
6913 | round_to_int(&t); | |
6914 | ((long *) &tll)[0] = t.sigl; | |
6915 | ((long *) &tll)[1] = t.sigh; | |
6916 | if ((t.sigh & 0x80000000) && | |
6917 | !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) { | |
6918 | EXCEPTION(EX_Invalid); | |
6919 | /* This is a special case: see sec 16.2.5.1 of the 80486 book */ | |
6920 | if (control_word & EX_Invalid) { | |
6921 | /* Produce "indefinite" */ | |
6922 | put_indefinite: | |
6923 | ((long *) &tll)[1] = 0x80000000; | |
6924 | ((long *) &tll)[0] = 0; | |
6925 | } else | |
6926 | return 0; | |
6927 | } else | |
6928 | if (t.sign) | |
6929 | tll = -tll; | |
6930 | ||
6931 | REENTRANT_CHECK(OFF); | |
6932 | /* verify_area(VERIFY_WRITE, (void *) d, 8); */ | |
6933 | suword((unsigned long *) d, ((long *) &tll)[0]); | |
6934 | suword(1 + (unsigned long *) d, ((long *) &tll)[1]); | |
6935 | REENTRANT_CHECK(ON); | |
6936 | ||
6937 | return 1; | |
6938 | } | |
6939 | ||
6940 | ||
6941 | /* Put a long into user memory */ | |
6942 | int | |
6943 | reg_store_int32(void) | |
6944 | { | |
6945 | long *d = (long *) FPU_data_address; | |
6946 | FPU_REG t; | |
6947 | ||
6948 | if (FPU_st0_tag == TW_Empty) { | |
6949 | /* Empty register (stack underflow) */ | |
6950 | EXCEPTION(EX_StackUnder); | |
6951 | if (control_word & EX_Invalid) { | |
6952 | /* The masked response */ | |
6953 | /* Put out the QNaN indefinite */ | |
6954 | REENTRANT_CHECK(OFF); | |
6955 | /* verify_area(VERIFY_WRITE, d, 4);*/ | |
6956 | suword((unsigned long *) d, 0x80000000); | |
6957 | REENTRANT_CHECK(ON); | |
6958 | return 1; | |
6959 | } else | |
6960 | return 0; | |
6961 | } | |
6962 | reg_move(FPU_st0_ptr, &t); | |
6963 | round_to_int(&t); | |
6964 | if (t.sigh || | |
6965 | ((t.sigl & 0x80000000) && | |
6966 | !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG)))) { | |
6967 | EXCEPTION(EX_Invalid); | |
6968 | /* This is a special case: see sec 16.2.5.1 of the 80486 book */ | |
6969 | if (control_word & EX_Invalid) { | |
6970 | /* Produce "indefinite" */ | |
6971 | t.sigl = 0x80000000; | |
6972 | } else | |
6973 | return 0; | |
6974 | } else | |
6975 | if (t.sign) | |
6976 | t.sigl = -(long) t.sigl; | |
6977 | ||
6978 | REENTRANT_CHECK(OFF); | |
6979 | /* verify_area(VERIFY_WRITE, d, 4); */ | |
6980 | suword((unsigned long *) d, t.sigl); | |
6981 | REENTRANT_CHECK(ON); | |
6982 | ||
6983 | return 1; | |
6984 | } | |
6985 | ||
6986 | ||
6987 | /* Put a short into user memory */ | |
6988 | int | |
6989 | reg_store_int16(void) | |
6990 | { | |
6991 | short *d = (short *) FPU_data_address; | |
6992 | FPU_REG t; | |
6993 | short ts; | |
6994 | ||
6995 | if (FPU_st0_tag == TW_Empty) { | |
6996 | /* Empty register (stack underflow) */ | |
6997 | EXCEPTION(EX_StackUnder); | |
6998 | if (control_word & EX_Invalid) { | |
6999 | /* The masked response */ | |
7000 | /* Put out the QNaN indefinite */ | |
7001 | REENTRANT_CHECK(OFF); | |
7002 | /* verify_area(VERIFY_WRITE, d, 2);*/ | |
7003 | suword((unsigned short *) d, 0x8000); | |
7004 | REENTRANT_CHECK(ON); | |
7005 | return 1; | |
7006 | } else | |
7007 | return 0; | |
7008 | } | |
7009 | reg_move(FPU_st0_ptr, &t); | |
7010 | round_to_int(&t); | |
7011 | if (t.sigh || | |
7012 | ((t.sigl & 0xffff8000) && | |
7013 | !((t.sigl == 0x8000) && (t.sign == SIGN_NEG)))) { | |
7014 | EXCEPTION(EX_Invalid); | |
7015 | /* This is a special case: see sec 16.2.5.1 of the 80486 book */ | |
7016 | if (control_word & EX_Invalid) { | |
7017 | /* Produce "indefinite" */ | |
7018 | ts = 0x8000; | |
7019 | } else | |
7020 | return 0; | |
7021 | } else | |
7022 | if (t.sign) | |
7023 | t.sigl = -t.sigl; | |
7024 | ||
7025 | REENTRANT_CHECK(OFF); | |
7026 | /* verify_area(VERIFY_WRITE, d, 2); */ | |
7027 | suword((short *) d, (short) t.sigl); | |
7028 | REENTRANT_CHECK(ON); | |
7029 | ||
7030 | return 1; | |
7031 | } | |
7032 | ||
7033 | ||
7034 | /* Put a packed bcd array into user memory */ | |
7035 | int | |
7036 | reg_store_bcd(void) | |
7037 | { | |
7038 | char *d = (char *) FPU_data_address; | |
7039 | FPU_REG t; | |
7040 | long long ll; | |
7041 | unsigned char b; | |
7042 | int i; | |
7043 | unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0; | |
7044 | ||
7045 | if (FPU_st0_tag == TW_Empty) { | |
7046 | /* Empty register (stack underflow) */ | |
7047 | EXCEPTION(EX_StackUnder); | |
7048 | if (control_word & EX_Invalid) { | |
7049 | /* The masked response */ | |
7050 | /* Put out the QNaN indefinite */ | |
7051 | goto put_indefinite; | |
7052 | } else | |
7053 | return 0; | |
7054 | } | |
7055 | reg_move(FPU_st0_ptr, &t); | |
7056 | round_to_int(&t); | |
7057 | ll = *(long long *) (&t.sigl); | |
7058 | ||
7059 | /* Check for overflow, by comparing with 999999999999999999 decimal. */ | |
7060 | if ((t.sigh > 0x0de0b6b3) || | |
7061 | ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) { | |
7062 | EXCEPTION(EX_Invalid); | |
7063 | /* This is a special case: see sec 16.2.5.1 of the 80486 book */ | |
7064 | if (control_word & EX_Invalid) { | |
7065 | put_indefinite: | |
7066 | /* Produce "indefinite" */ | |
7067 | REENTRANT_CHECK(OFF); | |
7068 | /* verify_area(VERIFY_WRITE, d, 10);*/ | |
7069 | subyte((unsigned char *) d + 7, 0xff); | |
7070 | subyte((unsigned char *) d + 8, 0xff); | |
7071 | subyte((unsigned char *) d + 9, 0xff); | |
7072 | REENTRANT_CHECK(ON); | |
7073 | return 1; | |
7074 | } else | |
7075 | return 0; | |
7076 | } | |
7077 | /* verify_area(VERIFY_WRITE, d, 10);*/ | |
7078 | for (i = 0; i < 9; i++) { | |
7079 | b = div_small(&ll, 10); | |
7080 | b |= (div_small(&ll, 10)) << 4; | |
7081 | REENTRANT_CHECK(OFF); | |
7082 | subyte((unsigned char *) d + i, b); | |
7083 | REENTRANT_CHECK(ON); | |
7084 | } | |
7085 | REENTRANT_CHECK(OFF); | |
7086 | subyte((unsigned char *) d + 9, sign); | |
7087 | REENTRANT_CHECK(ON); | |
7088 | ||
7089 | return 1; | |
7090 | } | |
7091 | /*===========================================================================*/ | |
7092 | ||
7093 | /* r gets mangled such that sig is int, sign: | |
7094 | it is NOT normalized */ | |
7095 | /* The return value (in eax) is zero if the result is exact, | |
7096 | if bits are changed due to rounding, truncation, etc, then | |
7097 | a non-zero value is returned */ | |
7098 | /* Overflow is signalled by a non-zero return value (in eax). | |
7099 | In the case of overflow, the returned significand always has the | |
7100 | the largest possible value */ | |
7101 | /* The value returned in eax is never actually needed :-) */ | |
7102 | int | |
7103 | round_to_int(FPU_REG * r) | |
7104 | { | |
7105 | char very_big; | |
7106 | unsigned eax; | |
7107 | ||
7108 | if (r->tag == TW_Zero) { | |
7109 | /* Make sure that zero is returned */ | |
7110 | *(long long *) &r->sigl = 0; | |
7111 | return 0; /* o.k. */ | |
7112 | } | |
7113 | if (r->exp > EXP_BIAS + 63) { | |
7114 | r->sigl = r->sigh = ~0; /* The largest representable number */ | |
7115 | return 1; /* overflow */ | |
7116 | } | |
7117 | eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp); | |
7118 | very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */ | |
7119 | #define half_or_more (eax & 0x80000000) | |
7120 | #define frac_part (eax) | |
7121 | #define more_than_half ((eax & 0x80000001) == 0x80000001) | |
7122 | switch (control_word & CW_RC) { | |
7123 | case RC_RND: | |
7124 | if (more_than_half /* nearest */ | |
7125 | || (half_or_more && (r->sigl & 1))) { /* odd -> even */ | |
7126 | if (very_big) | |
7127 | return 1; /* overflow */ | |
7128 | (*(long long *) (&r->sigl))++; | |
7129 | return LOST_UP; | |
7130 | } | |
7131 | break; | |
7132 | case RC_DOWN: | |
7133 | if (frac_part && r->sign) { | |
7134 | if (very_big) | |
7135 | return 1; /* overflow */ | |
7136 | (*(long long *) (&r->sigl))++; | |
7137 | return LOST_UP; | |
7138 | } | |
7139 | break; | |
7140 | case RC_UP: | |
7141 | if (frac_part && !r->sign) { | |
7142 | if (very_big) | |
7143 | return 1; /* overflow */ | |
7144 | (*(long long *) (&r->sigl))++; | |
7145 | return LOST_UP; | |
7146 | } | |
7147 | break; | |
7148 | case RC_CHOP: | |
7149 | break; | |
7150 | } | |
7151 | ||
7152 | return eax ? LOST_DOWN : 0; | |
7153 | ||
7154 | } | |
7155 | /*===========================================================================*/ | |
7156 | ||
7157 | char * | |
7158 | fldenv(void) | |
7159 | { | |
7160 | char *s = (char *) FPU_data_address; | |
7161 | unsigned short tag_word = 0; | |
7162 | unsigned char tag; | |
7163 | int i; | |
7164 | ||
7165 | REENTRANT_CHECK(OFF); | |
7166 | control_word = fuword((unsigned short *) s); | |
7167 | status_word = fuword((unsigned short *) (s + 4)); | |
7168 | tag_word = fuword((unsigned short *) (s + 8)); | |
7169 | ip_offset = fuword((unsigned long *) (s + 0x0c)); | |
7170 | cs_selector = fuword((unsigned long *) (s + 0x10)); | |
7171 | data_operand_offset = fuword((unsigned long *) (s + 0x14)); | |
7172 | operand_selector = fuword((unsigned long *) (s + 0x18)); | |
7173 | REENTRANT_CHECK(ON); | |
7174 | ||
7175 | top = (status_word >> SW_Top_Shift) & 7; | |
7176 | ||
7177 | for (i = 0; i < 8; i++) { | |
7178 | tag = tag_word & 3; | |
7179 | tag_word >>= 2; | |
7180 | ||
7181 | switch (tag) { | |
7182 | case 0: | |
7183 | regs[i].tag = TW_Valid; | |
7184 | break; | |
7185 | case 1: | |
7186 | regs[i].tag = TW_Zero; | |
7187 | break; | |
7188 | case 2: | |
7189 | regs[i].tag = TW_NaN; | |
7190 | break; | |
7191 | case 3: | |
7192 | regs[i].tag = TW_Empty; | |
7193 | break; | |
7194 | } | |
7195 | } | |
7196 | ||
7197 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
7198 | FPU_entry_eip = ip_offset; /* We want no net effect */ | |
7199 | ||
7200 | return s + 0x1c; | |
7201 | } | |
7202 | ||
7203 | ||
7204 | void | |
7205 | frstor(void) | |
7206 | { | |
7207 | int i, stnr; | |
7208 | unsigned char tag; | |
7209 | unsigned short saved_status, saved_control; | |
7210 | char *s = (char *) fldenv(); | |
7211 | ||
7212 | saved_status = status_word; | |
7213 | saved_control = control_word; | |
7214 | control_word = 0x037f; /* Mask all interrupts while we load. */ | |
7215 | for (i = 0; i < 8; i++) { | |
7216 | /* load each register */ | |
7217 | FPU_data_address = (void *) (s + i * 10); | |
7218 | reg_load_extended(); | |
7219 | stnr = (i + top) & 7; | |
7220 | tag = regs[stnr].tag; /* derived from the loaded tag word */ | |
7221 | reg_move(&FPU_loaded_data, ®s[stnr]); | |
7222 | if (tag == TW_NaN) { | |
7223 | /* The current data is a special, i.e. NaN, | |
7224 | * unsupported, infinity, or denormal */ | |
7225 | unsigned char t = regs[stnr].tag; /* derived from the new | |
7226 | * data */ | |
7227 | if ( /* (t == TW_Valid) || *** */ (t == TW_Zero)) | |
7228 | regs[stnr].tag = TW_NaN; | |
7229 | } else | |
7230 | regs[stnr].tag = tag; | |
7231 | } | |
7232 | control_word = saved_control; | |
7233 | status_word = saved_status; | |
7234 | ||
7235 | FPU_data_address = (void *) data_operand_offset; /* We want no net effect */ | |
7236 | } | |
7237 | ||
7238 | ||
7239 | unsigned short | |
7240 | tag_word(void) | |
7241 | { | |
7242 | unsigned short word = 0; | |
7243 | unsigned char tag; | |
7244 | int i; | |
7245 | ||
7246 | for (i = 7; i >= 0; i--) { | |
7247 | switch (tag = regs[i].tag) { | |
7248 | #if 0 /* TW_Denormal is not used yet, and probably | |
7249 | * won't be */ | |
7250 | case TW_Denormal: | |
7251 | #endif | |
7252 | case TW_Valid: | |
7253 | if (regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias)) | |
7254 | tag = 2; | |
7255 | break; | |
7256 | case TW_Infinity: | |
7257 | case TW_NaN: | |
7258 | tag = 2; | |
7259 | break; | |
7260 | case TW_Empty: | |
7261 | tag = 3; | |
7262 | break; | |
7263 | /* TW_Valid and TW_Zero already have the correct value */ | |
7264 | } | |
7265 | word <<= 2; | |
7266 | word |= tag; | |
7267 | } | |
7268 | return word; | |
7269 | } | |
7270 | ||
7271 | ||
7272 | char * | |
7273 | fstenv(void) | |
7274 | { | |
7275 | char *d = (char *) FPU_data_address; | |
7276 | ||
7277 | /* verify_area(VERIFY_WRITE, d, 28);*/ | |
7278 | ||
7279 | #if 0 /****/ | |
7280 | *(unsigned short *) &cs_selector = fpu_cs; | |
7281 | *(unsigned short *) &operand_selector = fpu_os; | |
7282 | #endif /****/ | |
7283 | ||
7284 | REENTRANT_CHECK(OFF); | |
7285 | suword((unsigned short *) d, control_word); | |
7286 | suword((unsigned short *) (d + 4), (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift)); | |
7287 | suword((unsigned short *) (d + 8), tag_word()); | |
7288 | suword((unsigned long *) (d + 0x0c), ip_offset); | |
7289 | suword((unsigned long *) (d + 0x10), cs_selector); | |
7290 | suword((unsigned long *) (d + 0x14), data_operand_offset); | |
7291 | suword((unsigned long *) (d + 0x18), operand_selector); | |
7292 | REENTRANT_CHECK(ON); | |
7293 | ||
7294 | return d + 0x1c; | |
7295 | } | |
7296 | ||
7297 | ||
7298 | void | |
7299 | fsave(void) | |
7300 | { | |
7301 | char *d; | |
7302 | FPU_REG tmp, *rp; | |
7303 | int i; | |
7304 | short e; | |
7305 | ||
7306 | d = fstenv(); | |
7307 | /* verify_area(VERIFY_WRITE, d, 80);*/ | |
7308 | for (i = 0; i < 8; i++) { | |
7309 | /* Store each register in the order: st(0), st(1), ... */ | |
7310 | rp = ®s[(top + i) & 7]; | |
7311 | ||
7312 | e = rp->exp - EXP_BIAS + EXTENDED_Ebias; | |
7313 | ||
7314 | if (rp->tag == TW_Valid) { | |
7315 | if (e >= 0x7fff) { | |
7316 | /* Overflow to infinity */ | |
7317 | REENTRANT_CHECK(OFF); | |
7318 | suword((unsigned long *) (d + i * 10), 0); | |
7319 | suword((unsigned long *) (d + i * 10 + 4), 0); | |
7320 | REENTRANT_CHECK(ON); | |
7321 | e = 0x7fff; | |
7322 | } else | |
7323 | if (e <= 0) { | |
7324 | if (e > -63) { | |
7325 | /* Make a de-normal */ | |
7326 | reg_move(rp, &tmp); | |
7327 | tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */ | |
7328 | round_to_int(&tmp); | |
7329 | REENTRANT_CHECK(OFF); | |
7330 | suword((unsigned long *) (d + i * 10), tmp.sigl); | |
7331 | suword((unsigned long *) (d + i * 10 + 4), tmp.sigh); | |
7332 | REENTRANT_CHECK(ON); | |
7333 | } else { | |
7334 | /* Underflow to zero */ | |
7335 | REENTRANT_CHECK(OFF); | |
7336 | suword((unsigned long *) (d + i * 10), 0); | |
7337 | suword((unsigned long *) (d + i * 10 + 4), 0); | |
7338 | REENTRANT_CHECK(ON); | |
7339 | } | |
7340 | e = 0; | |
7341 | } else { | |
7342 | REENTRANT_CHECK(OFF); | |
7343 | suword((unsigned long *) (d + i * 10), rp->sigl); | |
7344 | suword((unsigned long *) (d + i * 10 + 4), rp->sigh); | |
7345 | REENTRANT_CHECK(ON); | |
7346 | } | |
7347 | } else | |
7348 | if (rp->tag == TW_Zero) { | |
7349 | REENTRANT_CHECK(OFF); | |
7350 | suword((unsigned long *) (d + i * 10), 0); | |
7351 | suword((unsigned long *) (d + i * 10 + 4), 0); | |
7352 | REENTRANT_CHECK(ON); | |
7353 | e = 0; | |
7354 | } else | |
7355 | if (rp->tag == TW_Infinity) { | |
7356 | REENTRANT_CHECK(OFF); | |
7357 | suword((unsigned long *) (d + i * 10), 0); | |
7358 | suword((unsigned long *) (d + i * 10 + 4), 0x80000000); | |
7359 | REENTRANT_CHECK(ON); | |
7360 | e = 0x7fff; | |
7361 | } else | |
7362 | if (rp->tag == TW_NaN) { | |
7363 | REENTRANT_CHECK(OFF); | |
7364 | suword((unsigned long *) (d + i * 10), rp->sigl); | |
7365 | suword((unsigned long *) (d + i * 10 + 4), rp->sigh); | |
7366 | REENTRANT_CHECK(ON); | |
7367 | e = 0x7fff; | |
7368 | } else | |
7369 | if (rp->tag == TW_Empty) { | |
7370 | /* just copy the reg */ | |
7371 | REENTRANT_CHECK(OFF); | |
7372 | suword((unsigned long *) (d + i * 10), rp->sigl); | |
7373 | suword((unsigned long *) (d + i * 10 + 4), rp->sigh); | |
7374 | REENTRANT_CHECK(ON); | |
7375 | } | |
7376 | e |= rp->sign == SIGN_POS ? 0 : 0x8000; | |
7377 | REENTRANT_CHECK(OFF); | |
7378 | suword((unsigned short *) (d + i * 10 + 8), e); | |
7379 | REENTRANT_CHECK(ON); | |
7380 | } | |
7381 | ||
7382 | finit(); | |
7383 | ||
7384 | } | |
7385 | /*===========================================================================*/ | |
7386 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_div.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 14734 5462505570 12412\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "reg_div.S" | |
7387 | /* | |
7388 | * reg_div.S | |
7389 | * | |
7390 | * Divide one FPU_REG by another and put the result in a destination FPU_REG. | |
7391 | * | |
7392 | * Call from C as: | |
7393 | * void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | |
7394 | * | |
7395 | * | |
7396 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
7397 | * Vic 3163, Australia. | |
7398 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
7399 | * All rights reserved. | |
7400 | * | |
7401 | * This copyright notice covers the redistribution and use of the | |
7402 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
7403 | * in the 386BSD operating system. Any other use is not permitted | |
7404 | * under this copyright. | |
7405 | * | |
7406 | * Redistribution and use in source and binary forms, with or without | |
7407 | * modification, are permitted provided that the following conditions | |
7408 | * are met: | |
7409 | * 1. Redistributions of source code must retain the above copyright | |
7410 | * notice, this list of conditions and the following disclaimer. | |
7411 | * 2. Redistributions in binary form must include information specifying | |
7412 | * that source code for the emulator is freely available and include | |
7413 | * either: | |
7414 | * a) an offer to provide the source code for a nominal distribution | |
7415 | * fee, or | |
7416 | * b) list at least two alternative methods whereby the source | |
7417 | * can be obtained, e.g. a publically accessible bulletin board | |
7418 | * and an anonymous ftp site from which the software can be | |
7419 | * downloaded. | |
7420 | * 3. All advertising materials specifically mentioning features or use of | |
7421 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
7422 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
7423 | * products derived from this software without specific prior written | |
7424 | * permission. | |
7425 | * | |
7426 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
7427 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
7428 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
7429 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
7430 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
7431 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
7432 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
7433 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
7434 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
7435 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
7436 | * unsigned int control_word) | |
7437 | */ | |
7438 | ||
7439 | #include "exception.h" | |
7440 | #include "fpu_asm.h" | |
7441 | #include "control_w.h" | |
7442 | ||
7443 | .text | |
7444 | .align 2 | |
7445 | ||
7446 | .globl _reg_div | |
7447 | _reg_div: | |
7448 | pushl %ebp | |
7449 | movl %esp,%ebp | |
7450 | ||
7451 | pushl %esi | |
7452 | pushl %edi | |
7453 | pushl %ebx | |
7454 | ||
7455 | movl PARAM1,%esi | |
7456 | movl PARAM2,%ebx | |
7457 | movl PARAM3,%edi | |
7458 | ||
7459 | movb TAG(%esi),%al | |
7460 | orb TAG(%ebx),%al | |
7461 | ||
7462 | jne L_div_special /* Not (both numbers TW_Valid) */ | |
7463 | ||
7464 | #ifdef DENORM_OPERAND | |
7465 | /* Check for denormals */ | |
7466 | cmpl EXP_UNDER,EXP(%esi) | |
7467 | jg xL_arg1_not_denormal | |
7468 | ||
7469 | call _denormal_operand | |
7470 | orl %eax,%eax | |
7471 | jnz FPU_Arith_exit | |
7472 | ||
7473 | xL_arg1_not_denormal: | |
7474 | cmpl EXP_UNDER,EXP(%ebx) | |
7475 | jg xL_arg2_not_denormal | |
7476 | ||
7477 | call _denormal_operand | |
7478 | orl %eax,%eax | |
7479 | jnz FPU_Arith_exit | |
7480 | ||
7481 | xL_arg2_not_denormal: | |
7482 | #endif DENORM_OPERAND | |
7483 | ||
7484 | /* Both arguments are TW_Valid */ | |
7485 | movb TW_Valid,TAG(%edi) | |
7486 | ||
7487 | movb SIGN(%esi),%cl | |
7488 | cmpb %cl,SIGN(%ebx) | |
7489 | setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */ | |
7490 | ||
7491 | movl EXP(%esi),%edx | |
7492 | movl EXP(%ebx),%eax | |
7493 | subl %eax,%edx | |
7494 | addl EXP_BIAS,%edx | |
7495 | movl %edx,EXP(%edi) | |
7496 | ||
7497 | jmp _divide_kernel | |
7498 | ||
7499 | ||
7500 | /*-----------------------------------------------------------------------*/ | |
7501 | L_div_special: | |
7502 | cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */ | |
7503 | je L_arg1_NaN | |
7504 | ||
7505 | cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */ | |
7506 | jne L_no_NaN_arg | |
7507 | ||
7508 | /* Operations on NaNs */ | |
7509 | L_arg1_NaN: | |
7510 | L_arg2_NaN: | |
7511 | pushl %edi /* Destination */ | |
7512 | pushl %ebx | |
7513 | pushl %esi | |
7514 | call _real_2op_NaN | |
7515 | jmp LDiv_exit | |
7516 | ||
7517 | /* Invalid operations */ | |
7518 | L_zero_zero: | |
7519 | L_inf_inf: | |
7520 | pushl %edi /* Destination */ | |
7521 | call _arith_invalid /* 0/0 or Infinity/Infinity */ | |
7522 | jmp LDiv_exit | |
7523 | ||
7524 | L_no_NaN_arg: | |
7525 | cmpb TW_Infinity,TAG(%esi) | |
7526 | jne L_arg1_not_inf | |
7527 | ||
7528 | cmpb TW_Infinity,TAG(%ebx) | |
7529 | je L_inf_inf /* invalid operation */ | |
7530 | ||
7531 | cmpb TW_Valid,TAG(%ebx) | |
7532 | je L_inf_valid | |
7533 | ||
7534 | #ifdef PARANOID | |
7535 | /* arg2 must be zero or valid */ | |
7536 | cmpb TW_Zero,TAG(%ebx) | |
7537 | ja L_unknown_tags | |
7538 | #endif PARANOID | |
7539 | ||
7540 | /* Note that p16-9 says that infinity/0 returns infinity */ | |
7541 | jmp L_copy_arg1 /* Answer is Inf */ | |
7542 | ||
7543 | L_inf_valid: | |
7544 | #ifdef DENORM_OPERAND | |
7545 | cmpl EXP_UNDER,EXP(%ebx) | |
7546 | jg L_copy_arg1 /* Answer is Inf */ | |
7547 | ||
7548 | call _denormal_operand | |
7549 | orl %eax,%eax | |
7550 | jnz FPU_Arith_exit | |
7551 | #endif DENORM_OPERAND | |
7552 | ||
7553 | jmp L_copy_arg1 /* Answer is Inf */ | |
7554 | ||
7555 | L_arg1_not_inf: | |
7556 | cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */ | |
7557 | jne L_arg2_not_zero | |
7558 | ||
7559 | cmpb TW_Zero,TAG(%esi) | |
7560 | je L_zero_zero /* invalid operation */ | |
7561 | ||
7562 | #ifdef PARANOID | |
7563 | /* arg1 must be valid */ | |
7564 | cmpb TW_Valid,TAG(%esi) | |
7565 | ja L_unknown_tags | |
7566 | #endif PARANOID | |
7567 | ||
7568 | /* Division by zero error */ | |
7569 | pushl %edi /* destination */ | |
7570 | movb SIGN(%esi),%al | |
7571 | xorb SIGN(%ebx),%al | |
7572 | pushl %eax /* lower 8 bits have the sign */ | |
7573 | call _divide_by_zero | |
7574 | jmp LDiv_exit | |
7575 | ||
7576 | L_arg2_not_zero: | |
7577 | cmpb TW_Infinity,TAG(%ebx) | |
7578 | jne L_arg2_not_inf | |
7579 | ||
7580 | #ifdef DENORM_OPERAND | |
7581 | cmpb TW_Valid,TAG(%esi) | |
7582 | jne L_return_zero | |
7583 | ||
7584 | cmpl EXP_UNDER,EXP(%esi) | |
7585 | jg L_return_zero /* Answer is zero */ | |
7586 | ||
7587 | call _denormal_operand | |
7588 | orl %eax,%eax | |
7589 | jnz FPU_Arith_exit | |
7590 | #endif DENORM_OPERAND | |
7591 | ||
7592 | jmp L_return_zero /* Answer is zero */ | |
7593 | ||
7594 | L_arg2_not_inf: | |
7595 | ||
7596 | #ifdef PARANOID | |
7597 | cmpb TW_Zero,TAG(%esi) | |
7598 | jne L_unknown_tags | |
7599 | #endif PARANOID | |
7600 | ||
7601 | /* arg1 is zero, arg2 is not Infinity or a NaN */ | |
7602 | ||
7603 | #ifdef DENORM_OPERAND | |
7604 | cmpl EXP_UNDER,EXP(%ebx) | |
7605 | jg L_copy_arg1 /* Answer is zero */ | |
7606 | ||
7607 | call _denormal_operand | |
7608 | orl %eax,%eax | |
7609 | jnz FPU_Arith_exit | |
7610 | #endif DENORM_OPERAND | |
7611 | ||
7612 | L_copy_arg1: | |
7613 | movb TAG(%esi),%ax | |
7614 | movb %ax,TAG(%edi) | |
7615 | movl EXP(%esi),%eax | |
7616 | movl %eax,EXP(%edi) | |
7617 | movl SIGL(%esi),%eax | |
7618 | movl %eax,SIGL(%edi) | |
7619 | movl SIGH(%esi),%eax | |
7620 | movl %eax,SIGH(%edi) | |
7621 | ||
7622 | movb SIGN(%esi),%cl | |
7623 | cmpb %cl,SIGN(%ebx) | |
7624 | jne LDiv_negative_result | |
7625 | ||
7626 | movb SIGN_POS,SIGN(%edi) | |
7627 | jmp LDiv_exit | |
7628 | ||
7629 | LDiv_set_result_sign: | |
7630 | movb SIGN(%esi),%cl | |
7631 | cmpb %cl,SIGN(%edi) | |
7632 | jne LDiv_negative_result | |
7633 | ||
7634 | movb SIGN_POS,SIGN(%ebx) | |
7635 | jmp LDiv_exit | |
7636 | ||
7637 | LDiv_negative_result: | |
7638 | movb SIGN_NEG,SIGN(%edi) | |
7639 | ||
7640 | LDiv_exit: | |
7641 | leal -12(%ebp),%esp | |
7642 | ||
7643 | popl %ebx | |
7644 | popl %edi | |
7645 | popl %esi | |
7646 | leave | |
7647 | ret | |
7648 | ||
7649 | ||
7650 | L_return_zero: | |
7651 | movb TW_Zero,TAG(%edi) | |
7652 | jmp LDiv_set_result_sign | |
7653 | ||
7654 | #ifdef PARANOID | |
7655 | L_unknown_tags: | |
7656 | push EX_INTERNAL | 0x208 | |
7657 | call EXCEPTION | |
7658 | ||
7659 | /* Generate a NaN for unknown tags */ | |
7660 | movl _CONST_QNaN,%eax | |
7661 | movl %eax,(%edi) | |
7662 | movl _CONST_QNaN+4,%eax | |
7663 | movl %eax,SIGL(%edi) | |
7664 | movl _CONST_QNaN+8,%eax | |
7665 | movl %eax,SIGH(%edi) | |
7666 | jmp LDiv_exit | |
7667 | #endif PARANOID | |
7668 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_mul.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 11742 5462320166 12422\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
7669 | * reg_mul.c | |
7670 | * | |
7671 | * Multiply one FPU_REG by another, put the result in a destination FPU_REG. | |
7672 | * | |
7673 | * | |
7674 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
7675 | * Vic 3163, Australia. | |
7676 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
7677 | * All rights reserved. | |
7678 | * | |
7679 | * This copyright notice covers the redistribution and use of the | |
7680 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
7681 | * in the 386BSD operating system. Any other use is not permitted | |
7682 | * under this copyright. | |
7683 | * | |
7684 | * Redistribution and use in source and binary forms, with or without | |
7685 | * modification, are permitted provided that the following conditions | |
7686 | * are met: | |
7687 | * 1. Redistributions of source code must retain the above copyright | |
7688 | * notice, this list of conditions and the following disclaimer. | |
7689 | * 2. Redistributions in binary form must include information specifying | |
7690 | * that source code for the emulator is freely available and include | |
7691 | * either: | |
7692 | * a) an offer to provide the source code for a nominal distribution | |
7693 | * fee, or | |
7694 | * b) list at least two alternative methods whereby the source | |
7695 | * can be obtained, e.g. a publically accessible bulletin board | |
7696 | * and an anonymous ftp site from which the software can be | |
7697 | * downloaded. | |
7698 | * 3. All advertising materials specifically mentioning features or use of | |
7699 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
7700 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
7701 | * products derived from this software without specific prior written | |
7702 | * permission. | |
7703 | * | |
7704 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
7705 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
7706 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
7707 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
7708 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
7709 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
7710 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
7711 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
7712 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
7713 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
7714 | * | |
7715 | */ | |
7716 | ||
7717 | /*---------------------------------------------------------------------------+ | |
7718 | | The destination may be any FPU_REG, including one of the source FPU_REGs. | | |
7719 | +---------------------------------------------------------------------------*/ | |
7720 | ||
7721 | #include "exception.h" | |
7722 | #include "reg_constant.h" | |
7723 | #include "fpu_emu.h" | |
7724 | #include "fpu_system.h" | |
7725 | ||
7726 | ||
7727 | /* This routine must be called with non-empty source registers */ | |
7728 | void | |
7729 | reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w) | |
7730 | { | |
7731 | char sign = (a->sign ^ b->sign); | |
7732 | ||
7733 | if (!(a->tag | b->tag)) { | |
7734 | /* This should be the most common case */ | |
7735 | reg_u_mul(a, b, dest, control_w); | |
7736 | dest->sign = sign; | |
7737 | return; | |
7738 | } else | |
7739 | if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero)) { | |
7740 | #ifdef DENORM_OPERAND | |
7741 | if (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) || | |
7742 | ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER))) { | |
7743 | if (denormal_operand()) | |
7744 | return; | |
7745 | } | |
7746 | #endif /* DENORM_OPERAND */ | |
7747 | /* Must have either both arguments == zero, or one | |
7748 | * valid and the other zero. The result is therefore | |
7749 | * zero. */ | |
7750 | reg_move(&CONST_Z, dest); | |
7751 | #ifdef PECULIAR_486 | |
7752 | /* The 80486 book says that the answer is +0, but a | |
7753 | * real 80486 appears to behave this way... */ | |
7754 | dest->sign = sign; | |
7755 | #endif /* PECULIAR_486 */ | |
7756 | return; | |
7757 | } | |
7758 | #if 0 /* TW_Denormal is not used yet... perhaps | |
7759 | * never will be. */ | |
7760 | else | |
7761 | if ((a->tag <= TW_Denormal) && (b->tag <= TW_Denormal)) { | |
7762 | /* One or both arguments are de-normalized */ | |
7763 | /* Internal de-normalized numbers are not | |
7764 | * supported yet */ | |
7765 | EXCEPTION(EX_INTERNAL | 0x105); | |
7766 | reg_move(&CONST_Z, dest); | |
7767 | } | |
7768 | #endif | |
7769 | else { | |
7770 | /* Must have infinities, NaNs, etc */ | |
7771 | if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) { | |
7772 | real_2op_NaN(a, b, dest); | |
7773 | return; | |
7774 | } else | |
7775 | if (a->tag == TW_Infinity) { | |
7776 | if (b->tag == TW_Zero) { | |
7777 | arith_invalid(dest); | |
7778 | return; | |
7779 | } | |
7780 | /* Zero*Infinity is invalid */ | |
7781 | else { | |
7782 | #ifdef DENORM_OPERAND | |
7783 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && | |
7784 | denormal_operand()) | |
7785 | return; | |
7786 | #endif /* DENORM_OPERAND */ | |
7787 | reg_move(a, dest); | |
7788 | dest->sign = sign; | |
7789 | } | |
7790 | return; | |
7791 | } else | |
7792 | if (b->tag == TW_Infinity) { | |
7793 | if (a->tag == TW_Zero) { | |
7794 | arith_invalid(dest); | |
7795 | return; | |
7796 | } | |
7797 | /* Zero*Infinity is | |
7798 | * invalid */ | |
7799 | else { | |
7800 | #ifdef DENORM_OPERAND | |
7801 | if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && | |
7802 | denormal_operand()) | |
7803 | return; | |
7804 | #endif /* DENORM_OPERAND */ | |
7805 | reg_move(b, dest); | |
7806 | dest->sign = sign; | |
7807 | } | |
7808 | return; | |
7809 | } | |
7810 | #ifdef PARANOID | |
7811 | else { | |
7812 | EXCEPTION(EX_INTERNAL | 0x102); | |
7813 | } | |
7814 | #endif /* PARANOID */ | |
7815 | } | |
7816 | } | |
7817 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_norm.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 10233 5462505570 12571\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
7818 | * reg_norm.s | |
7819 | * | |
7820 | * Normalize the value in a FPU_REG. | |
7821 | * | |
7822 | * Call from C as: | |
7823 | * void normalize(FPU_REG *n) | |
7824 | * | |
7825 | * void normalize_nuo(FPU_REG *n) | |
7826 | * | |
7827 | * | |
7828 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
7829 | * Vic 3163, Australia. | |
7830 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
7831 | * All rights reserved. | |
7832 | * | |
7833 | * This copyright notice covers the redistribution and use of the | |
7834 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
7835 | * in the 386BSD operating system. Any other use is not permitted | |
7836 | * under this copyright. | |
7837 | * | |
7838 | * Redistribution and use in source and binary forms, with or without | |
7839 | * modification, are permitted provided that the following conditions | |
7840 | * are met: | |
7841 | * 1. Redistributions of source code must retain the above copyright | |
7842 | * notice, this list of conditions and the following disclaimer. | |
7843 | * 2. Redistributions in binary form must include information specifying | |
7844 | * that source code for the emulator is freely available and include | |
7845 | * either: | |
7846 | * a) an offer to provide the source code for a nominal distribution | |
7847 | * fee, or | |
7848 | * b) list at least two alternative methods whereby the source | |
7849 | * can be obtained, e.g. a publically accessible bulletin board | |
7850 | * and an anonymous ftp site from which the software can be | |
7851 | * downloaded. | |
7852 | * 3. All advertising materials specifically mentioning features or use of | |
7853 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
7854 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
7855 | * products derived from this software without specific prior written | |
7856 | * permission. | |
7857 | * | |
7858 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
7859 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
7860 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
7861 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
7862 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
7863 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
7864 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
7865 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
7866 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
7867 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
7868 | * | |
7869 | */ | |
7870 | ||
7871 | ||
7872 | #include "fpu_asm.h" | |
7873 | ||
7874 | ||
7875 | .text | |
7876 | ||
7877 | .align 2,144 | |
7878 | .globl _normalize | |
7879 | ||
7880 | _normalize: | |
7881 | pushl %ebp | |
7882 | movl %esp,%ebp | |
7883 | pushl %ebx | |
7884 | ||
7885 | movl PARAM1,%ebx | |
7886 | ||
7887 | movl SIGH(%ebx),%edx | |
7888 | movl SIGL(%ebx),%eax | |
7889 | ||
7890 | orl %edx,%edx /* ms bits */ | |
7891 | js L_done /* Already normalized */ | |
7892 | jnz L_shift_1 /* Shift left 1 - 31 bits */ | |
7893 | ||
7894 | orl %eax,%eax | |
7895 | jz L_zero /* The contents are zero */ | |
7896 | ||
7897 | /* L_shift_32: */ | |
7898 | movl %eax,%edx | |
7899 | xorl %eax,%eax | |
7900 | subl $32,EXP(%ebx) /* This can cause an underflow */ | |
7901 | ||
7902 | /* We need to shift left by 1 - 31 bits */ | |
7903 | L_shift_1: | |
7904 | bsrl %edx,%ecx /* get the required shift in %ecx */ | |
7905 | subl $31,%ecx | |
7906 | negl %ecx | |
7907 | shld %cl,%eax,%edx | |
7908 | shl %cl,%eax | |
7909 | subl %ecx,EXP(%ebx) /* This can cause an underflow */ | |
7910 | ||
7911 | movl %edx,SIGH(%ebx) | |
7912 | movl %eax,SIGL(%ebx) | |
7913 | ||
7914 | L_done: | |
7915 | cmpl EXP_OVER,EXP(%ebx) | |
7916 | jge L_overflow | |
7917 | ||
7918 | cmpl EXP_UNDER,EXP(%ebx) | |
7919 | jle L_underflow | |
7920 | ||
7921 | L_exit: | |
7922 | popl %ebx | |
7923 | leave | |
7924 | ret | |
7925 | ||
7926 | ||
7927 | L_zero: | |
7928 | movl EXP_UNDER,EXP(%ebx) | |
7929 | movb TW_Zero,TAG(%ebx) | |
7930 | jmp L_exit | |
7931 | ||
7932 | L_underflow: | |
7933 | push %ebx | |
7934 | call _arith_underflow | |
7935 | pop %ebx | |
7936 | jmp L_exit | |
7937 | ||
7938 | L_overflow: | |
7939 | push %ebx | |
7940 | call _arith_overflow | |
7941 | pop %ebx | |
7942 | jmp L_exit | |
7943 | ||
7944 | ||
7945 | ||
7946 | /* Normalise without reporting underflow or overflow */ | |
7947 | .align 2,144 | |
7948 | .globl _normalize_nuo | |
7949 | ||
7950 | _normalize_nuo: | |
7951 | pushl %ebp | |
7952 | movl %esp,%ebp | |
7953 | pushl %ebx | |
7954 | ||
7955 | movl PARAM1,%ebx | |
7956 | ||
7957 | movl SIGH(%ebx),%edx | |
7958 | movl SIGL(%ebx),%eax | |
7959 | ||
7960 | orl %edx,%edx /* ms bits */ | |
7961 | js L_exit /* Already normalized */ | |
7962 | jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */ | |
7963 | ||
7964 | orl %eax,%eax | |
7965 | jz L_zero /* The contents are zero */ | |
7966 | ||
7967 | /* L_nuo_shift_32: */ | |
7968 | movl %eax,%edx | |
7969 | xorl %eax,%eax | |
7970 | subl $32,EXP(%ebx) /* This can cause an underflow */ | |
7971 | ||
7972 | /* We need to shift left by 1 - 31 bits */ | |
7973 | L_nuo_shift_1: | |
7974 | bsrl %edx,%ecx /* get the required shift in %ecx */ | |
7975 | subl $31,%ecx | |
7976 | negl %ecx | |
7977 | shld %cl,%eax,%edx | |
7978 | shl %cl,%eax | |
7979 | subl %ecx,EXP(%ebx) /* This can cause an underflow */ | |
7980 | ||
7981 | movl %edx,SIGH(%ebx) | |
7982 | movl %eax,SIGL(%ebx) | |
7983 | jmp L_exit | |
7984 | ||
7985 | ||
7986 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/bde_trapinfo.mail\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100600 \0 0 \0 24 \0 2454 5462277677 14116\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0From bde@kralizec.zeta.org.au Sun Jun 27 01:18:32 1993 | |
7987 | Received: from ultima.socs.uts.EDU.AU by bsd.coe.montana.edu (5.67/KAOS-1) | |
7988 | id AA11952; Sun, 27 Jun 93 01:18:32 -0600 | |
7989 | Received: by ultima.socs.uts.EDU.AU (5.65+/SMI-3.3) | |
7990 | id AA03033; Sun, 27 Jun 93 17:10:22 +1000 | |
7991 | Received: by kralizec.zeta.org.au (4.0/SMI-4.0) | |
7992 | id AA15074; Sat, 26 Jun 93 02:32:58 EST | |
7993 | Date: Sat, 26 Jun 93 02:32:58 EST | |
7994 | From: bde@kralizec.zeta.org.au (Bruce Evans) | |
7995 | Message-Id: <9306251632.AA15074@kralizec.zeta.org.au> | |
7996 | To: nate@bsd.coe.montana.edu | |
7997 | Subject: Re: Trapframe information | |
7998 | Status: OR | |
7999 | ||
8000 | tf_isp original esp (probably spare - popal ignores it) | |
8001 | tf_trapno s/w trap no (may be spare - trap.c has already looked at it) | |
8002 | tf_err h/w error code (probably spare - gets discarded before iret) | |
8003 | ||
8004 | ___fs not stored in 386BSD pcb. Constant anyway unless user has | |
8005 | screwed with it (?). | |
8006 | ___gs ditto | |
8007 | ___orig_eip in linux, this is on the stack just before the call to the | |
8008 | emulator. The reason that it's not a local variable is to | |
8009 | avoid passing around pointers to it - current->frame (or | |
8010 | whatever) points to everything in the stack frame. The | |
8011 | macros hide a lot of slow memory references | |
8012 | current->frame->var. | |
8013 | ||
8014 | >(And I need to see if I can map orig_eip to one of the three that I'm unsure of | |
8015 | >in the BSD sources) | |
8016 | ||
8017 | tf_isp is the least evil. | |
8018 | ||
8019 | Bruce | |
8020 | ||
8021 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/fpu_proto.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 6610 5462320157 12770\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* errors.c */ | |
8022 | extern void Un_impl(void); | |
8023 | extern void emu_printall(void); | |
8024 | extern void exception(int n); | |
8025 | extern void real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest); | |
8026 | extern void arith_invalid(FPU_REG * dest); | |
8027 | extern void divide_by_zero(int sign, FPU_REG * dest); | |
8028 | extern void set_precision_flag_up(void); | |
8029 | extern void set_precision_flag_down(void); | |
8030 | extern int denormal_operand(void); | |
8031 | extern void arith_overflow(FPU_REG * dest); | |
8032 | extern void arith_underflow(FPU_REG * dest); | |
8033 | extern void stack_overflow(void); | |
8034 | extern void stack_underflow(void); | |
8035 | extern void stack_underflow_i(int i); | |
8036 | extern void stack_underflow_pop(int i); | |
8037 | /* fpu_arith.c */ | |
8038 | extern void fadd__(void); | |
8039 | extern void fmul__(void); | |
8040 | extern void fsub__(void); | |
8041 | extern void fsubr_(void); | |
8042 | extern void fdiv__(void); | |
8043 | extern void fdivr_(void); | |
8044 | extern void fadd_i(void); | |
8045 | extern void fmul_i(void); | |
8046 | extern void fsubri(void); | |
8047 | extern void fsub_i(void); | |
8048 | extern void fdivri(void); | |
8049 | extern void fdiv_i(void); | |
8050 | extern void faddp_(void); | |
8051 | extern void fmulp_(void); | |
8052 | extern void fsubrp(void); | |
8053 | extern void fsubp_(void); | |
8054 | extern void fdivrp(void); | |
8055 | extern void fdivp_(void); | |
8056 | /* fpu_aux.c */ | |
8057 | extern void fclex(void); | |
8058 | extern void finit(void); | |
8059 | extern void finit_(void); | |
8060 | extern void fstsw_(void); | |
8061 | extern void fp_nop(void); | |
8062 | extern void fld_i_(void); | |
8063 | extern void fxch_i(void); | |
8064 | extern void ffree_(void); | |
8065 | extern void ffreep(void); | |
8066 | extern void fst_i_(void); | |
8067 | extern void fstp_i(void); | |
8068 | /* fpu_entry.c */ | |
8069 | extern int math_emulate(struct trapframe * info); | |
8070 | /* fpu_etc.c */ | |
8071 | extern void fp_etc(void); | |
8072 | /* fpu_trig.c */ | |
8073 | extern void convert_l2reg(long *arg, FPU_REG * dest); | |
8074 | extern void trig_a(void); | |
8075 | extern void trig_b(void); | |
8076 | /* get_address.c */ | |
8077 | extern void get_address(unsigned char FPU_modrm); | |
8078 | /* load_store.c */ | |
8079 | extern void load_store_instr(char type); | |
8080 | /* poly_2xm1.c */ | |
8081 | extern int poly_2xm1(FPU_REG * arg, FPU_REG * result); | |
8082 | /* poly_atan.c */ | |
8083 | extern void poly_atan(FPU_REG * arg); | |
8084 | extern void poly_add_1(FPU_REG * src); | |
8085 | /* poly_l2.c */ | |
8086 | extern void poly_l2(FPU_REG * arg, FPU_REG * result); | |
8087 | extern int poly_l2p1(FPU_REG * arg, FPU_REG * result); | |
8088 | /* poly_sin.c */ | |
8089 | extern void poly_sine(FPU_REG * arg, FPU_REG * result); | |
8090 | /* poly_tan.c */ | |
8091 | extern void poly_tan(FPU_REG * arg, FPU_REG * y_reg); | |
8092 | /* reg_add_sub.c */ | |
8093 | extern void reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w); | |
8094 | extern void reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w); | |
8095 | /* reg_compare.c */ | |
8096 | extern int compare(FPU_REG * b); | |
8097 | extern int compare_st_data(void); | |
8098 | extern void fcom_st(void); | |
8099 | extern void fcompst(void); | |
8100 | extern void fcompp(void); | |
8101 | extern void fucom_(void); | |
8102 | extern void fucomp(void); | |
8103 | extern void fucompp(void); | |
8104 | /* reg_constant.c */ | |
8105 | extern void fconst(void); | |
8106 | /* reg_ld_str.c */ | |
8107 | extern void reg_load_extended(void); | |
8108 | extern void reg_load_double(void); | |
8109 | extern void reg_load_single(void); | |
8110 | extern void reg_load_int64(void); | |
8111 | extern void reg_load_int32(void); | |
8112 | extern void reg_load_int16(void); | |
8113 | extern void reg_load_bcd(void); | |
8114 | extern int reg_store_extended(void); | |
8115 | extern int reg_store_double(void); | |
8116 | extern int reg_store_single(void); | |
8117 | extern int reg_store_int64(void); | |
8118 | extern int reg_store_int32(void); | |
8119 | extern int reg_store_int16(void); | |
8120 | extern int reg_store_bcd(void); | |
8121 | extern int round_to_int(FPU_REG * r); | |
8122 | extern char *fldenv(void); | |
8123 | extern void frstor(void); | |
8124 | extern unsigned short tag_word(void); | |
8125 | extern char *fstenv(void); | |
8126 | extern void fsave(void); | |
8127 | /* reg_mul.c */ | |
8128 | extern void reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w); | |
8129 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_mul64.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 6170 5462505570 12760\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
8130 | * poly_mul64.S | |
8131 | * | |
8132 | * Multiply two 64 bit integers. | |
8133 | * | |
8134 | * Call from C as: | |
8135 | * void mul64(long long *a, long long *b, long long *result) | |
8136 | * | |
8137 | * | |
8138 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
8139 | * Vic 3163, Australia. | |
8140 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
8141 | * All rights reserved. | |
8142 | * | |
8143 | * This copyright notice covers the redistribution and use of the | |
8144 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
8145 | * in the 386BSD operating system. Any other use is not permitted | |
8146 | * under this copyright. | |
8147 | * | |
8148 | * Redistribution and use in source and binary forms, with or without | |
8149 | * modification, are permitted provided that the following conditions | |
8150 | * are met: | |
8151 | * 1. Redistributions of source code must retain the above copyright | |
8152 | * notice, this list of conditions and the following disclaimer. | |
8153 | * 2. Redistributions in binary form must include information specifying | |
8154 | * that source code for the emulator is freely available and include | |
8155 | * either: | |
8156 | * a) an offer to provide the source code for a nominal distribution | |
8157 | * fee, or | |
8158 | * b) list at least two alternative methods whereby the source | |
8159 | * can be obtained, e.g. a publically accessible bulletin board | |
8160 | * and an anonymous ftp site from which the software can be | |
8161 | * downloaded. | |
8162 | * 3. All advertising materials specifically mentioning features or use of | |
8163 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
8164 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
8165 | * products derived from this software without specific prior written | |
8166 | * permission. | |
8167 | * | |
8168 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
8169 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
8170 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
8171 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
8172 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
8173 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
8174 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
8175 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
8176 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
8177 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
8178 | * | |
8179 | */ | |
8180 | ||
8181 | ||
8182 | #include "fpu_asm.h" | |
8183 | ||
8184 | .text | |
8185 | .align 2,144 | |
8186 | .globl _mul64 | |
8187 | _mul64: | |
8188 | pushl %ebp | |
8189 | movl %esp,%ebp | |
8190 | subl $16,%esp | |
8191 | pushl %esi | |
8192 | pushl %ebx | |
8193 | ||
8194 | movl PARAM1,%esi | |
8195 | movl PARAM2,%ecx | |
8196 | movl PARAM3,%ebx | |
8197 | ||
8198 | xor %eax,%eax | |
8199 | movl %eax,-4(%ebp) | |
8200 | movl %eax,-8(%ebp) | |
8201 | ||
8202 | movl (%esi),%eax | |
8203 | mull (%ecx) | |
8204 | movl %eax,-16(%ebp) /* Not used */ | |
8205 | movl %edx,-12(%ebp) | |
8206 | ||
8207 | movl (%esi),%eax | |
8208 | mull 4(%ecx) | |
8209 | addl %eax,-12(%ebp) | |
8210 | adcl %edx,-8(%ebp) | |
8211 | adcl $0,-4(%ebp) | |
8212 | ||
8213 | movl 4(%esi),%eax | |
8214 | mull (%ecx) | |
8215 | addl %eax,-12(%ebp) | |
8216 | adcl %edx,-8(%ebp) | |
8217 | adcl $0,-4(%ebp) | |
8218 | ||
8219 | movl 4(%esi),%eax | |
8220 | mull 4(%ecx) | |
8221 | addl %eax,-8(%ebp) | |
8222 | adcl %edx,-4(%ebp) | |
8223 | ||
8224 | testb $128,-9(%ebp) | |
8225 | je L_no_round | |
8226 | ||
8227 | addl $1,-8(%ebp) | |
8228 | adcl $0,-4(%ebp) | |
8229 | ||
8230 | L_no_round: | |
8231 | movl -8(%ebp),%esi | |
8232 | movl %esi,(%ebx) | |
8233 | movl -4(%ebp),%esi | |
8234 | movl %esi,4(%ebx) | |
8235 | ||
8236 | popl %ebx | |
8237 | popl %esi | |
8238 | leave | |
8239 | ret | |
8240 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/status_w.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 7206 5462320166 12601\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
8241 | * status_w.h | |
8242 | * | |
8243 | * | |
8244 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
8245 | * Vic 3163, Australia. | |
8246 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
8247 | * All rights reserved. | |
8248 | * | |
8249 | * This copyright notice covers the redistribution and use of the | |
8250 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
8251 | * in the 386BSD operating system. Any other use is not permitted | |
8252 | * under this copyright. | |
8253 | * | |
8254 | * Redistribution and use in source and binary forms, with or without | |
8255 | * modification, are permitted provided that the following conditions | |
8256 | * are met: | |
8257 | * 1. Redistributions of source code must retain the above copyright | |
8258 | * notice, this list of conditions and the following disclaimer. | |
8259 | * 2. Redistributions in binary form must include information specifying | |
8260 | * that source code for the emulator is freely available and include | |
8261 | * either: | |
8262 | * a) an offer to provide the source code for a nominal distribution | |
8263 | * fee, or | |
8264 | * b) list at least two alternative methods whereby the source | |
8265 | * can be obtained, e.g. a publically accessible bulletin board | |
8266 | * and an anonymous ftp site from which the software can be | |
8267 | * downloaded. | |
8268 | * 3. All advertising materials specifically mentioning features or use of | |
8269 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
8270 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
8271 | * products derived from this software without specific prior written | |
8272 | * permission. | |
8273 | * | |
8274 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
8275 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
8276 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
8277 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
8278 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
8279 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
8280 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
8281 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
8282 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
8283 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
8284 | * | |
8285 | */ | |
8286 | ||
8287 | ||
8288 | #ifndef _STATUS_H_ | |
8289 | #define _STATUS_H_ | |
8290 | ||
8291 | ||
8292 | #ifdef LOCORE | |
8293 | #define Const__(x) $/**/x | |
8294 | #else | |
8295 | #define Const__(x) x | |
8296 | #endif | |
8297 | ||
8298 | #define SW_Backward Const__(0x8000) /* backward compatibility */ | |
8299 | #define SW_C3 Const__(0x4000) /* condition bit 3 */ | |
8300 | #define SW_Top Const__(0x3800) /* top of stack */ | |
8301 | #define SW_Top_Shift Const__(11) /* shift for top of stack bits */ | |
8302 | #define SW_C2 Const__(0x0400) /* condition bit 2 */ | |
8303 | #define SW_C1 Const__(0x0200) /* condition bit 1 */ | |
8304 | #define SW_C0 Const__(0x0100) /* condition bit 0 */ | |
8305 | #define SW_Summary Const__(0x0080) /* exception summary */ | |
8306 | #define SW_Stack_Fault Const__(0x0040) /* stack fault */ | |
8307 | #define SW_Precision Const__(0x0020) /* loss of precision */ | |
8308 | #define SW_Underflow Const__(0x0010) /* underflow */ | |
8309 | #define SW_Overflow Const__(0x0008) /* overflow */ | |
8310 | #define SW_Zero_Div Const__(0x0004) /* divide by zero */ | |
8311 | #define SW_Denorm_Op Const__(0x0002) /* denormalized operand */ | |
8312 | #define SW_Invalid Const__(0x0001) /* invalid operation */ | |
8313 | ||
8314 | #define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */ | |
8315 | ||
8316 | #ifndef LOCORE | |
8317 | ||
8318 | #define COMP_A_gt_B 1 | |
8319 | #define COMP_A_eq_B 2 | |
8320 | #define COMP_A_lt_B 3 | |
8321 | #define COMP_No_Comp 4 | |
8322 | #define COMP_Denormal 0x20 | |
8323 | #define COMP_NaN 0x40 | |
8324 | #define COMP_SNaN 0x80 | |
8325 | ||
8326 | #define setcc(cc) ({ \ | |
8327 | status_word &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \ | |
8328 | status_word |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); }) | |
8329 | ||
8330 | #endif /* LOCORE */ | |
8331 | ||
8332 | #endif /* _STATUS_H_ */ | |
8333 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/version.h\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 4431 5462320167 12440\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
8334 | * version.h | |
8335 | * | |
8336 | * | |
8337 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
8338 | * Vic 3163, Australia. | |
8339 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
8340 | * All rights reserved. | |
8341 | * | |
8342 | * This copyright notice covers the redistribution and use of the | |
8343 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
8344 | * in the 386BSD operating system. Any other use is not permitted | |
8345 | * under this copyright. | |
8346 | * | |
8347 | * Redistribution and use in source and binary forms, with or without | |
8348 | * modification, are permitted provided that the following conditions | |
8349 | * are met: | |
8350 | * 1. Redistributions of source code must retain the above copyright | |
8351 | * notice, this list of conditions and the following disclaimer. | |
8352 | * 2. Redistributions in binary form must include information specifying | |
8353 | * that source code for the emulator is freely available and include | |
8354 | * either: | |
8355 | * a) an offer to provide the source code for a nominal distribution | |
8356 | * fee, or | |
8357 | * b) list at least two alternative methods whereby the source | |
8358 | * can be obtained, e.g. a publically accessible bulletin board | |
8359 | * and an anonymous ftp site from which the software can be | |
8360 | * downloaded. | |
8361 | * 3. All advertising materials specifically mentioning features or use of | |
8362 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
8363 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
8364 | * products derived from this software without specific prior written | |
8365 | * permission. | |
8366 | * | |
8367 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
8368 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
8369 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
8370 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
8371 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
8372 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
8373 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
8374 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
8375 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
8376 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
8377 | * | |
8378 | */ | |
8379 | ||
8380 | #define FPU_VERSION "wm-FPU-emu version BETA 1.4" | |
8381 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_round.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 40214 5462505570 12747\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "reg_round.S" | |
8382 | /* | |
8383 | * reg_round.S | |
8384 | * | |
8385 | * Rounding/truncation/etc for FPU basic arithmetic functions. | |
8386 | * | |
8387 | * This code has four possible entry points. | |
8388 | * The following must be entered by a jmp intruction: | |
8389 | * FPU_round, FPU_round_sqrt, and FPU_Arith_exit. | |
8390 | * | |
8391 | * The _round_reg entry point is intended to be used by C code. | |
8392 | * From C, call as: | |
8393 | * void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) | |
8394 | * | |
8395 | * | |
8396 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
8397 | * Vic 3163, Australia. | |
8398 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
8399 | * All rights reserved. | |
8400 | * | |
8401 | * This copyright notice covers the redistribution and use of the | |
8402 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
8403 | * in the 386BSD operating system. Any other use is not permitted | |
8404 | * under this copyright. | |
8405 | * | |
8406 | * Redistribution and use in source and binary forms, with or without | |
8407 | * modification, are permitted provided that the following conditions | |
8408 | * are met: | |
8409 | * 1. Redistributions of source code must retain the above copyright | |
8410 | * notice, this list of conditions and the following disclaimer. | |
8411 | * 2. Redistributions in binary form must include information specifying | |
8412 | * that source code for the emulator is freely available and include | |
8413 | * either: | |
8414 | * a) an offer to provide the source code for a nominal distribution | |
8415 | * fee, or | |
8416 | * b) list at least two alternative methods whereby the source | |
8417 | * can be obtained, e.g. a publically accessible bulletin board | |
8418 | * and an anonymous ftp site from which the software can be | |
8419 | * downloaded. | |
8420 | * 3. All advertising materials specifically mentioning features or use of | |
8421 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
8422 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
8423 | * products derived from this software without specific prior written | |
8424 | * permission. | |
8425 | * | |
8426 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
8427 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
8428 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
8429 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
8430 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
8431 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
8432 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
8433 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
8434 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
8435 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
8436 | * | |
8437 | */ | |
8438 | ||
8439 | ||
8440 | /*---------------------------------------------------------------------------+ | |
8441 | | Four entry points. | | |
8442 | | | | |
8443 | | Needed by both the FPU_round and FPU_round_sqrt entry points: | | |
8444 | | %eax:%ebx 64 bit significand | | |
8445 | | %edx 32 bit extension of the significand | | |
8446 | | %edi pointer to an FPU_REG for the result to be stored | | |
8447 | | stack calling function must have set up a C stack frame and | | |
8448 | | pushed %esi, %edi, and %ebx | | |
8449 | | | | |
8450 | | Needed just for the FPU_round_sqrt entry point: | | |
8451 | | %cx A control word in the same format as the FPU control word. | | |
8452 | | Otherwise, PARAM4 must give such a value. | | |
8453 | | | | |
8454 | | | | |
8455 | | The significand and its extension are assumed to be exact in the | | |
8456 | | following sense: | | |
8457 | | If the significand by itself is the exact result then the significand | | |
8458 | | extension (%edx) must contain 0, otherwise the significand extension | | |
8459 | | must be non-zero. | | |
8460 | | If the significand extension is non-zero then the significand is | | |
8461 | | smaller than the magnitude of the correct exact result by an amount | | |
8462 | | greater than zero and less than one ls bit of the significand. | | |
8463 | | The significand extension is only required to have three possible | | |
8464 | | non-zero values: | | |
8465 | | less than 0x80000000 <=> the significand is less than 1/2 an ls | | |
8466 | | bit smaller than the magnitude of the | | |
8467 | | true exact result. | | |
8468 | | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit | | |
8469 | | smaller than the magnitude of the true | | |
8470 | | exact result. | | |
8471 | | greater than 0x80000000 <=> the significand is more than 1/2 an ls | | |
8472 | | bit smaller than the magnitude of the | | |
8473 | | true exact result. | | |
8474 | | | | |
8475 | +---------------------------------------------------------------------------*/ | |
8476 | ||
8477 | /*---------------------------------------------------------------------------+ | |
8478 | | The code in this module has become quite complex, but it should handle | | |
8479 | | all of the FPU flags which are set at this stage of the basic arithmetic | | |
8480 | | computations. | | |
8481 | | There are a few rare cases where the results are not set identically to | | |
8482 | | a real FPU. These require a bit more thought because at this stage the | | |
8483 | | results of the code here appear to be more consistent... | | |
8484 | | This may be changed in a future version. | | |
8485 | +---------------------------------------------------------------------------*/ | |
8486 | ||
8487 | ||
8488 | #include "fpu_asm.h" | |
8489 | #include "exception.h" | |
8490 | #include "control_w.h" | |
8491 | ||
8492 | #define LOST_DOWN $1 | |
8493 | #define LOST_UP $2 | |
8494 | #define DENORMAL $1 | |
8495 | #define UNMASKED_UNDERFLOW $2 | |
8496 | ||
8497 | .data | |
8498 | .align 2,0 | |
8499 | FPU_bits_lost: | |
8500 | .byte 0 | |
8501 | FPU_denormal: | |
8502 | .byte 0 | |
8503 | ||
8504 | .text | |
8505 | .align 2,144 | |
8506 | .globl FPU_round | |
8507 | .globl FPU_round_sqrt | |
8508 | .globl FPU_Arith_exit | |
8509 | .globl _round_reg | |
8510 | ||
8511 | /* Entry point when called from C */ | |
8512 | _round_reg: | |
8513 | pushl %ebp | |
8514 | movl %esp,%ebp | |
8515 | pushl %esi | |
8516 | pushl %edi | |
8517 | pushl %ebx | |
8518 | ||
8519 | movl PARAM1,%edi | |
8520 | movl SIGH(%edi),%eax | |
8521 | movl SIGL(%edi),%ebx | |
8522 | movl PARAM2,%edx | |
8523 | movl PARAM3,%ecx | |
8524 | jmp FPU_round_sqrt | |
8525 | ||
8526 | FPU_round: /* Normal entry point */ | |
8527 | movl PARAM4,%ecx | |
8528 | ||
8529 | FPU_round_sqrt: /* Entry point from wm_sqrt.S */ | |
8530 | ||
8531 | #ifdef PARANOID | |
8532 | /* Cannot use this here yet */ | |
8533 | /* orl %eax,%eax */ | |
8534 | /* jns L_entry_bugged */ | |
8535 | #endif PARANOID | |
8536 | ||
8537 | cmpl EXP_UNDER,EXP(%edi) | |
8538 | jle xMake_denorm /* The number is a de-normal*/ | |
8539 | ||
8540 | movb $0,FPU_denormal /* 0 -> not a de-normal*/ | |
8541 | ||
8542 | xDenorm_done: | |
8543 | movb $0,FPU_bits_lost /*No bits yet lost in rounding*/ | |
8544 | ||
8545 | movl %ecx,%esi | |
8546 | andl CW_PC,%ecx | |
8547 | cmpl PR_64_BITS,%ecx | |
8548 | je LRound_To_64 | |
8549 | ||
8550 | cmpl PR_53_BITS,%ecx | |
8551 | je LRound_To_53 | |
8552 | ||
8553 | cmpl PR_24_BITS,%ecx | |
8554 | je LRound_To_24 | |
8555 | ||
8556 | #ifdef PARANOID | |
8557 | jmp L_bugged /* There is no bug, just a bad control word */ | |
8558 | #endif PARANOID | |
8559 | ||
8560 | ||
8561 | /* Round etc to 24 bit precision */ | |
8562 | LRound_To_24: | |
8563 | movl %esi,%ecx | |
8564 | andl CW_RC,%ecx | |
8565 | cmpl RC_RND,%ecx | |
8566 | je LRound_nearest_24 | |
8567 | ||
8568 | cmpl RC_CHOP,%ecx | |
8569 | je LCheck_truncate_24 | |
8570 | ||
8571 | cmpl RC_UP,%ecx /* Towards +infinity */ | |
8572 | je LUp_24 | |
8573 | ||
8574 | cmpl RC_DOWN,%ecx /* Towards -infinity */ | |
8575 | je LDown_24 | |
8576 | ||
8577 | #ifdef PARANOID | |
8578 | jmp L_bugged | |
8579 | #endif PARANOID | |
8580 | ||
8581 | LUp_24: | |
8582 | cmpb SIGN_POS,SIGN(%edi) | |
8583 | jne LCheck_truncate_24 /* If negative then up==truncate */ | |
8584 | ||
8585 | jmp LCheck_24_round_up | |
8586 | ||
8587 | LDown_24: | |
8588 | cmpb SIGN_POS,SIGN(%edi) | |
8589 | je LCheck_truncate_24 /* If positive then down==truncate */ | |
8590 | ||
8591 | LCheck_24_round_up: | |
8592 | movl %eax,%ecx | |
8593 | andl $0x000000ff,%ecx | |
8594 | orl %ebx,%ecx | |
8595 | orl %edx,%ecx | |
8596 | jnz LDo_24_round_up | |
8597 | jmp LRe_normalise | |
8598 | ||
8599 | LRound_nearest_24: | |
8600 | /* Do rounding of the 24th bit if needed (nearest or even) */ | |
8601 | movl %eax,%ecx | |
8602 | andl $0x000000ff,%ecx | |
8603 | cmpl $0x00000080,%ecx | |
8604 | jc LCheck_truncate_24 /*less than half, no increment needed*/ | |
8605 | ||
8606 | jne LGreater_Half_24 /* greater than half, increment needed*/ | |
8607 | ||
8608 | /* Possibly half, we need to check the ls bits */ | |
8609 | orl %ebx,%ebx | |
8610 | jnz LGreater_Half_24 /* greater than half, increment needed*/ | |
8611 | ||
8612 | orl %edx,%edx | |
8613 | jnz LGreater_Half_24 /* greater than half, increment needed*/ | |
8614 | ||
8615 | /* Exactly half, increment only if 24th bit is 1 (round to even)*/ | |
8616 | testl $0x00000100,%eax | |
8617 | jz LDo_truncate_24 | |
8618 | ||
8619 | LGreater_Half_24: /*Rounding: increment at the 24th bit*/ | |
8620 | LDo_24_round_up: | |
8621 | andl $0xffffff00,%eax /*Truncate to 24 bits*/ | |
8622 | xorl %ebx,%ebx | |
8623 | movb LOST_UP,FPU_bits_lost | |
8624 | addl $0x00000100,%eax | |
8625 | jmp LCheck_Round_Overflow | |
8626 | ||
8627 | LCheck_truncate_24: | |
8628 | movl %eax,%ecx | |
8629 | andl $0x000000ff,%ecx | |
8630 | orl %ebx,%ecx | |
8631 | orl %edx,%ecx | |
8632 | jz LRe_normalise /* No truncation needed*/ | |
8633 | ||
8634 | LDo_truncate_24: | |
8635 | andl $0xffffff00,%eax /* Truncate to 24 bits*/ | |
8636 | xorl %ebx,%ebx | |
8637 | movb LOST_DOWN,FPU_bits_lost | |
8638 | jmp LRe_normalise | |
8639 | ||
8640 | ||
8641 | /* Round etc to 53 bit precision */ | |
8642 | LRound_To_53: | |
8643 | movl %esi,%ecx | |
8644 | andl CW_RC,%ecx | |
8645 | cmpl RC_RND,%ecx | |
8646 | je LRound_nearest_53 | |
8647 | ||
8648 | cmpl RC_CHOP,%ecx | |
8649 | je LCheck_truncate_53 | |
8650 | ||
8651 | cmpl RC_UP,%ecx /* Towards +infinity*/ | |
8652 | je LUp_53 | |
8653 | ||
8654 | cmpl RC_DOWN,%ecx /* Towards -infinity*/ | |
8655 | je LDown_53 | |
8656 | ||
8657 | #ifdef PARANOID | |
8658 | jmp L_bugged | |
8659 | #endif PARANOID | |
8660 | ||
8661 | LUp_53: | |
8662 | cmpb SIGN_POS,SIGN(%edi) | |
8663 | jne LCheck_truncate_53 /* If negative then up==truncate*/ | |
8664 | ||
8665 | jmp LCheck_53_round_up | |
8666 | ||
8667 | LDown_53: | |
8668 | cmpb SIGN_POS,SIGN(%edi) | |
8669 | je LCheck_truncate_53 /* If positive then down==truncate*/ | |
8670 | ||
8671 | LCheck_53_round_up: | |
8672 | movl %ebx,%ecx | |
8673 | andl $0x000007ff,%ecx | |
8674 | orl %edx,%ecx | |
8675 | jnz LDo_53_round_up | |
8676 | jmp LRe_normalise | |
8677 | ||
8678 | LRound_nearest_53: | |
8679 | /*Do rounding of the 53rd bit if needed (nearest or even)*/ | |
8680 | movl %ebx,%ecx | |
8681 | andl $0x000007ff,%ecx | |
8682 | cmpl $0x00000400,%ecx | |
8683 | jc LCheck_truncate_53 /* less than half, no increment needed*/ | |
8684 | ||
8685 | jnz LGreater_Half_53 /* greater than half, increment needed*/ | |
8686 | ||
8687 | /*Possibly half, we need to check the ls bits*/ | |
8688 | orl %edx,%edx | |
8689 | jnz LGreater_Half_53 /* greater than half, increment needed*/ | |
8690 | ||
8691 | /* Exactly half, increment only if 53rd bit is 1 (round to even)*/ | |
8692 | testl $0x00000800,%ebx | |
8693 | jz LTruncate_53 | |
8694 | ||
8695 | LGreater_Half_53: /*Rounding: increment at the 53rd bit*/ | |
8696 | LDo_53_round_up: | |
8697 | movb LOST_UP,FPU_bits_lost | |
8698 | andl $0xfffff800,%ebx /* Truncate to 53 bits*/ | |
8699 | addl $0x00000800,%ebx | |
8700 | adcl $0,%eax | |
8701 | jmp LCheck_Round_Overflow | |
8702 | ||
8703 | LCheck_truncate_53: | |
8704 | movl %ebx,%ecx | |
8705 | andl $0x000007ff,%ecx | |
8706 | orl %edx,%ecx | |
8707 | jz LRe_normalise | |
8708 | ||
8709 | LTruncate_53: | |
8710 | movb LOST_DOWN,FPU_bits_lost | |
8711 | andl $0xfffff800,%ebx /* Truncate to 53 bits*/ | |
8712 | jmp LRe_normalise | |
8713 | ||
8714 | ||
8715 | /* Round etc to 64 bit precision*/ | |
8716 | LRound_To_64: | |
8717 | movl %esi,%ecx | |
8718 | andl CW_RC,%ecx | |
8719 | cmpl RC_RND,%ecx | |
8720 | je LRound_nearest_64 | |
8721 | ||
8722 | cmpl RC_CHOP,%ecx | |
8723 | je LCheck_truncate_64 | |
8724 | ||
8725 | cmpl RC_UP,%ecx /* Towards +infinity*/ | |
8726 | je LUp_64 | |
8727 | ||
8728 | cmpl RC_DOWN,%ecx /* Towards -infinity*/ | |
8729 | je LDown_64 | |
8730 | ||
8731 | #ifdef PARANOID | |
8732 | jmp L_bugged | |
8733 | #endif PARANOID | |
8734 | ||
8735 | LUp_64: | |
8736 | cmpb SIGN_POS,SIGN(%edi) | |
8737 | jne LCheck_truncate_64 /* If negative then up==truncate*/ | |
8738 | ||
8739 | orl %edx,%edx | |
8740 | jnz LDo_64_round_up | |
8741 | jmp LRe_normalise | |
8742 | ||
8743 | LDown_64: | |
8744 | cmpb SIGN_POS,SIGN(%edi) | |
8745 | je LCheck_truncate_64 /*If positive then down==truncate*/ | |
8746 | ||
8747 | orl %edx,%edx | |
8748 | jnz LDo_64_round_up | |
8749 | jmp LRe_normalise | |
8750 | ||
8751 | LRound_nearest_64: | |
8752 | cmpl $0x80000000,%edx | |
8753 | jc LCheck_truncate_64 | |
8754 | ||
8755 | jne LDo_64_round_up | |
8756 | ||
8757 | /* Now test for round-to-even */ | |
8758 | testb $1,%ebx | |
8759 | jz LCheck_truncate_64 | |
8760 | ||
8761 | LDo_64_round_up: | |
8762 | movb LOST_UP,FPU_bits_lost | |
8763 | addl $1,%ebx | |
8764 | adcl $0,%eax | |
8765 | ||
8766 | LCheck_Round_Overflow: | |
8767 | jnc LRe_normalise /* Rounding done, no overflow */ | |
8768 | ||
8769 | /* Overflow, adjust the result (to 1.0) */ | |
8770 | rcrl $1,%eax | |
8771 | rcrl $1,%ebx | |
8772 | incl EXP(%edi) | |
8773 | jmp LRe_normalise | |
8774 | ||
8775 | LCheck_truncate_64: | |
8776 | orl %edx,%edx | |
8777 | jz LRe_normalise | |
8778 | ||
8779 | LTruncate_64: | |
8780 | movb LOST_DOWN,FPU_bits_lost | |
8781 | ||
8782 | LRe_normalise: | |
8783 | testb $0xff,FPU_denormal | |
8784 | jnz xNormalise_result | |
8785 | ||
8786 | xL_Normalised: | |
8787 | cmpb LOST_UP,FPU_bits_lost | |
8788 | je xL_precision_lost_up | |
8789 | ||
8790 | cmpb LOST_DOWN,FPU_bits_lost | |
8791 | je xL_precision_lost_down | |
8792 | ||
8793 | xL_no_precision_loss: | |
8794 | cmpl EXP_OVER,EXP(%edi) | |
8795 | jge L_overflow | |
8796 | ||
8797 | /* store the result */ | |
8798 | movb TW_Valid,TAG(%edi) | |
8799 | ||
8800 | xL_Store_significand: | |
8801 | movl %eax,SIGH(%edi) | |
8802 | movl %ebx,SIGL(%edi) | |
8803 | ||
8804 | FPU_Arith_exit: | |
8805 | popl %ebx | |
8806 | popl %edi | |
8807 | popl %esi | |
8808 | leave | |
8809 | ret | |
8810 | ||
8811 | ||
8812 | /* Set the FPU status flags to represent precision loss due to*/ | |
8813 | /* round-up.*/ | |
8814 | xL_precision_lost_up: | |
8815 | push %eax | |
8816 | call _set_precision_flag_up | |
8817 | popl %eax | |
8818 | jmp xL_no_precision_loss | |
8819 | ||
8820 | /* Set the FPU status flags to represent precision loss due to*/ | |
8821 | /* truncation.*/ | |
8822 | xL_precision_lost_down: | |
8823 | push %eax | |
8824 | call _set_precision_flag_down | |
8825 | popl %eax | |
8826 | jmp xL_no_precision_loss | |
8827 | ||
8828 | ||
8829 | /* The number is a denormal (which might get rounded up to a normal) | |
8830 | // Shift the number right the required number of bits, which will | |
8831 | // have to be undone later...*/ | |
8832 | xMake_denorm: | |
8833 | /* The action to be taken depends upon whether the underflow | |
8834 | // exception is masked*/ | |
8835 | testb CW_Underflow,%cl /* Underflow mask.*/ | |
8836 | jz xUnmasked_underflow /* Do not make a denormal.*/ | |
8837 | ||
8838 | movb DENORMAL,FPU_denormal | |
8839 | ||
8840 | pushl %ecx /* Save*/ | |
8841 | movl EXP(%edi),%ecx | |
8842 | subl EXP_UNDER+1,%ecx | |
8843 | negl %ecx | |
8844 | ||
8845 | cmpl $64,%ecx /* shrd only works for 0..31 bits */ | |
8846 | jnc xDenorm_shift_more_than_63 | |
8847 | ||
8848 | cmpl $32,%ecx /* shrd only works for 0..31 bits */ | |
8849 | jnc xDenorm_shift_more_than_32 | |
8850 | ||
8851 | /* We got here without jumps by assuming that the most common requirement | |
8852 | // is for a small de-normalising shift. | |
8853 | // Shift by [1..31] bits */ | |
8854 | addl %ecx,EXP(%edi) | |
8855 | orl %edx,%edx /* extension*/ | |
8856 | setne %ch | |
8857 | xorl %edx,%edx | |
8858 | shrd %cl,%ebx,%edx | |
8859 | shrd %cl,%eax,%ebx | |
8860 | shr %cl,%eax | |
8861 | orb %ch,%dl | |
8862 | popl %ecx | |
8863 | jmp xDenorm_done | |
8864 | ||
8865 | /* Shift by [32..63] bits*/ | |
8866 | xDenorm_shift_more_than_32: | |
8867 | addl %ecx,EXP(%edi) | |
8868 | subb $32,%cl | |
8869 | orl %edx,%edx | |
8870 | setne %ch | |
8871 | orb %ch,%bl | |
8872 | xorl %edx,%edx | |
8873 | shrd %cl,%ebx,%edx | |
8874 | shrd %cl,%eax,%ebx | |
8875 | shr %cl,%eax | |
8876 | orl %edx,%edx /*test these 32 bits*/ | |
8877 | setne %cl | |
8878 | orb %ch,%bl | |
8879 | orb %cl,%bl | |
8880 | movl %ebx,%edx | |
8881 | movl %eax,%ebx | |
8882 | xorl %eax,%eax | |
8883 | popl %ecx | |
8884 | jmp xDenorm_done | |
8885 | ||
8886 | /* Shift by [64..) bits*/ | |
8887 | xDenorm_shift_more_than_63: | |
8888 | cmpl $64,%ecx | |
8889 | jne xDenorm_shift_more_than_64 | |
8890 | ||
8891 | /* Exactly 64 bit shift*/ | |
8892 | addl %ecx,EXP(%edi) | |
8893 | xorl %ecx,%ecx | |
8894 | orl %edx,%edx | |
8895 | setne %cl | |
8896 | orl %ebx,%ebx | |
8897 | setne %ch | |
8898 | orb %ch,%cl | |
8899 | orb %cl,%al | |
8900 | movl %eax,%edx | |
8901 | xorl %eax,%eax | |
8902 | xorl %ebx,%ebx | |
8903 | popl %ecx | |
8904 | jmp xDenorm_done | |
8905 | ||
8906 | xDenorm_shift_more_than_64: | |
8907 | movl EXP_UNDER+1,EXP(%edi) | |
8908 | /* This is easy, %eax must be non-zero, so..*/ | |
8909 | movl $1,%edx | |
8910 | xorl %eax,%eax | |
8911 | xorl %ebx,%ebx | |
8912 | popl %ecx | |
8913 | jmp xDenorm_done | |
8914 | ||
8915 | ||
8916 | xUnmasked_underflow: | |
8917 | /* Increase the exponent by the magic number*/ | |
8918 | addl $(3*(1<<13)),EXP(%edi) | |
8919 | movb UNMASKED_UNDERFLOW,FPU_denormal | |
8920 | jmp xDenorm_done | |
8921 | ||
8922 | ||
8923 | /* Undo the de-normalisation.*/ | |
8924 | xNormalise_result: | |
8925 | cmpb UNMASKED_UNDERFLOW,FPU_denormal | |
8926 | je xSignal_underflow | |
8927 | ||
8928 | /* The number must be a denormal if we got here.*/ | |
8929 | #ifdef PARANOID | |
8930 | /* But check it... just in case.*/ | |
8931 | cmpl EXP_UNDER+1,EXP(%edi) | |
8932 | jne L_norm_bugged | |
8933 | #endif PARANOID | |
8934 | ||
8935 | orl %eax,%eax /* ms bits*/ | |
8936 | jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits*/ | |
8937 | ||
8938 | orl %ebx,%ebx | |
8939 | jz L_underflow_to_zero /* The contents are zero*/ | |
8940 | ||
8941 | /* Shift left 32 - 63 bits*/ | |
8942 | movl %ebx,%eax | |
8943 | xorl %ebx,%ebx | |
8944 | subl $32,EXP(%edi) | |
8945 | ||
8946 | LNormalise_shift_up_to_31: | |
8947 | bsrl %eax,%ecx /* get the required shift in %ecx */ | |
8948 | subl $31,%ecx | |
8949 | negl %ecx | |
8950 | shld %cl,%ebx,%eax | |
8951 | shl %cl,%ebx | |
8952 | subl %ecx,EXP(%edi) | |
8953 | ||
8954 | LNormalise_shift_done: | |
8955 | testb $0xff,FPU_bits_lost /* bits lost == underflow*/ | |
8956 | jz xL_Normalised | |
8957 | ||
8958 | /* There must be a masked underflow*/ | |
8959 | push %eax | |
8960 | pushl EX_Underflow | |
8961 | call _exception | |
8962 | popl %eax | |
8963 | popl %eax | |
8964 | jmp xL_Normalised | |
8965 | ||
8966 | ||
8967 | /* The operations resulted in a number too small to represent. | |
8968 | // Masked response.*/ | |
8969 | L_underflow_to_zero: | |
8970 | push %eax | |
8971 | call _set_precision_flag_down | |
8972 | popl %eax | |
8973 | ||
8974 | push %eax | |
8975 | pushl EX_Underflow | |
8976 | call _exception | |
8977 | popl %eax | |
8978 | popl %eax | |
8979 | ||
8980 | movb TW_Zero,TAG(%edi) | |
8981 | jmp xL_Store_significand | |
8982 | ||
8983 | ||
8984 | /* The operations resulted in a number too large to represent.*/ | |
8985 | L_overflow: | |
8986 | push %edi | |
8987 | call _arith_overflow | |
8988 | pop %edi | |
8989 | jmp FPU_Arith_exit | |
8990 | ||
8991 | ||
8992 | xSignal_underflow: | |
8993 | push %eax | |
8994 | pushl EX_Underflow | |
8995 | call EXCEPTION | |
8996 | popl %eax | |
8997 | popl %eax | |
8998 | jmp xL_Normalised | |
8999 | ||
9000 | ||
9001 | #ifdef PARANOID | |
9002 | /* If we ever get here then we have problems! */ | |
9003 | L_bugged: | |
9004 | pushl EX_INTERNAL|0x201 | |
9005 | call EXCEPTION | |
9006 | popl %ebx | |
9007 | jmp FPU_Arith_exit | |
9008 | ||
9009 | L_norm_bugged: | |
9010 | pushl EX_INTERNAL|0x216 | |
9011 | call EXCEPTION | |
9012 | popl %ebx | |
9013 | jmp FPU_Arith_exit | |
9014 | ||
9015 | L_entry_bugged: | |
9016 | pushl EX_INTERNAL|0x217 | |
9017 | call EXCEPTION | |
9018 | popl %ebx | |
9019 | jmp FPU_Arith_exit | |
9020 | #endif PARANOID | |
9021 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_u_add.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 12727 5462505570 12704\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "reg_u_add.S" | |
9022 | /* | |
9023 | * reg_u_add.S | |
9024 | * | |
9025 | * Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the | |
9026 | * result in a destination FPU_REG. | |
9027 | * | |
9028 | * Call from C as: | |
9029 | * void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | |
9030 | * int control_w) | |
9031 | * | |
9032 | * | |
9033 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
9034 | * Vic 3163, Australia. | |
9035 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
9036 | * All rights reserved. | |
9037 | * | |
9038 | * This copyright notice covers the redistribution and use of the | |
9039 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
9040 | * in the 386BSD operating system. Any other use is not permitted | |
9041 | * under this copyright. | |
9042 | * | |
9043 | * Redistribution and use in source and binary forms, with or without | |
9044 | * modification, are permitted provided that the following conditions | |
9045 | * are met: | |
9046 | * 1. Redistributions of source code must retain the above copyright | |
9047 | * notice, this list of conditions and the following disclaimer. | |
9048 | * 2. Redistributions in binary form must include information specifying | |
9049 | * that source code for the emulator is freely available and include | |
9050 | * either: | |
9051 | * a) an offer to provide the source code for a nominal distribution | |
9052 | * fee, or | |
9053 | * b) list at least two alternative methods whereby the source | |
9054 | * can be obtained, e.g. a publically accessible bulletin board | |
9055 | * and an anonymous ftp site from which the software can be | |
9056 | * downloaded. | |
9057 | * 3. All advertising materials specifically mentioning features or use of | |
9058 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
9059 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
9060 | * products derived from this software without specific prior written | |
9061 | * permission. | |
9062 | * | |
9063 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
9064 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
9065 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
9066 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
9067 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
9068 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
9069 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
9070 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
9071 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
9072 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
9073 | * | |
9074 | */ | |
9075 | ||
9076 | ||
9077 | /* | |
9078 | | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ). | |
9079 | | Takes two valid reg f.p. numbers (TW_Valid), which are | |
9080 | | treated as unsigned numbers, | |
9081 | | and returns their sum as a TW_Valid or TW_S f.p. number. | |
9082 | | The returned number is normalized. | |
9083 | | Basic checks are performed if PARANOID is defined. | |
9084 | */ | |
9085 | ||
9086 | #include "exception.h" | |
9087 | #include "fpu_asm.h" | |
9088 | #include "control_w.h" | |
9089 | ||
9090 | .text | |
9091 | .align 2,144 | |
9092 | .globl _reg_u_add | |
9093 | _reg_u_add: | |
9094 | pushl %ebp | |
9095 | movl %esp,%ebp | |
9096 | /* subl $16,%esp*/ | |
9097 | pushl %esi | |
9098 | pushl %edi | |
9099 | pushl %ebx | |
9100 | ||
9101 | movl PARAM1,%esi /* source 1 */ | |
9102 | movl PARAM2,%edi /* source 2 */ | |
9103 | ||
9104 | #ifdef DENORM_OPERAND | |
9105 | cmpl EXP_UNDER,EXP(%esi) | |
9106 | jg xOp1_not_denorm | |
9107 | ||
9108 | call _denormal_operand | |
9109 | orl %eax,%eax | |
9110 | jnz FPU_Arith_exit | |
9111 | ||
9112 | xOp1_not_denorm: | |
9113 | cmpl EXP_UNDER,EXP(%edi) | |
9114 | jg xOp2_not_denorm | |
9115 | ||
9116 | call _denormal_operand | |
9117 | orl %eax,%eax | |
9118 | jnz FPU_Arith_exit | |
9119 | ||
9120 | xOp2_not_denorm: | |
9121 | #endif DENORM_OPERAND | |
9122 | ||
9123 | /* xorl %ecx,%ecx*/ | |
9124 | movl EXP(%esi),%ecx | |
9125 | subl EXP(%edi),%ecx /* exp1 - exp2 */ | |
9126 | /* jnc L_arg1_larger*/ | |
9127 | jge L_arg1_larger | |
9128 | ||
9129 | /* num1 is smaller */ | |
9130 | movl SIGL(%esi),%ebx | |
9131 | movl SIGH(%esi),%eax | |
9132 | ||
9133 | movl %edi,%esi | |
9134 | negw %cx | |
9135 | jmp L_accum_loaded | |
9136 | ||
9137 | L_arg1_larger: | |
9138 | /* num1 has larger or equal exponent */ | |
9139 | movl SIGL(%edi),%ebx | |
9140 | movl SIGH(%edi),%eax | |
9141 | ||
9142 | L_accum_loaded: | |
9143 | movl PARAM3,%edi /* destination */ | |
9144 | movb SIGN(%esi),%dl | |
9145 | movb %dl,SIGN(%edi) /* Copy the sign from the first arg */ | |
9146 | ||
9147 | ||
9148 | movl EXP(%esi),%edx | |
9149 | movl %edx,EXP(%edi) /* Copy exponent to destination */ | |
9150 | ||
9151 | xorl %edx,%edx /* clear the extension */ | |
9152 | ||
9153 | #ifdef PARANOID | |
9154 | testl $0x80000000,%eax | |
9155 | je L_bugged | |
9156 | ||
9157 | testl $0x80000000,SIGH(%esi) | |
9158 | je L_bugged | |
9159 | #endif PARANOID | |
9160 | ||
9161 | /* The number to be shifted is in %eax:%ebx:%edx*/ | |
9162 | cmpw $32,%cx /* shrd only works for 0..31 bits */ | |
9163 | jnc L_more_than_31 | |
9164 | ||
9165 | /* less than 32 bits */ | |
9166 | shrd %cl,%ebx,%edx | |
9167 | shrd %cl,%eax,%ebx | |
9168 | shr %cl,%eax | |
9169 | jmp L_shift_done | |
9170 | ||
9171 | L_more_than_31: | |
9172 | cmpw $64,%cx | |
9173 | jnc L_more_than_63 | |
9174 | ||
9175 | subb $32,%cl | |
9176 | jz L_exactly_32 | |
9177 | ||
9178 | shrd %cl,%eax,%edx | |
9179 | shr %cl,%eax | |
9180 | orl %ebx,%ebx | |
9181 | jz L_more_31_no_low /* none of the lowest bits is set*/ | |
9182 | ||
9183 | orl $1,%edx /* record the fact in the extension*/ | |
9184 | ||
9185 | L_more_31_no_low: | |
9186 | movl %eax,%ebx | |
9187 | xorl %eax,%eax | |
9188 | jmp L_shift_done | |
9189 | ||
9190 | L_exactly_32: | |
9191 | movl %ebx,%edx | |
9192 | movl %eax,%ebx | |
9193 | xorl %eax,%eax | |
9194 | jmp L_shift_done | |
9195 | ||
9196 | L_more_than_63: | |
9197 | cmpw $65,%cx | |
9198 | jnc L_more_than_64 | |
9199 | ||
9200 | movl %eax,%edx | |
9201 | orl %ebx,%ebx | |
9202 | jz L_more_63_no_low | |
9203 | ||
9204 | orl $1,%edx | |
9205 | jmp L_more_63_no_low | |
9206 | ||
9207 | L_more_than_64: | |
9208 | movl $1,%edx /* The shifted nr always at least one '1'*/ | |
9209 | ||
9210 | L_more_63_no_low: | |
9211 | xorl %ebx,%ebx | |
9212 | xorl %eax,%eax | |
9213 | ||
9214 | L_shift_done: | |
9215 | /* Now do the addition */ | |
9216 | addl SIGL(%esi),%ebx | |
9217 | adcl SIGH(%esi),%eax | |
9218 | jnc L_round_the_result | |
9219 | ||
9220 | /* Overflow, adjust the result */ | |
9221 | rcrl $1,%eax | |
9222 | rcrl $1,%ebx | |
9223 | rcrl $1,%edx | |
9224 | jnc L_no_bit_lost | |
9225 | ||
9226 | orl $1,%edx | |
9227 | ||
9228 | L_no_bit_lost: | |
9229 | incl EXP(%edi) | |
9230 | ||
9231 | L_round_the_result: | |
9232 | jmp FPU_round /* Round the result*/ | |
9233 | ||
9234 | ||
9235 | ||
9236 | #ifdef PARANOID | |
9237 | /* If we ever get here then we have problems! */ | |
9238 | L_bugged: | |
9239 | pushl EX_INTERNAL|0x201 | |
9240 | call EXCEPTION | |
9241 | pop %ebx | |
9242 | jmp L_exit | |
9243 | #endif PARANOID | |
9244 | ||
9245 | ||
9246 | L_exit: | |
9247 | popl %ebx | |
9248 | popl %edi | |
9249 | popl %esi | |
9250 | leave | |
9251 | ret | |
9252 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_u_div.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 31130 5462505570 12723\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "reg_u_div.S" | |
9253 | /* | |
9254 | * reg_u_div.S | |
9255 | * | |
9256 | * Core division routines | |
9257 | * | |
9258 | * | |
9259 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
9260 | * Vic 3163, Australia. | |
9261 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
9262 | * All rights reserved. | |
9263 | * | |
9264 | * This copyright notice covers the redistribution and use of the | |
9265 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
9266 | * in the 386BSD operating system. Any other use is not permitted | |
9267 | * under this copyright. | |
9268 | * | |
9269 | * Redistribution and use in source and binary forms, with or without | |
9270 | * modification, are permitted provided that the following conditions | |
9271 | * are met: | |
9272 | * 1. Redistributions of source code must retain the above copyright | |
9273 | * notice, this list of conditions and the following disclaimer. | |
9274 | * 2. Redistributions in binary form must include information specifying | |
9275 | * that source code for the emulator is freely available and include | |
9276 | * either: | |
9277 | * a) an offer to provide the source code for a nominal distribution | |
9278 | * fee, or | |
9279 | * b) list at least two alternative methods whereby the source | |
9280 | * can be obtained, e.g. a publically accessible bulletin board | |
9281 | * and an anonymous ftp site from which the software can be | |
9282 | * downloaded. | |
9283 | * 3. All advertising materials specifically mentioning features or use of | |
9284 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
9285 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
9286 | * products derived from this software without specific prior written | |
9287 | * permission. | |
9288 | * | |
9289 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
9290 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
9291 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
9292 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
9293 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
9294 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
9295 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
9296 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
9297 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
9298 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
9299 | * | |
9300 | */ | |
9301 | ||
9302 | /*---------------------------------------------------------------------------+ | |
9303 | | Kernel for the division routines. | | |
9304 | | | | |
9305 | | void reg_u_div(FPU_REG *a, FPU_REG *a, | | |
9306 | | FPU_REG *dest, unsigned int control_word) | | |
9307 | | | | |
9308 | | Does not compute the destination exponent, but does adjust it. | | |
9309 | +---------------------------------------------------------------------------*/ | |
9310 | ||
9311 | #include "exception.h" | |
9312 | #include "fpu_asm.h" | |
9313 | #include "control_w.h" | |
9314 | ||
9315 | ||
9316 | /* #define dSIGL(x) (x) */ | |
9317 | /* #define dSIGH(x) 4(x) */ | |
9318 | ||
9319 | ||
9320 | .data | |
9321 | /* | |
9322 | Local storage: | |
9323 | Result: accum_3:accum_2:accum_1:accum_0 | |
9324 | Overflow flag: ovfl_flag | |
9325 | */ | |
9326 | .align 2,0 | |
9327 | accum_3: | |
9328 | .long 0 | |
9329 | accum_2: | |
9330 | .long 0 | |
9331 | accum_1: | |
9332 | .long 0 | |
9333 | accum_0: | |
9334 | .long 0 | |
9335 | result_1: | |
9336 | .long 0 | |
9337 | result_2: | |
9338 | .long 0 | |
9339 | ovfl_flag: | |
9340 | .byte 0 | |
9341 | ||
9342 | ||
9343 | .text | |
9344 | .align 2,144 | |
9345 | ||
9346 | .globl _reg_u_div | |
9347 | ||
9348 | .globl _divide_kernel | |
9349 | ||
9350 | _reg_u_div: | |
9351 | pushl %ebp | |
9352 | movl %esp,%ebp | |
9353 | ||
9354 | pushl %esi | |
9355 | pushl %edi | |
9356 | pushl %ebx | |
9357 | ||
9358 | movl PARAM1,%esi /* pointer to num */ | |
9359 | movl PARAM2,%ebx /* pointer to denom */ | |
9360 | movl PARAM3,%edi /* pointer to answer */ | |
9361 | ||
9362 | #ifdef DENORM_OPERAND | |
9363 | movl EXP(%esi),%eax | |
9364 | cmpl EXP_UNDER,%eax | |
9365 | jg xOp1_not_denorm | |
9366 | ||
9367 | call _denormal_operand | |
9368 | orl %eax,%eax | |
9369 | jnz FPU_Arith_exit | |
9370 | ||
9371 | xOp1_not_denorm: | |
9372 | movl EXP(%ebx),%eax | |
9373 | cmpl EXP_UNDER,%eax | |
9374 | jg xOp2_not_denorm | |
9375 | ||
9376 | call _denormal_operand | |
9377 | orl %eax,%eax | |
9378 | jnz FPU_Arith_exit | |
9379 | ||
9380 | xOp2_not_denorm: | |
9381 | #endif DENORM_OPERAND | |
9382 | ||
9383 | _divide_kernel: | |
9384 | #ifdef PARANOID | |
9385 | /* testl $0x80000000, SIGH(%esi) *//* Dividend */ | |
9386 | /* je L_bugged */ | |
9387 | testl $0x80000000, SIGH(%ebx) /* Divisor*/ | |
9388 | je L_bugged | |
9389 | #endif PARANOID | |
9390 | ||
9391 | /* Check if the divisor can be treated as having just 32 bits */ | |
9392 | cmpl $0,SIGL(%ebx) | |
9393 | jnz L_Full_Division /* Can't do a quick divide */ | |
9394 | ||
9395 | /* We should be able to zip through the division here */ | |
9396 | movl SIGH(%ebx),%ecx /* The divisor */ | |
9397 | movl SIGH(%esi),%edx /* Dividend */ | |
9398 | movl SIGL(%esi),%eax /* Dividend */ | |
9399 | ||
9400 | cmpl %ecx,%edx | |
9401 | setaeb ovfl_flag /* Keep a record */ | |
9402 | jb L_no_adjust | |
9403 | ||
9404 | subl %ecx,%edx /* Prevent the overflow */ | |
9405 | ||
9406 | L_no_adjust: | |
9407 | /* Divide the 64 bit number by the 32 bit denominator */ | |
9408 | divl %ecx | |
9409 | movl %eax,result_2 | |
9410 | ||
9411 | /* Work on the remainder of the first division */ | |
9412 | xorl %eax,%eax | |
9413 | divl %ecx | |
9414 | movl %eax,result_1 | |
9415 | ||
9416 | /* Work on the remainder of the 64 bit division */ | |
9417 | xorl %eax,%eax | |
9418 | divl %ecx | |
9419 | ||
9420 | testb $255,ovfl_flag /* was the num > denom ? */ | |
9421 | je L_no_overflow | |
9422 | ||
9423 | /* Do the shifting here */ | |
9424 | /* increase the exponent */ | |
9425 | incl EXP(%edi) | |
9426 | ||
9427 | /* shift the mantissa right one bit */ | |
9428 | stc /* To set the ms bit */ | |
9429 | rcrl result_2 | |
9430 | rcrl result_1 | |
9431 | rcrl %eax | |
9432 | ||
9433 | L_no_overflow: | |
9434 | jmp LRound_precision /* Do the rounding as required*/ | |
9435 | ||
9436 | ||
9437 | /*---------------------------------------------------------------------------+ | |
9438 | | Divide: Return arg1/arg2 to arg3. | | |
9439 | | | | |
9440 | | This routine does not use the exponents of arg1 and arg2, but does | | |
9441 | | adjust the exponent of arg3. | | |
9442 | | | | |
9443 | | The maximum returned value is (ignoring exponents) | | |
9444 | | .ffffffff ffffffff | | |
9445 | | ------------------ = 1.ffffffff fffffffe | | |
9446 | | .80000000 00000000 | | |
9447 | | and the minimum is | | |
9448 | | .80000000 00000000 | | |
9449 | | ------------------ = .80000000 00000001 (rounded) | | |
9450 | | .ffffffff ffffffff | | |
9451 | | | | |
9452 | +---------------------------------------------------------------------------*/ | |
9453 | ||
9454 | ||
9455 | L_Full_Division: | |
9456 | /* Save extended dividend in local register*/ | |
9457 | movl SIGL(%esi),%eax | |
9458 | movl %eax,accum_2 | |
9459 | movl SIGH(%esi),%eax | |
9460 | movl %eax,accum_3 | |
9461 | xorl %eax,%eax | |
9462 | movl %eax,accum_1 /* zero the extension */ | |
9463 | movl %eax,accum_0 /* zero the extension */ | |
9464 | ||
9465 | movl SIGL(%esi),%eax /* Get the current num */ | |
9466 | movl SIGH(%esi),%edx | |
9467 | ||
9468 | /*----------------------------------------------------------------------*/ | |
9469 | /* Initialization done */ | |
9470 | /* Do the first 32 bits */ | |
9471 | ||
9472 | movb $0,ovfl_flag | |
9473 | cmpl SIGH(%ebx),%edx /* Test for imminent overflow */ | |
9474 | jb LLess_than_1 | |
9475 | ja LGreater_than_1 | |
9476 | ||
9477 | cmpl SIGL(%ebx),%eax | |
9478 | jb LLess_than_1 | |
9479 | ||
9480 | LGreater_than_1: | |
9481 | /* The dividend is greater or equal, would cause overflow */ | |
9482 | setaeb ovfl_flag /* Keep a record */ | |
9483 | ||
9484 | subl SIGL(%ebx),%eax | |
9485 | sbbl SIGH(%ebx),%edx /* Prevent the overflow */ | |
9486 | movl %eax,accum_2 | |
9487 | movl %edx,accum_3 | |
9488 | ||
9489 | LLess_than_1: | |
9490 | /* At this point, we have a dividend < divisor, with a record of | |
9491 | adjustment in ovfl_flag */ | |
9492 | ||
9493 | /* We will divide by a number which is too large */ | |
9494 | movl SIGH(%ebx),%ecx | |
9495 | addl $1,%ecx | |
9496 | jnc LFirst_div_not_1 | |
9497 | ||
9498 | /* here we need to divide by 100000000h, | |
9499 | i.e., no division at all.. */ | |
9500 | mov %edx,%eax | |
9501 | jmp LFirst_div_done | |
9502 | ||
9503 | LFirst_div_not_1: | |
9504 | divl %ecx /* Divide the numerator by the augmented | |
9505 | denom ms dw */ | |
9506 | ||
9507 | LFirst_div_done: | |
9508 | movl %eax,result_2 /* Put the result in the answer */ | |
9509 | ||
9510 | mull SIGH(%ebx) /* mul by the ms dw of the denom */ | |
9511 | ||
9512 | subl %eax,accum_2 /* Subtract from the num local reg */ | |
9513 | sbbl %edx,accum_3 | |
9514 | ||
9515 | movl result_2,%eax /* Get the result back */ | |
9516 | mull SIGL(%ebx) /* now mul the ls dw of the denom */ | |
9517 | ||
9518 | subl %eax,accum_1 /* Subtract from the num local reg */ | |
9519 | sbbl %edx,accum_2 | |
9520 | sbbl $0,accum_3 | |
9521 | je LDo_2nd_32_bits /* Must check for non-zero result here */ | |
9522 | ||
9523 | #ifdef PARANOID | |
9524 | jb L_bugged_1 | |
9525 | #endif PARANOID | |
9526 | ||
9527 | /* need to subtract another once of the denom */ | |
9528 | incl result_2 /* Correct the answer */ | |
9529 | ||
9530 | movl SIGL(%ebx),%eax | |
9531 | movl SIGH(%ebx),%edx | |
9532 | subl %eax,accum_1 /* Subtract from the num local reg */ | |
9533 | sbbl %edx,accum_2 | |
9534 | ||
9535 | #ifdef PARANOID | |
9536 | sbbl $0,accum_3 | |
9537 | jne L_bugged_1 /* Must check for non-zero result here */ | |
9538 | #endif PARANOID | |
9539 | ||
9540 | /*----------------------------------------------------------------------*/ | |
9541 | /* Half of the main problem is done, there is just a reduced numerator | |
9542 | to handle now */ | |
9543 | /* Work with the second 32 bits, accum_0 not used from now on */ | |
9544 | LDo_2nd_32_bits: | |
9545 | movl accum_2,%edx /* get the reduced num */ | |
9546 | movl accum_1,%eax | |
9547 | ||
9548 | /* need to check for possible subsequent overflow */ | |
9549 | cmpl SIGH(%ebx),%edx | |
9550 | jb LDo_2nd_div | |
9551 | ja LPrevent_2nd_overflow | |
9552 | ||
9553 | cmpl SIGL(%ebx),%eax | |
9554 | jb LDo_2nd_div | |
9555 | ||
9556 | LPrevent_2nd_overflow: | |
9557 | /* The numerator is greater or equal, would cause overflow */ | |
9558 | /* prevent overflow */ | |
9559 | subl SIGL(%ebx),%eax | |
9560 | sbbl SIGH(%ebx),%edx | |
9561 | movl %edx,accum_2 | |
9562 | movl %eax,accum_1 | |
9563 | ||
9564 | incl result_2 /* Reflect the subtraction in the answer */ | |
9565 | ||
9566 | #ifdef PARANOID | |
9567 | je L_bugged_2 /* Can't bump the result to 1.0 */ | |
9568 | #endif PARANOID | |
9569 | ||
9570 | LDo_2nd_div: | |
9571 | cmpl $0,%ecx /* augmented denom msw*/ | |
9572 | jnz LSecond_div_not_1 | |
9573 | ||
9574 | /* %ecx == 0, we are dividing by 1.0 */ | |
9575 | mov %edx,%eax | |
9576 | jmp LSecond_div_done | |
9577 | ||
9578 | LSecond_div_not_1: | |
9579 | divl %ecx /* Divide the numerator by the denom ms dw */ | |
9580 | ||
9581 | LSecond_div_done: | |
9582 | movl %eax,result_1 /* Put the result in the answer */ | |
9583 | ||
9584 | mull SIGH(%ebx) /* mul by the ms dw of the denom */ | |
9585 | ||
9586 | subl %eax,accum_1 /* Subtract from the num local reg */ | |
9587 | sbbl %edx,accum_2 | |
9588 | ||
9589 | #ifdef PARANOID | |
9590 | jc L_bugged_2 | |
9591 | #endif PARANOID | |
9592 | ||
9593 | movl result_1,%eax /* Get the result back */ | |
9594 | mull SIGL(%ebx) /* now mul the ls dw of the denom */ | |
9595 | ||
9596 | subl %eax,accum_0 /* Subtract from the num local reg */ | |
9597 | sbbl %edx,accum_1 /* Subtract from the num local reg */ | |
9598 | sbbl $0,accum_2 | |
9599 | ||
9600 | #ifdef PARANOID | |
9601 | jc L_bugged_2 | |
9602 | #endif PARANOID | |
9603 | ||
9604 | jz LDo_3rd_32_bits | |
9605 | ||
9606 | #ifdef PARANOID | |
9607 | cmpl $1,accum_2 | |
9608 | jne L_bugged_2 | |
9609 | #endif PARANOID | |
9610 | ||
9611 | /* need to subtract another once of the denom */ | |
9612 | movl SIGL(%ebx),%eax | |
9613 | movl SIGH(%ebx),%edx | |
9614 | subl %eax,accum_0 /* Subtract from the num local reg */ | |
9615 | sbbl %edx,accum_1 | |
9616 | sbbl $0,accum_2 | |
9617 | ||
9618 | #ifdef PARANOID | |
9619 | jc L_bugged_2 | |
9620 | jne L_bugged_2 | |
9621 | #endif PARANOID | |
9622 | ||
9623 | addl $1,result_1 /* Correct the answer */ | |
9624 | adcl $0,result_2 | |
9625 | ||
9626 | #ifdef PARANOID | |
9627 | jc L_bugged_2 /* Must check for non-zero result here */ | |
9628 | #endif PARANOID | |
9629 | ||
9630 | /*----------------------------------------------------------------------*/ | |
9631 | /* The division is essentially finished here, we just need to perform | |
9632 | tidying operations. */ | |
9633 | /* deal with the 3rd 32 bits */ | |
9634 | LDo_3rd_32_bits: | |
9635 | movl accum_1,%edx /* get the reduced num */ | |
9636 | movl accum_0,%eax | |
9637 | ||
9638 | /* need to check for possible subsequent overflow */ | |
9639 | cmpl SIGH(%ebx),%edx /* denom*/ | |
9640 | jb LRound_prep | |
9641 | ja LPrevent_3rd_overflow | |
9642 | ||
9643 | cmpl SIGL(%ebx),%eax /* denom */ | |
9644 | jb LRound_prep | |
9645 | ||
9646 | LPrevent_3rd_overflow: | |
9647 | /* prevent overflow */ | |
9648 | subl SIGL(%ebx),%eax | |
9649 | sbbl SIGH(%ebx),%edx | |
9650 | movl %edx,accum_1 | |
9651 | movl %eax,accum_0 | |
9652 | ||
9653 | addl $1,result_1 /* Reflect the subtraction in the answer */ | |
9654 | adcl $0,result_2 | |
9655 | jne LRound_prep | |
9656 | jnc LRound_prep | |
9657 | ||
9658 | /* This is a tricky spot, there is an overflow of the answer */ | |
9659 | movb $255,ovfl_flag /* Overflow -> 1.000 */ | |
9660 | ||
9661 | LRound_prep: | |
9662 | /* Prepare for rounding. | |
9663 | // To test for rounding, we just need to compare 2*accum with the | |
9664 | // denom. */ | |
9665 | movl accum_0,%ecx | |
9666 | movl accum_1,%edx | |
9667 | movl %ecx,%eax | |
9668 | orl %edx,%eax | |
9669 | jz LRound_ovfl /* The accumulator contains zero.*/ | |
9670 | ||
9671 | /* Multiply by 2 */ | |
9672 | clc | |
9673 | rcll $1,%ecx | |
9674 | rcll $1,%edx | |
9675 | jc LRound_large /* No need to compare, denom smaller */ | |
9676 | ||
9677 | subl SIGL(%ebx),%ecx | |
9678 | sbbl SIGH(%ebx),%edx | |
9679 | jnc LRound_not_small | |
9680 | ||
9681 | movl $0x70000000,%eax /* Denom was larger */ | |
9682 | jmp LRound_ovfl | |
9683 | ||
9684 | LRound_not_small: | |
9685 | jnz LRound_large | |
9686 | ||
9687 | movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */ | |
9688 | jmp LRound_ovfl | |
9689 | ||
9690 | LRound_large: | |
9691 | movl $0xff000000,%eax /* Denom was smaller */ | |
9692 | ||
9693 | LRound_ovfl: | |
9694 | /* We are now ready to deal with rounding, but first we must get | |
9695 | the bits properly aligned */ | |
9696 | testb $255,ovfl_flag /* was the num > denom ? */ | |
9697 | je LRound_precision | |
9698 | ||
9699 | incl EXP(%edi) | |
9700 | ||
9701 | /* shift the mantissa right one bit */ | |
9702 | stc /* Will set the ms bit */ | |
9703 | rcrl result_2 | |
9704 | rcrl result_1 | |
9705 | rcrl %eax | |
9706 | ||
9707 | /* Round the result as required */ | |
9708 | LRound_precision: | |
9709 | decl EXP(%edi) /* binary point between 1st & 2nd bits */ | |
9710 | ||
9711 | movl %eax,%edx | |
9712 | movl result_1,%ebx | |
9713 | movl result_2,%eax | |
9714 | jmp FPU_round | |
9715 | ||
9716 | ||
9717 | #ifdef PARANOID | |
9718 | /* The logic is wrong if we got here */ | |
9719 | L_bugged: | |
9720 | pushl EX_INTERNAL|0x202 | |
9721 | call EXCEPTION | |
9722 | pop %ebx | |
9723 | jmp L_exit | |
9724 | ||
9725 | L_bugged_1: | |
9726 | pushl EX_INTERNAL|0x203 | |
9727 | call EXCEPTION | |
9728 | pop %ebx | |
9729 | jmp L_exit | |
9730 | ||
9731 | L_bugged_2: | |
9732 | pushl EX_INTERNAL|0x204 | |
9733 | call EXCEPTION | |
9734 | pop %ebx | |
9735 | jmp L_exit | |
9736 | ||
9737 | L_exit: | |
9738 | popl %ebx | |
9739 | popl %edi | |
9740 | popl %esi | |
9741 | ||
9742 | leave | |
9743 | ret | |
9744 | #endif PARANOID | |
9745 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/div_small.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 5753 5462505570 12726\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "div_small.S" | |
9746 | /* | |
9747 | * div_small.S | |
9748 | * | |
9749 | * Divide a 64 bit integer by a 32 bit integer & return remainder. | |
9750 | * | |
9751 | * | |
9752 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
9753 | * Vic 3163, Australia. | |
9754 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
9755 | * All rights reserved. | |
9756 | * | |
9757 | * This copyright notice covers the redistribution and use of the | |
9758 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
9759 | * in the 386BSD operating system. Any other use is not permitted | |
9760 | * under this copyright. | |
9761 | * | |
9762 | * Redistribution and use in source and binary forms, with or without | |
9763 | * modification, are permitted provided that the following conditions | |
9764 | * are met: | |
9765 | * 1. Redistributions of source code must retain the above copyright | |
9766 | * notice, this list of conditions and the following disclaimer. | |
9767 | * 2. Redistributions in binary form must include information specifying | |
9768 | * that source code for the emulator is freely available and include | |
9769 | * either: | |
9770 | * a) an offer to provide the source code for a nominal distribution | |
9771 | * fee, or | |
9772 | * b) list at least two alternative methods whereby the source | |
9773 | * can be obtained, e.g. a publically accessible bulletin board | |
9774 | * and an anonymous ftp site from which the software can be | |
9775 | * downloaded. | |
9776 | * 3. All advertising materials specifically mentioning features or use of | |
9777 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
9778 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
9779 | * products derived from this software without specific prior written | |
9780 | * permission. | |
9781 | * | |
9782 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
9783 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
9784 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
9785 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
9786 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
9787 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
9788 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
9789 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
9790 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
9791 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
9792 | * | |
9793 | */ | |
9794 | ||
9795 | /*---------------------------------------------------------------------------+ | |
9796 | | unsigned long div_small(unsigned long long *x, unsigned long y) | | |
9797 | +---------------------------------------------------------------------------*/ | |
9798 | ||
9799 | #include "fpu_asm.h" | |
9800 | ||
9801 | .text | |
9802 | .align 2,144 | |
9803 | ||
9804 | .globl _div_small | |
9805 | ||
9806 | _div_small: | |
9807 | pushl %ebp | |
9808 | movl %esp,%ebp | |
9809 | ||
9810 | pushl %esi | |
9811 | ||
9812 | movl PARAM1,%esi /* pointer to num */ | |
9813 | movl PARAM2,%ecx /* The denominator */ | |
9814 | ||
9815 | movl 4(%esi),%eax /* Get the current num msw */ | |
9816 | xorl %edx,%edx | |
9817 | divl %ecx | |
9818 | ||
9819 | movl %eax,4(%esi) | |
9820 | ||
9821 | movl (%esi),%eax /* Get the num lsw */ | |
9822 | divl %ecx | |
9823 | ||
9824 | movl %eax,(%esi) | |
9825 | ||
9826 | movl %edx,%eax /* Return the remainder in eax */ | |
9827 | ||
9828 | popl %esi | |
9829 | ||
9830 | leave | |
9831 | ret | |
9832 | ||
9833 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/poly_div.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 6731 5462505570 12576\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "poly_div.S" | |
9834 | /* | |
9835 | * poly_div.S | |
9836 | * | |
9837 | * A set of functions to divide 64 bit integers by fixed numbers. | |
9838 | * | |
9839 | * | |
9840 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
9841 | * Vic 3163, Australia. | |
9842 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
9843 | * All rights reserved. | |
9844 | * | |
9845 | * This copyright notice covers the redistribution and use of the | |
9846 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
9847 | * in the 386BSD operating system. Any other use is not permitted | |
9848 | * under this copyright. | |
9849 | * | |
9850 | * Redistribution and use in source and binary forms, with or without | |
9851 | * modification, are permitted provided that the following conditions | |
9852 | * are met: | |
9853 | * 1. Redistributions of source code must retain the above copyright | |
9854 | * notice, this list of conditions and the following disclaimer. | |
9855 | * 2. Redistributions in binary form must include information specifying | |
9856 | * that source code for the emulator is freely available and include | |
9857 | * either: | |
9858 | * a) an offer to provide the source code for a nominal distribution | |
9859 | * fee, or | |
9860 | * b) list at least two alternative methods whereby the source | |
9861 | * can be obtained, e.g. a publically accessible bulletin board | |
9862 | * and an anonymous ftp site from which the software can be | |
9863 | * downloaded. | |
9864 | * 3. All advertising materials specifically mentioning features or use of | |
9865 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
9866 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
9867 | * products derived from this software without specific prior written | |
9868 | * permission. | |
9869 | * | |
9870 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
9871 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
9872 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
9873 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
9874 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
9875 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
9876 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
9877 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
9878 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
9879 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
9880 | * | |
9881 | */ | |
9882 | ||
9883 | #include "fpu_asm.h" | |
9884 | ||
9885 | .text | |
9886 | ||
9887 | /*---------------------------------------------------------------------------*/ | |
9888 | .align 2,144 | |
9889 | .globl _poly_div2 | |
9890 | _poly_div2: | |
9891 | pushl %ebp | |
9892 | movl %esp,%ebp | |
9893 | ||
9894 | movl PARAM1,%ecx | |
9895 | movw (%ecx),%ax | |
9896 | ||
9897 | shrl $1,4(%ecx) | |
9898 | rcrl $1,(%ecx) | |
9899 | ||
9900 | testw $1,%ax | |
9901 | je poly_div2_exit | |
9902 | ||
9903 | addl $1,(%ecx) | |
9904 | adcl $0,4(%ecx) | |
9905 | poly_div2_exit: | |
9906 | ||
9907 | leave | |
9908 | ret | |
9909 | /*---------------------------------------------------------------------------*/ | |
9910 | .align 2,144 | |
9911 | .globl _poly_div4 | |
9912 | _poly_div4: | |
9913 | pushl %ebp | |
9914 | movl %esp,%ebp | |
9915 | ||
9916 | movl PARAM1,%ecx | |
9917 | movw (%ecx),%ax | |
9918 | ||
9919 | movl 4(%ecx),%edx | |
9920 | shll $30,%edx | |
9921 | ||
9922 | shrl $2,4(%ecx) | |
9923 | shrl $2,(%ecx) | |
9924 | ||
9925 | orl %edx,(%ecx) | |
9926 | ||
9927 | testw $2,%ax | |
9928 | je poly_div4_exit | |
9929 | ||
9930 | addl $1,(%ecx) | |
9931 | adcl $0,4(%ecx) | |
9932 | poly_div4_exit: | |
9933 | ||
9934 | leave | |
9935 | ret | |
9936 | /*---------------------------------------------------------------------------*/ | |
9937 | .align 2,144 | |
9938 | .globl _poly_div16 | |
9939 | _poly_div16: | |
9940 | pushl %ebp | |
9941 | movl %esp,%ebp | |
9942 | ||
9943 | movl PARAM1,%ecx | |
9944 | movw (%ecx),%ax | |
9945 | ||
9946 | movl 4(%ecx),%edx | |
9947 | shll $28,%edx | |
9948 | ||
9949 | shrl $4,4(%ecx) | |
9950 | shrl $4,(%ecx) | |
9951 | ||
9952 | orl %edx,(%ecx) | |
9953 | ||
9954 | testw $8,%ax | |
9955 | je poly_div16_exit | |
9956 | ||
9957 | addl $1,(%ecx) | |
9958 | adcl $0,4(%ecx) | |
9959 | poly_div16_exit: | |
9960 | ||
9961 | leave | |
9962 | ret | |
9963 | /*---------------------------------------------------------------------------*/ | |
9964 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/polynomial.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 10713 5462505570 13147\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
9965 | * polynomial.S | |
9966 | * | |
9967 | * Fixed point arithmetic polynomial evaluation. | |
9968 | * | |
9969 | * Call from C as: | |
9970 | * void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2], | |
9971 | * int n) | |
9972 | * | |
9973 | * Computes: | |
9974 | * terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x | |
9975 | * The result is returned in accum. | |
9976 | * | |
9977 | * | |
9978 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
9979 | * Vic 3163, Australia. | |
9980 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
9981 | * All rights reserved. | |
9982 | * | |
9983 | * This copyright notice covers the redistribution and use of the | |
9984 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
9985 | * in the 386BSD operating system. Any other use is not permitted | |
9986 | * under this copyright. | |
9987 | * | |
9988 | * Redistribution and use in source and binary forms, with or without | |
9989 | * modification, are permitted provided that the following conditions | |
9990 | * are met: | |
9991 | * 1. Redistributions of source code must retain the above copyright | |
9992 | * notice, this list of conditions and the following disclaimer. | |
9993 | * 2. Redistributions in binary form must include information specifying | |
9994 | * that source code for the emulator is freely available and include | |
9995 | * either: | |
9996 | * a) an offer to provide the source code for a nominal distribution | |
9997 | * fee, or | |
9998 | * b) list at least two alternative methods whereby the source | |
9999 | * can be obtained, e.g. a publically accessible bulletin board | |
10000 | * and an anonymous ftp site from which the software can be | |
10001 | * downloaded. | |
10002 | * 3. All advertising materials specifically mentioning features or use of | |
10003 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
10004 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
10005 | * products derived from this software without specific prior written | |
10006 | * permission. | |
10007 | * | |
10008 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
10009 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
10010 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
10011 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
10012 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
10013 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
10014 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
10015 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
10016 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
10017 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
10018 | * | |
10019 | */ | |
10020 | ||
10021 | .file "fpolynom.s" | |
10022 | ||
10023 | #include "fpu_asm.h" | |
10024 | ||
10025 | ||
10026 | /* #define EXTRA_PRECISE*/ | |
10027 | ||
10028 | #define TERM_SIZE $8 | |
10029 | ||
10030 | ||
10031 | .text | |
10032 | .align 2,144 | |
10033 | .globl _polynomial | |
10034 | _polynomial: | |
10035 | pushl %ebp | |
10036 | movl %esp,%ebp | |
10037 | subl $32,%esp | |
10038 | pushl %esi | |
10039 | pushl %edi | |
10040 | pushl %ebx | |
10041 | ||
10042 | movl PARAM1,%esi /* accum */ | |
10043 | movl PARAM2,%edi /* x */ | |
10044 | movl PARAM3,%ebx /* terms */ | |
10045 | movl PARAM4,%ecx /* n */ | |
10046 | ||
10047 | movl TERM_SIZE,%eax | |
10048 | mull %ecx | |
10049 | movl %eax,%ecx | |
10050 | ||
10051 | movl 4(%ebx,%ecx,1),%edx /* terms[n] */ | |
10052 | movl %edx,-20(%ebp) | |
10053 | movl (%ebx,%ecx,1),%edx /* terms[n] */ | |
10054 | movl %edx,-24(%ebp) | |
10055 | xor %eax,%eax | |
10056 | movl %eax,-28(%ebp) | |
10057 | ||
10058 | subl TERM_SIZE,%ecx | |
10059 | js L_accum_done | |
10060 | ||
10061 | L_accum_loop: | |
10062 | xor %eax,%eax | |
10063 | movl %eax,-4(%ebp) | |
10064 | movl %eax,-8(%ebp) | |
10065 | ||
10066 | #ifdef EXTRA_PRECISE | |
10067 | movl -28(%ebp),%eax | |
10068 | mull 4(%edi) /* x ms long */ | |
10069 | movl %edx,-12(%ebp) | |
10070 | #endif EXTRA_PRECISE | |
10071 | ||
10072 | movl -24(%ebp),%eax | |
10073 | mull (%edi) /* x ls long */ | |
10074 | /* movl %eax,-16(%ebp) */ /* Not needed */ | |
10075 | addl %edx,-12(%ebp) | |
10076 | adcl $0,-8(%ebp) | |
10077 | ||
10078 | movl -24(%ebp),%eax | |
10079 | mull 4(%edi) /* x ms long */ | |
10080 | addl %eax,-12(%ebp) | |
10081 | adcl %edx,-8(%ebp) | |
10082 | adcl $0,-4(%ebp) | |
10083 | ||
10084 | movl -20(%ebp),%eax | |
10085 | mull (%edi) | |
10086 | addl %eax,-12(%ebp) | |
10087 | adcl %edx,-8(%ebp) | |
10088 | adcl $0,-4(%ebp) | |
10089 | ||
10090 | movl -20(%ebp),%eax | |
10091 | mull 4(%edi) | |
10092 | addl %eax,-8(%ebp) | |
10093 | adcl %edx,-4(%ebp) | |
10094 | ||
10095 | /* Now add the next term */ | |
10096 | movl (%ebx,%ecx,1),%eax | |
10097 | addl %eax,-8(%ebp) | |
10098 | movl 4(%ebx,%ecx,1),%eax | |
10099 | adcl %eax,-4(%ebp) | |
10100 | ||
10101 | /* And put into the second register */ | |
10102 | movl -4(%ebp),%eax | |
10103 | movl %eax,-20(%ebp) | |
10104 | movl -8(%ebp),%eax | |
10105 | movl %eax,-24(%ebp) | |
10106 | ||
10107 | #ifdef EXTRA_PRECISE | |
10108 | movl -12(%ebp),%eax | |
10109 | movl %eax,-28(%ebp) | |
10110 | #else | |
10111 | testb $128,-25(%ebp) | |
10112 | je L_no_poly_round | |
10113 | ||
10114 | addl $1,-24(%ebp) | |
10115 | adcl $0,-20(%ebp) | |
10116 | L_no_poly_round: | |
10117 | #endif EXTRA_PRECISE | |
10118 | ||
10119 | subl TERM_SIZE,%ecx | |
10120 | jns L_accum_loop | |
10121 | ||
10122 | L_accum_done: | |
10123 | #ifdef EXTRA_PRECISE | |
10124 | /* And round the result */ | |
10125 | testb $128,-25(%ebp) | |
10126 | je L_poly_done | |
10127 | ||
10128 | addl $1,-24(%ebp) | |
10129 | adcl $0,-20(%ebp) | |
10130 | #endif EXTRA_PRECISE | |
10131 | ||
10132 | L_poly_done: | |
10133 | movl -24(%ebp),%eax | |
10134 | movl %eax,(%esi) | |
10135 | movl -20(%ebp),%eax | |
10136 | movl %eax,4(%esi) | |
10137 | ||
10138 | popl %ebx | |
10139 | popl %edi | |
10140 | popl %esi | |
10141 | leave | |
10142 | ret | |
10143 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_u_mul.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 11460 5462505570 12742\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "reg_u_mul.S" | |
10144 | /* | |
10145 | * reg_u_mul.S | |
10146 | * | |
10147 | * Core multiplication routine | |
10148 | * | |
10149 | * | |
10150 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
10151 | * Vic 3163, Australia. | |
10152 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
10153 | * All rights reserved. | |
10154 | * | |
10155 | * This copyright notice covers the redistribution and use of the | |
10156 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
10157 | * in the 386BSD operating system. Any other use is not permitted | |
10158 | * under this copyright. | |
10159 | * | |
10160 | * Redistribution and use in source and binary forms, with or without | |
10161 | * modification, are permitted provided that the following conditions | |
10162 | * are met: | |
10163 | * 1. Redistributions of source code must retain the above copyright | |
10164 | * notice, this list of conditions and the following disclaimer. | |
10165 | * 2. Redistributions in binary form must include information specifying | |
10166 | * that source code for the emulator is freely available and include | |
10167 | * either: | |
10168 | * a) an offer to provide the source code for a nominal distribution | |
10169 | * fee, or | |
10170 | * b) list at least two alternative methods whereby the source | |
10171 | * can be obtained, e.g. a publically accessible bulletin board | |
10172 | * and an anonymous ftp site from which the software can be | |
10173 | * downloaded. | |
10174 | * 3. All advertising materials specifically mentioning features or use of | |
10175 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
10176 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
10177 | * products derived from this software without specific prior written | |
10178 | * permission. | |
10179 | * | |
10180 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
10181 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
10182 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
10183 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
10184 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
10185 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
10186 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
10187 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
10188 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
10189 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
10190 | * | |
10191 | */ | |
10192 | ||
10193 | /*---------------------------------------------------------------------------+ | |
10194 | | Basic multiplication routine. | | |
10195 | | Does not check the resulting exponent for overflow/underflow | | |
10196 | | | | |
10197 | | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); | | |
10198 | | | | |
10199 | | Internal working is at approx 128 bits. | | |
10200 | | Result is rounded to nearest 53 or 64 bits, using "nearest or even". | | |
10201 | +---------------------------------------------------------------------------*/ | |
10202 | ||
10203 | #include "exception.h" | |
10204 | #include "fpu_asm.h" | |
10205 | #include "control_w.h" | |
10206 | ||
10207 | ||
10208 | .data | |
10209 | .align 2,0 | |
10210 | accum_0: | |
10211 | .long 0 | |
10212 | accum_1: | |
10213 | .long 0 | |
10214 | ||
10215 | ||
10216 | .text | |
10217 | .align 2,144 | |
10218 | ||
10219 | .globl _reg_u_mul | |
10220 | _reg_u_mul: | |
10221 | pushl %ebp | |
10222 | movl %esp,%ebp | |
10223 | pushl %esi | |
10224 | pushl %edi | |
10225 | pushl %ebx | |
10226 | ||
10227 | movl PARAM1,%esi | |
10228 | movl PARAM2,%edi | |
10229 | ||
10230 | #ifdef PARANOID | |
10231 | testl $0x80000000,SIGH(%esi) | |
10232 | jz L_bugged | |
10233 | testl $0x80000000,SIGH(%edi) | |
10234 | jz L_bugged | |
10235 | #endif PARANOID | |
10236 | ||
10237 | #ifdef DENORM_OPERAND | |
10238 | movl EXP(%esi),%eax | |
10239 | cmpl EXP_UNDER,%eax | |
10240 | jg xOp1_not_denorm | |
10241 | ||
10242 | call _denormal_operand | |
10243 | orl %eax,%eax | |
10244 | jnz FPU_Arith_exit | |
10245 | ||
10246 | xOp1_not_denorm: | |
10247 | movl EXP(%edi),%eax | |
10248 | cmpl EXP_UNDER,%eax | |
10249 | jg xOp2_not_denorm | |
10250 | ||
10251 | call _denormal_operand | |
10252 | orl %eax,%eax | |
10253 | jnz FPU_Arith_exit | |
10254 | ||
10255 | xOp2_not_denorm: | |
10256 | #endif DENORM_OPERAND | |
10257 | ||
10258 | xorl %ecx,%ecx | |
10259 | xorl %ebx,%ebx | |
10260 | ||
10261 | movl SIGL(%esi),%eax | |
10262 | mull SIGL(%edi) | |
10263 | movl %eax,accum_0 | |
10264 | movl %edx,accum_1 | |
10265 | ||
10266 | movl SIGL(%esi),%eax | |
10267 | mull SIGH(%edi) | |
10268 | addl %eax,accum_1 | |
10269 | adcl %edx,%ebx | |
10270 | /* adcl $0,%ecx *//* overflow here is not possible */ | |
10271 | ||
10272 | movl SIGH(%esi),%eax | |
10273 | mull SIGL(%edi) | |
10274 | addl %eax,accum_1 | |
10275 | adcl %edx,%ebx | |
10276 | adcl $0,%ecx | |
10277 | ||
10278 | movl SIGH(%esi),%eax | |
10279 | mull SIGH(%edi) | |
10280 | addl %eax,%ebx | |
10281 | adcl %edx,%ecx | |
10282 | ||
10283 | movl EXP(%esi),%eax /* Compute the exponent */ | |
10284 | addl EXP(%edi),%eax | |
10285 | subl EXP_BIAS-1,%eax | |
10286 | /* Have now finished with the sources */ | |
10287 | movl PARAM3,%edi /* Point to the destination */ | |
10288 | movl %eax,EXP(%edi) | |
10289 | ||
10290 | /* Now make sure that the result is normalized */ | |
10291 | testl $0x80000000,%ecx | |
10292 | jnz LResult_Normalised | |
10293 | ||
10294 | /* Normalize by shifting left one bit */ | |
10295 | shll $1,accum_0 | |
10296 | rcll $1,accum_1 | |
10297 | rcll $1,%ebx | |
10298 | rcll $1,%ecx | |
10299 | decl EXP(%edi) | |
10300 | ||
10301 | LResult_Normalised: | |
10302 | movl accum_0,%eax | |
10303 | movl accum_1,%edx | |
10304 | orl %eax,%eax | |
10305 | jz L_extent_zero | |
10306 | ||
10307 | orl $1,%edx | |
10308 | ||
10309 | L_extent_zero: | |
10310 | movl %ecx,%eax | |
10311 | jmp FPU_round | |
10312 | ||
10313 | ||
10314 | #ifdef PARANOID | |
10315 | L_bugged: | |
10316 | pushl EX_INTERNAL|0x205 | |
10317 | call EXCEPTION | |
10318 | pop %ebx | |
10319 | jmp L_exit | |
10320 | ||
10321 | L_exit: | |
10322 | popl %ebx | |
10323 | popl %edi | |
10324 | popl %esi | |
10325 | leave | |
10326 | ret | |
10327 | #endif PARANOID | |
10328 | ||
10329 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_u_sub.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 17550 5462505570 12744\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "reg_u_sub.S" | |
10330 | /* | |
10331 | * reg_u_sub.S | |
10332 | * | |
10333 | * Core floating point subtraction routine. | |
10334 | * | |
10335 | * Call from C as: | |
10336 | * void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | |
10337 | * int control_w) | |
10338 | * | |
10339 | * | |
10340 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
10341 | * Vic 3163, Australia. | |
10342 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
10343 | * All rights reserved. | |
10344 | * | |
10345 | * This copyright notice covers the redistribution and use of the | |
10346 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
10347 | * in the 386BSD operating system. Any other use is not permitted | |
10348 | * under this copyright. | |
10349 | * | |
10350 | * Redistribution and use in source and binary forms, with or without | |
10351 | * modification, are permitted provided that the following conditions | |
10352 | * are met: | |
10353 | * 1. Redistributions of source code must retain the above copyright | |
10354 | * notice, this list of conditions and the following disclaimer. | |
10355 | * 2. Redistributions in binary form must include information specifying | |
10356 | * that source code for the emulator is freely available and include | |
10357 | * either: | |
10358 | * a) an offer to provide the source code for a nominal distribution | |
10359 | * fee, or | |
10360 | * b) list at least two alternative methods whereby the source | |
10361 | * can be obtained, e.g. a publically accessible bulletin board | |
10362 | * and an anonymous ftp site from which the software can be | |
10363 | * downloaded. | |
10364 | * 3. All advertising materials specifically mentioning features or use of | |
10365 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
10366 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
10367 | * products derived from this software without specific prior written | |
10368 | * permission. | |
10369 | * | |
10370 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
10371 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
10372 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
10373 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
10374 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
10375 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
10376 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
10377 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
10378 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
10379 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
10380 | * | |
10381 | */ | |
10382 | ||
10383 | /* | |
10384 | | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ). | |
10385 | | Takes two valid reg f.p. numbers (TW_Valid), which are | |
10386 | | treated as unsigned numbers, | |
10387 | | and returns their difference as a TW_Valid or TW_Zero f.p. | |
10388 | | number. | |
10389 | | The first number (arg1) must be the larger. | |
10390 | | The returned number is normalized. | |
10391 | | Basic checks are performed if PARANOID is defined. | |
10392 | */ | |
10393 | ||
10394 | #include "exception.h" | |
10395 | #include "fpu_asm.h" | |
10396 | #include "control_w.h" | |
10397 | ||
10398 | .text | |
10399 | .align 2,144 | |
10400 | .globl _reg_u_sub | |
10401 | _reg_u_sub: | |
10402 | pushl %ebp | |
10403 | movl %esp,%ebp | |
10404 | pushl %esi | |
10405 | pushl %edi | |
10406 | pushl %ebx | |
10407 | ||
10408 | movl PARAM1,%esi /* source 1 */ | |
10409 | movl PARAM2,%edi /* source 2 */ | |
10410 | ||
10411 | #ifdef DENORM_OPERAND | |
10412 | cmpl EXP_UNDER,EXP(%esi) | |
10413 | jg xOp1_not_denorm | |
10414 | ||
10415 | call _denormal_operand | |
10416 | orl %eax,%eax | |
10417 | jnz FPU_Arith_exit | |
10418 | ||
10419 | xOp1_not_denorm: | |
10420 | cmpl EXP_UNDER,EXP(%edi) | |
10421 | jg xOp2_not_denorm | |
10422 | ||
10423 | call _denormal_operand | |
10424 | orl %eax,%eax | |
10425 | jnz FPU_Arith_exit | |
10426 | ||
10427 | xOp2_not_denorm: | |
10428 | #endif DENORM_OPERAND | |
10429 | ||
10430 | /* xorl %ecx,%ecx */ | |
10431 | movl EXP(%esi),%ecx | |
10432 | subl EXP(%edi),%ecx /* exp1 - exp2 */ | |
10433 | ||
10434 | #ifdef PARANOID | |
10435 | /* source 2 is always smaller than source 1 */ | |
10436 | /* jc L_bugged */ | |
10437 | js L_bugged_1 | |
10438 | ||
10439 | testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ | |
10440 | je L_bugged_2 | |
10441 | ||
10442 | testl $0x80000000,SIGH(%esi) | |
10443 | je L_bugged_2 | |
10444 | #endif PARANOID | |
10445 | ||
10446 | /*--------------------------------------+ | |
10447 | | Form a register holding the | | |
10448 | | smaller number | | |
10449 | +--------------------------------------*/ | |
10450 | movl SIGH(%edi),%eax /* register ms word */ | |
10451 | movl SIGL(%edi),%ebx /* register ls word */ | |
10452 | ||
10453 | movl PARAM3,%edi /* destination */ | |
10454 | movl EXP(%esi),%edx | |
10455 | movl %edx,EXP(%edi) /* Copy exponent to destination */ | |
10456 | movb SIGN(%esi),%dl | |
10457 | movb %dl,SIGN(%edi) /* Copy the sign from the first arg */ | |
10458 | ||
10459 | xorl %edx,%edx /* register extension */ | |
10460 | ||
10461 | /*--------------------------------------+ | |
10462 | | Shift the temporary register | | |
10463 | | right the required number of | | |
10464 | | places. | | |
10465 | +--------------------------------------*/ | |
10466 | L_shift_r: | |
10467 | cmpl $32,%ecx /* shrd only works for 0..31 bits */ | |
10468 | jnc L_more_than_31 | |
10469 | ||
10470 | /* less than 32 bits */ | |
10471 | shrd %cl,%ebx,%edx | |
10472 | shrd %cl,%eax,%ebx | |
10473 | shr %cl,%eax | |
10474 | jmp L_shift_done | |
10475 | ||
10476 | L_more_than_31: | |
10477 | cmpl $64,%ecx | |
10478 | jnc L_more_than_63 | |
10479 | ||
10480 | subb $32,%cl | |
10481 | jz L_exactly_32 | |
10482 | ||
10483 | shrd %cl,%eax,%edx | |
10484 | shr %cl,%eax | |
10485 | orl %ebx,%ebx | |
10486 | jz L_more_31_no_low /* none of the lowest bits is set */ | |
10487 | ||
10488 | orl $1,%edx /* record the fact in the extension */ | |
10489 | ||
10490 | L_more_31_no_low: | |
10491 | movl %eax,%ebx | |
10492 | xorl %eax,%eax | |
10493 | jmp L_shift_done | |
10494 | ||
10495 | L_exactly_32: | |
10496 | movl %ebx,%edx | |
10497 | movl %eax,%ebx | |
10498 | xorl %eax,%eax | |
10499 | jmp L_shift_done | |
10500 | ||
10501 | L_more_than_63: | |
10502 | cmpw $65,%cx | |
10503 | jnc L_more_than_64 | |
10504 | ||
10505 | /* Shift right by 64 bits */ | |
10506 | movl %eax,%edx | |
10507 | orl %ebx,%ebx | |
10508 | jz L_more_63_no_low | |
10509 | ||
10510 | orl $1,%edx | |
10511 | jmp L_more_63_no_low | |
10512 | ||
10513 | L_more_than_64: | |
10514 | jne L_more_than_65 | |
10515 | ||
10516 | /* Shift right by 65 bits */ | |
10517 | /* Carry is clear if we get here */ | |
10518 | movl %eax,%edx | |
10519 | rcrl %edx | |
10520 | jnc L_shift_65_nc | |
10521 | ||
10522 | orl $1,%edx | |
10523 | jmp L_more_63_no_low | |
10524 | ||
10525 | L_shift_65_nc: | |
10526 | orl %ebx,%ebx | |
10527 | jz L_more_63_no_low | |
10528 | ||
10529 | orl $1,%edx | |
10530 | jmp L_more_63_no_low | |
10531 | ||
10532 | L_more_than_65: | |
10533 | movl $1,%edx /* The shifted nr always at least one '1' */ | |
10534 | ||
10535 | L_more_63_no_low: | |
10536 | xorl %ebx,%ebx | |
10537 | xorl %eax,%eax | |
10538 | ||
10539 | L_shift_done: | |
10540 | L_subtr: | |
10541 | /*------------------------------+ | |
10542 | | Do the subtraction | | |
10543 | +------------------------------*/ | |
10544 | xorl %ecx,%ecx | |
10545 | subl %edx,%ecx | |
10546 | movl %ecx,%edx | |
10547 | movl SIGL(%esi),%ecx | |
10548 | sbbl %ebx,%ecx | |
10549 | movl %ecx,%ebx | |
10550 | movl SIGH(%esi),%ecx | |
10551 | sbbl %eax,%ecx | |
10552 | movl %ecx,%eax | |
10553 | ||
10554 | #ifdef PARANOID | |
10555 | /* We can never get a borrow */ | |
10556 | jc L_bugged | |
10557 | #endif PARANOID | |
10558 | ||
10559 | /*--------------------------------------+ | |
10560 | | Normalize the result | | |
10561 | +--------------------------------------*/ | |
10562 | testl $0x80000000,%eax | |
10563 | jnz L_round /* no shifting needed */ | |
10564 | ||
10565 | orl %eax,%eax | |
10566 | jnz L_shift_1 /* shift left 1 - 31 bits */ | |
10567 | ||
10568 | orl %ebx,%ebx | |
10569 | jnz L_shift_32 /* shift left 32 - 63 bits */ | |
10570 | ||
10571 | /* A rare case, the only one which is non-zero if we got here | |
10572 | // is: 1000000 .... 0000 | |
10573 | // -0111111 .... 1111 1 | |
10574 | // -------------------- | |
10575 | // 0000000 .... 0000 1 */ | |
10576 | ||
10577 | cmpl $0x80000000,%edx | |
10578 | jnz L_must_be_zero | |
10579 | ||
10580 | /* Shift left 64 bits */ | |
10581 | subl $64,EXP(%edi) | |
10582 | movl %edx,%eax | |
10583 | jmp L_store | |
10584 | ||
10585 | L_must_be_zero: | |
10586 | #ifdef PARANOID | |
10587 | orl %edx,%edx | |
10588 | jnz L_bugged_3 | |
10589 | #endif PARANOID | |
10590 | ||
10591 | /* The result is zero */ | |
10592 | movb TW_Zero,TAG(%edi) | |
10593 | movl $0,EXP(%edi) /* exponent */ | |
10594 | movl $0,SIGL(%edi) | |
10595 | movl $0,SIGH(%edi) | |
10596 | jmp L_exit /* Does not underflow */ | |
10597 | ||
10598 | L_shift_32: | |
10599 | movl %ebx,%eax | |
10600 | movl %edx,%ebx | |
10601 | movl $0,%edx | |
10602 | subl $32,EXP(%edi) /* Can get underflow here */ | |
10603 | ||
10604 | /* We need to shift left by 1 - 31 bits */ | |
10605 | L_shift_1: | |
10606 | bsrl %eax,%ecx /* get the required shift in %ecx */ | |
10607 | subl $31,%ecx | |
10608 | negl %ecx | |
10609 | shld %cl,%ebx,%eax | |
10610 | shld %cl,%edx,%ebx | |
10611 | shl %cl,%edx | |
10612 | subl %ecx,EXP(%edi) /* Can get underflow here */ | |
10613 | ||
10614 | L_round: | |
10615 | jmp FPU_round /* Round the result */ | |
10616 | ||
10617 | ||
10618 | #ifdef PARANOID | |
10619 | L_bugged_1: | |
10620 | pushl EX_INTERNAL|0x206 | |
10621 | call EXCEPTION | |
10622 | pop %ebx | |
10623 | jmp L_exit | |
10624 | ||
10625 | L_bugged_2: | |
10626 | pushl EX_INTERNAL|0x209 | |
10627 | call EXCEPTION | |
10628 | pop %ebx | |
10629 | jmp L_exit | |
10630 | ||
10631 | L_bugged_3: | |
10632 | pushl EX_INTERNAL|0x210 | |
10633 | call EXCEPTION | |
10634 | pop %ebx | |
10635 | jmp L_exit | |
10636 | ||
10637 | L_bugged_4: | |
10638 | pushl EX_INTERNAL|0x211 | |
10639 | call EXCEPTION | |
10640 | pop %ebx | |
10641 | jmp L_exit | |
10642 | ||
10643 | L_bugged: | |
10644 | pushl EX_INTERNAL|0x212 | |
10645 | call EXCEPTION | |
10646 | pop %ebx | |
10647 | jmp L_exit | |
10648 | #endif PARANOID | |
10649 | ||
10650 | ||
10651 | L_store: | |
10652 | /*------------------------------+ | |
10653 | | Store the result | | |
10654 | +------------------------------*/ | |
10655 | movl %eax,SIGH(%edi) | |
10656 | movl %ebx,SIGL(%edi) | |
10657 | ||
10658 | movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */ | |
10659 | ||
10660 | cmpl EXP_UNDER,EXP(%edi) | |
10661 | jle L_underflow | |
10662 | ||
10663 | L_exit: | |
10664 | popl %ebx | |
10665 | popl %edi | |
10666 | popl %esi | |
10667 | leave | |
10668 | ret | |
10669 | ||
10670 | ||
10671 | L_underflow: | |
10672 | push %edi | |
10673 | call _arith_underflow | |
10674 | pop %ebx | |
10675 | jmp L_exit | |
10676 | ||
10677 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/wm_shrx.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 16475 5462505570 12466\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "wm_shrx.S" | |
10678 | /* | |
10679 | * wm_shrx.S | |
10680 | * | |
10681 | * 64 bit right shift functions | |
10682 | * | |
10683 | * Call from C as: | |
10684 | * unsigned shrx(void *arg1, unsigned arg2) | |
10685 | * and | |
10686 | * unsigned shrxs(void *arg1, unsigned arg2) | |
10687 | * | |
10688 | * | |
10689 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
10690 | * Vic 3163, Australia. | |
10691 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
10692 | * All rights reserved. | |
10693 | * | |
10694 | * This copyright notice covers the redistribution and use of the | |
10695 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
10696 | * in the 386BSD operating system. Any other use is not permitted | |
10697 | * under this copyright. | |
10698 | * | |
10699 | * Redistribution and use in source and binary forms, with or without | |
10700 | * modification, are permitted provided that the following conditions | |
10701 | * are met: | |
10702 | * 1. Redistributions of source code must retain the above copyright | |
10703 | * notice, this list of conditions and the following disclaimer. | |
10704 | * 2. Redistributions in binary form must include information specifying | |
10705 | * that source code for the emulator is freely available and include | |
10706 | * either: | |
10707 | * a) an offer to provide the source code for a nominal distribution | |
10708 | * fee, or | |
10709 | * b) list at least two alternative methods whereby the source | |
10710 | * can be obtained, e.g. a publically accessible bulletin board | |
10711 | * and an anonymous ftp site from which the software can be | |
10712 | * downloaded. | |
10713 | * 3. All advertising materials specifically mentioning features or use of | |
10714 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
10715 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
10716 | * products derived from this software without specific prior written | |
10717 | * permission. | |
10718 | * | |
10719 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
10720 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
10721 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
10722 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
10723 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
10724 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
10725 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
10726 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
10727 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
10728 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
10729 | * | |
10730 | */ | |
10731 | ||
10732 | ||
10733 | #include "fpu_asm.h" | |
10734 | ||
10735 | .text | |
10736 | .align 2,144 | |
10737 | ||
10738 | /*---------------------------------------------------------------------------+ | |
10739 | | unsigned shrx(void *arg1, unsigned arg2) | | |
10740 | | | | |
10741 | | Extended shift right function. | | |
10742 | | Fastest for small shifts. | | |
10743 | | Shifts the 64 bit quantity pointed to by the first arg (arg1) | | |
10744 | | right by the number of bits specified by the second arg (arg2). | | |
10745 | | Forms a 96 bit quantity from the 64 bit arg and eax: | | |
10746 | | [ 64 bit arg ][ eax ] | | |
10747 | | shift right ---------> | | |
10748 | | The eax register is initialized to 0 before the shifting. | | |
10749 | | Results returned in the 64 bit arg and eax. | | |
10750 | +---------------------------------------------------------------------------*/ | |
10751 | ||
10752 | .globl _shrx | |
10753 | ||
10754 | _shrx: | |
10755 | push %ebp | |
10756 | movl %esp,%ebp | |
10757 | pushl %esi | |
10758 | movl PARAM2,%ecx | |
10759 | movl PARAM1,%esi | |
10760 | cmpl $32,%ecx /* shrd only works for 0..31 bits */ | |
10761 | jnc L_more_than_31 | |
10762 | ||
10763 | /* less than 32 bits */ | |
10764 | pushl %ebx | |
10765 | movl (%esi),%ebx /* lsl */ | |
10766 | movl 4(%esi),%edx /* msl */ | |
10767 | xorl %eax,%eax /* extension */ | |
10768 | shrd %cl,%ebx,%eax | |
10769 | shrd %cl,%edx,%ebx | |
10770 | shr %cl,%edx | |
10771 | movl %ebx,(%esi) | |
10772 | movl %edx,4(%esi) | |
10773 | popl %ebx | |
10774 | popl %esi | |
10775 | leave | |
10776 | ret | |
10777 | ||
10778 | L_more_than_31: | |
10779 | cmpl $64,%ecx | |
10780 | jnc L_more_than_63 | |
10781 | ||
10782 | subb $32,%cl | |
10783 | movl (%esi),%eax /* lsl */ | |
10784 | movl 4(%esi),%edx /* msl */ | |
10785 | shrd %cl,%edx,%eax | |
10786 | shr %cl,%edx | |
10787 | movl %edx,(%esi) | |
10788 | movl $0,4(%esi) | |
10789 | popl %esi | |
10790 | leave | |
10791 | ret | |
10792 | ||
10793 | L_more_than_63: | |
10794 | cmpl $96,%ecx | |
10795 | jnc L_more_than_95 | |
10796 | ||
10797 | subb $64,%cl | |
10798 | movl 4(%esi),%eax /* msl */ | |
10799 | shr %cl,%eax | |
10800 | xorl %edx,%edx | |
10801 | movl %edx,(%esi) | |
10802 | movl %edx,4(%esi) | |
10803 | popl %esi | |
10804 | leave | |
10805 | ret | |
10806 | ||
10807 | L_more_than_95: | |
10808 | xorl %eax,%eax | |
10809 | movl %eax,(%esi) | |
10810 | movl %eax,4(%esi) | |
10811 | popl %esi | |
10812 | leave | |
10813 | ret | |
10814 | ||
10815 | ||
10816 | /*---------------------------------------------------------------------------+ | |
10817 | | unsigned shrxs(void *arg1, unsigned arg2) | | |
10818 | | | | |
10819 | | Extended shift right function (optimized for small floating point | | |
10820 | | integers). | | |
10821 | | Shifts the 64 bit quantity pointed to by the first arg (arg1) | | |
10822 | | right by the number of bits specified by the second arg (arg2). | | |
10823 | | Forms a 96 bit quantity from the 64 bit arg and eax: | | |
10824 | | [ 64 bit arg ][ eax ] | | |
10825 | | shift right ---------> | | |
10826 | | The eax register is initialized to 0 before the shifting. | | |
10827 | | The lower 8 bits of eax are lost and replaced by a flag which is | | |
10828 | | set (to 0x01) if any bit, apart from the first one, is set in the | | |
10829 | | part which has been shifted out of the arg. | | |
10830 | | Results returned in the 64 bit arg and eax. | | |
10831 | +---------------------------------------------------------------------------*/ | |
10832 | .globl _shrxs | |
10833 | _shrxs: | |
10834 | push %ebp | |
10835 | movl %esp,%ebp | |
10836 | pushl %esi | |
10837 | pushl %ebx | |
10838 | movl PARAM2,%ecx | |
10839 | movl PARAM1,%esi | |
10840 | cmpl $64,%ecx /* shrd only works for 0..31 bits */ | |
10841 | jnc Ls_more_than_63 | |
10842 | ||
10843 | cmpl $32,%ecx /* shrd only works for 0..31 bits */ | |
10844 | jc Ls_less_than_32 | |
10845 | ||
10846 | /* We got here without jumps by assuming that the most common requirement | |
10847 | is for small integers */ | |
10848 | /* Shift by [32..63] bits */ | |
10849 | subb $32,%cl | |
10850 | movl (%esi),%eax /* lsl */ | |
10851 | movl 4(%esi),%edx /* msl */ | |
10852 | xorl %ebx,%ebx | |
10853 | shrd %cl,%eax,%ebx | |
10854 | shrd %cl,%edx,%eax | |
10855 | shr %cl,%edx | |
10856 | orl %ebx,%ebx /* test these 32 bits */ | |
10857 | setne %bl | |
10858 | test $0x7fffffff,%eax /* and 31 bits here */ | |
10859 | setne %bh | |
10860 | orw %bx,%bx /* Any of the 63 bit set ? */ | |
10861 | setne %al | |
10862 | movl %edx,(%esi) | |
10863 | movl $0,4(%esi) | |
10864 | popl %ebx | |
10865 | popl %esi | |
10866 | leave | |
10867 | ret | |
10868 | ||
10869 | /* Shift by [0..31] bits */ | |
10870 | Ls_less_than_32: | |
10871 | movl (%esi),%ebx /* lsl */ | |
10872 | movl 4(%esi),%edx /* msl */ | |
10873 | xorl %eax,%eax /* extension */ | |
10874 | shrd %cl,%ebx,%eax | |
10875 | shrd %cl,%edx,%ebx | |
10876 | shr %cl,%edx | |
10877 | test $0x7fffffff,%eax /* only need to look at eax here */ | |
10878 | setne %al | |
10879 | movl %ebx,(%esi) | |
10880 | movl %edx,4(%esi) | |
10881 | popl %ebx | |
10882 | popl %esi | |
10883 | leave | |
10884 | ret | |
10885 | ||
10886 | /* Shift by [64..95] bits */ | |
10887 | Ls_more_than_63: | |
10888 | cmpl $96,%ecx | |
10889 | jnc Ls_more_than_95 | |
10890 | ||
10891 | subb $64,%cl | |
10892 | movl (%esi),%ebx /* lsl */ | |
10893 | movl 4(%esi),%eax /* msl */ | |
10894 | xorl %edx,%edx /* extension */ | |
10895 | shrd %cl,%ebx,%edx | |
10896 | shrd %cl,%eax,%ebx | |
10897 | shr %cl,%eax | |
10898 | orl %ebx,%edx | |
10899 | setne %bl | |
10900 | test $0x7fffffff,%eax /* only need to look at eax here */ | |
10901 | setne %bh | |
10902 | orw %bx,%bx | |
10903 | setne %al | |
10904 | xorl %edx,%edx | |
10905 | movl %edx,(%esi) /* set to zero */ | |
10906 | movl %edx,4(%esi) /* set to zero */ | |
10907 | popl %ebx | |
10908 | popl %esi | |
10909 | leave | |
10910 | ret | |
10911 | ||
10912 | Ls_more_than_95: | |
10913 | /* Shift by [96..inf) bits */ | |
10914 | xorl %eax,%eax | |
10915 | movl (%esi),%ebx | |
10916 | orl 4(%esi),%ebx | |
10917 | setne %al | |
10918 | xorl %ebx,%ebx | |
10919 | movl %ebx,(%esi) | |
10920 | movl %ebx,4(%esi) | |
10921 | popl %ebx | |
10922 | popl %esi | |
10923 | leave | |
10924 | ret | |
10925 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/wm_sqrt.s\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 0 \0 26276 5462505570 12473\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0wheel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 .file "wm_sqrt.S" | |
10926 | /* | |
10927 | * wm_sqrt.S | |
10928 | * | |
10929 | * Fixed point arithmetic square root evaluation. | |
10930 | * | |
10931 | * Call from C as: | |
10932 | * void wm_sqrt(FPU_REG *n, unsigned int control_word) | |
10933 | * | |
10934 | * | |
10935 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
10936 | * Vic 3163, Australia. | |
10937 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
10938 | * All rights reserved. | |
10939 | * | |
10940 | * This copyright notice covers the redistribution and use of the | |
10941 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
10942 | * in the 386BSD operating system. Any other use is not permitted | |
10943 | * under this copyright. | |
10944 | * | |
10945 | * Redistribution and use in source and binary forms, with or without | |
10946 | * modification, are permitted provided that the following conditions | |
10947 | * are met: | |
10948 | * 1. Redistributions of source code must retain the above copyright | |
10949 | * notice, this list of conditions and the following disclaimer. | |
10950 | * 2. Redistributions in binary form must include information specifying | |
10951 | * that source code for the emulator is freely available and include | |
10952 | * either: | |
10953 | * a) an offer to provide the source code for a nominal distribution | |
10954 | * fee, or | |
10955 | * b) list at least two alternative methods whereby the source | |
10956 | * can be obtained, e.g. a publically accessible bulletin board | |
10957 | * and an anonymous ftp site from which the software can be | |
10958 | * downloaded. | |
10959 | * 3. All advertising materials specifically mentioning features or use of | |
10960 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
10961 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
10962 | * products derived from this software without specific prior written | |
10963 | * permission. | |
10964 | * | |
10965 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
10966 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
10967 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
10968 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
10969 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
10970 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
10971 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
10972 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
10973 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
10974 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
10975 | * | |
10976 | */ | |
10977 | ||
10978 | ||
10979 | /*---------------------------------------------------------------------------+ | |
10980 | | wm_sqrt(FPU_REG *n, unsigned int control_word) | | |
10981 | | returns the square root of n in n. | | |
10982 | | | | |
10983 | | Use Newton's method to compute the square root of a number, which must | | |
10984 | | be in the range [1.0 .. 4.0), to 64 bits accuracy. | | |
10985 | | Does not check the sign or tag of the argument. | | |
10986 | | Sets the exponent, but not the sign or tag of the result. | | |
10987 | | | | |
10988 | | The guess is kept in %esi:%edi | | |
10989 | +---------------------------------------------------------------------------*/ | |
10990 | ||
10991 | #include "exception.h" | |
10992 | #include "fpu_asm.h" | |
10993 | ||
10994 | ||
10995 | .data | |
10996 | /* | |
10997 | Local storage: | |
10998 | */ | |
10999 | .align 4,0 | |
11000 | accum_3: | |
11001 | .long 0 /* ms word */ | |
11002 | accum_2: | |
11003 | .long 0 | |
11004 | accum_1: | |
11005 | .long 0 | |
11006 | accum_0: | |
11007 | .long 0 | |
11008 | ||
11009 | /* The de-normalised argument: | |
11010 | // sq_2 sq_1 sq_0 | |
11011 | // b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0 | |
11012 | // ^ binary point here */ | |
11013 | fsqrt_arg_2: | |
11014 | .long 0 /* ms word */ | |
11015 | fsqrt_arg_1: | |
11016 | .long 0 | |
11017 | fsqrt_arg_0: | |
11018 | .long 0 /* ls word, at most the ms bit is set */ | |
11019 | ||
11020 | .text | |
11021 | .align 2,144 | |
11022 | ||
11023 | .globl _wm_sqrt | |
11024 | ||
11025 | _wm_sqrt: | |
11026 | pushl %ebp | |
11027 | movl %esp,%ebp | |
11028 | pushl %esi | |
11029 | pushl %edi | |
11030 | pushl %ebx | |
11031 | ||
11032 | movl PARAM1,%esi | |
11033 | ||
11034 | movl SIGH(%esi),%eax | |
11035 | movl SIGL(%esi),%ecx | |
11036 | xorl %edx,%edx | |
11037 | ||
11038 | /* We use a rough linear estimate for the first guess.. */ | |
11039 | ||
11040 | cmpl EXP_BIAS,EXP(%esi) | |
11041 | jnz sqrt_arg_ge_2 | |
11042 | ||
11043 | shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */ | |
11044 | rcrl $1,%ecx | |
11045 | rcrl $1,%edx | |
11046 | ||
11047 | sqrt_arg_ge_2: | |
11048 | /* From here on, n is never accessed directly again until it is | |
11049 | // replaced by the answer. */ | |
11050 | ||
11051 | movl %eax,fsqrt_arg_2 /* ms word of n */ | |
11052 | movl %ecx,fsqrt_arg_1 | |
11053 | movl %edx,fsqrt_arg_0 | |
11054 | ||
11055 | /* Make a linear first estimate */ | |
11056 | shrl $1,%eax | |
11057 | addl $0x40000000,%eax | |
11058 | movl $0xaaaaaaaa,%ecx | |
11059 | mull %ecx | |
11060 | shll %edx /* max result was 7fff... */ | |
11061 | testl $0x80000000,%edx /* but min was 3fff... */ | |
11062 | jnz sqrt_prelim_no_adjust | |
11063 | ||
11064 | movl $0x80000000,%edx /* round up */ | |
11065 | ||
11066 | sqrt_prelim_no_adjust: | |
11067 | movl %edx,%esi /* Our first guess */ | |
11068 | ||
11069 | /* We have now computed (approx) (2 + x) / 3, which forms the basis | |
11070 | for a few iterations of Newton's method */ | |
11071 | ||
11072 | movl fsqrt_arg_2,%ecx /* ms word */ | |
11073 | ||
11074 | /* From our initial estimate, three iterations are enough to get us | |
11075 | // to 30 bits or so. This will then allow two iterations at better | |
11076 | // precision to complete the process. | |
11077 | ||
11078 | // Compute (g + n/g)/2 at each iteration (g is the guess). */ | |
11079 | shrl %ecx /* Doing this first will prevent a divide */ | |
11080 | /* overflow later. */ | |
11081 | ||
11082 | movl %ecx,%edx /* msw of the arg / 2 */ | |
11083 | divl %esi /* current estimate */ | |
11084 | shrl %esi /* divide by 2 */ | |
11085 | addl %eax,%esi /* the new estimate */ | |
11086 | ||
11087 | movl %ecx,%edx | |
11088 | divl %esi | |
11089 | shrl %esi | |
11090 | addl %eax,%esi | |
11091 | ||
11092 | movl %ecx,%edx | |
11093 | divl %esi | |
11094 | shrl %esi | |
11095 | addl %eax,%esi | |
11096 | ||
11097 | /* Now that an estimate accurate to about 30 bits has been obtained (in %esi), | |
11098 | // we improve it to 60 bits or so. | |
11099 | ||
11100 | // The strategy from now on is to compute new estimates from | |
11101 | // guess := guess + (n - guess^2) / (2 * guess) */ | |
11102 | ||
11103 | /* First, find the square of the guess */ | |
11104 | movl %esi,%eax | |
11105 | mull %esi | |
11106 | /* guess^2 now in %edx:%eax */ | |
11107 | ||
11108 | movl fsqrt_arg_1,%ecx | |
11109 | subl %ecx,%eax | |
11110 | movl fsqrt_arg_2,%ecx /* ms word of normalized n */ | |
11111 | sbbl %ecx,%edx | |
11112 | jnc sqrt_stage_2_positive | |
11113 | /* subtraction gives a negative result | |
11114 | // negate the result before division */ | |
11115 | notl %edx | |
11116 | notl %eax | |
11117 | addl $1,%eax | |
11118 | adcl $0,%edx | |
11119 | ||
11120 | divl %esi | |
11121 | movl %eax,%ecx | |
11122 | ||
11123 | movl %edx,%eax | |
11124 | divl %esi | |
11125 | jmp sqrt_stage_2_finish | |
11126 | ||
11127 | sqrt_stage_2_positive: | |
11128 | divl %esi | |
11129 | movl %eax,%ecx | |
11130 | ||
11131 | movl %edx,%eax | |
11132 | divl %esi | |
11133 | ||
11134 | notl %ecx | |
11135 | notl %eax | |
11136 | addl $1,%eax | |
11137 | adcl $0,%ecx | |
11138 | ||
11139 | sqrt_stage_2_finish: | |
11140 | sarl $1,%ecx /* divide by 2 */ | |
11141 | rcrl $1,%eax | |
11142 | ||
11143 | /* Form the new estimate in %esi:%edi */ | |
11144 | movl %eax,%edi | |
11145 | addl %ecx,%esi | |
11146 | ||
11147 | jnz sqrt_stage_2_done /* result should be [1..2) */ | |
11148 | ||
11149 | #ifdef PARANOID | |
11150 | /* It should be possible to get here only if the arg is ffff....ffff*/ | |
11151 | cmp $0xffffffff,fsqrt_arg_1 | |
11152 | jnz sqrt_stage_2_error | |
11153 | #endif PARANOID | |
11154 | ||
11155 | /* The best rounded result.*/ | |
11156 | xorl %eax,%eax | |
11157 | decl %eax | |
11158 | movl %eax,%edi | |
11159 | movl %eax,%esi | |
11160 | movl $0x7fffffff,%eax | |
11161 | jmp sqrt_round_result | |
11162 | ||
11163 | #ifdef PARANOID | |
11164 | sqrt_stage_2_error: | |
11165 | pushl EX_INTERNAL|0x213 | |
11166 | call EXCEPTION | |
11167 | #endif PARANOID | |
11168 | ||
11169 | sqrt_stage_2_done: | |
11170 | ||
11171 | /* Now the square root has been computed to better than 60 bits */ | |
11172 | ||
11173 | /* Find the square of the guess*/ | |
11174 | movl %edi,%eax /* ls word of guess*/ | |
11175 | mull %edi | |
11176 | movl %edx,accum_1 | |
11177 | ||
11178 | movl %esi,%eax | |
11179 | mull %esi | |
11180 | movl %edx,accum_3 | |
11181 | movl %eax,accum_2 | |
11182 | ||
11183 | movl %edi,%eax | |
11184 | mull %esi | |
11185 | addl %eax,accum_1 | |
11186 | adcl %edx,accum_2 | |
11187 | adcl $0,accum_3 | |
11188 | ||
11189 | /* movl %esi,%eax*/ | |
11190 | /* mull %edi*/ | |
11191 | addl %eax,accum_1 | |
11192 | adcl %edx,accum_2 | |
11193 | adcl $0,accum_3 | |
11194 | ||
11195 | /* guess^2 now in accum_3:accum_2:accum_1*/ | |
11196 | ||
11197 | movl fsqrt_arg_0,%eax /* get normalized n*/ | |
11198 | subl %eax,accum_1 | |
11199 | movl fsqrt_arg_1,%eax | |
11200 | sbbl %eax,accum_2 | |
11201 | movl fsqrt_arg_2,%eax /* ms word of normalized n*/ | |
11202 | sbbl %eax,accum_3 | |
11203 | jnc sqrt_stage_3_positive | |
11204 | ||
11205 | /* subtraction gives a negative result*/ | |
11206 | /* negate the result before division */ | |
11207 | notl accum_1 | |
11208 | notl accum_2 | |
11209 | notl accum_3 | |
11210 | addl $1,accum_1 | |
11211 | adcl $0,accum_2 | |
11212 | ||
11213 | #ifdef PARANOID | |
11214 | adcl $0,accum_3 /* This must be zero */ | |
11215 | jz sqrt_stage_3_no_error | |
11216 | ||
11217 | sqrt_stage_3_error: | |
11218 | pushl EX_INTERNAL|0x207 | |
11219 | call EXCEPTION | |
11220 | ||
11221 | sqrt_stage_3_no_error: | |
11222 | #endif PARANOID | |
11223 | ||
11224 | movl accum_2,%edx | |
11225 | movl accum_1,%eax | |
11226 | divl %esi | |
11227 | movl %eax,%ecx | |
11228 | ||
11229 | movl %edx,%eax | |
11230 | divl %esi | |
11231 | ||
11232 | sarl $1,%ecx / divide by 2*/ | |
11233 | rcrl $1,%eax | |
11234 | ||
11235 | /* prepare to round the result*/ | |
11236 | ||
11237 | addl %ecx,%edi | |
11238 | adcl $0,%esi | |
11239 | ||
11240 | jmp sqrt_stage_3_finished | |
11241 | ||
11242 | sqrt_stage_3_positive: | |
11243 | movl accum_2,%edx | |
11244 | movl accum_1,%eax | |
11245 | divl %esi | |
11246 | movl %eax,%ecx | |
11247 | ||
11248 | movl %edx,%eax | |
11249 | divl %esi | |
11250 | ||
11251 | sarl $1,%ecx /* divide by 2*/ | |
11252 | rcrl $1,%eax | |
11253 | ||
11254 | /* prepare to round the result*/ | |
11255 | ||
11256 | notl %eax /* Negate the correction term*/ | |
11257 | notl %ecx | |
11258 | addl $1,%eax | |
11259 | adcl $0,%ecx /* carry here ==> correction == 0*/ | |
11260 | adcl $0xffffffff,%esi | |
11261 | ||
11262 | addl %ecx,%edi | |
11263 | adcl $0,%esi | |
11264 | ||
11265 | sqrt_stage_3_finished: | |
11266 | ||
11267 | /* The result in %esi:%edi:%esi should be good to about 90 bits here, | |
11268 | // and the rounding information here does not have sufficient accuracy | |
11269 | // in a few rare cases. */ | |
11270 | cmpl $0xffffffe0,%eax | |
11271 | ja sqrt_near_exact_x | |
11272 | ||
11273 | cmpl $0x00000020,%eax | |
11274 | jb sqrt_near_exact | |
11275 | ||
11276 | cmpl $0x7fffffe0,%eax | |
11277 | jb sqrt_round_result | |
11278 | ||
11279 | cmpl $0x80000020,%eax | |
11280 | jb sqrt_get_more_precision | |
11281 | ||
11282 | sqrt_round_result: | |
11283 | /* Set up for rounding operations*/ | |
11284 | movl %eax,%edx | |
11285 | movl %esi,%eax | |
11286 | movl %edi,%ebx | |
11287 | movl PARAM1,%edi | |
11288 | movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0)*/ | |
11289 | movl PARAM2,%ecx | |
11290 | jmp FPU_round_sqrt | |
11291 | ||
11292 | ||
11293 | sqrt_near_exact_x: | |
11294 | /* First, the estimate must be rounded up.*/ | |
11295 | addl $1,%edi | |
11296 | adcl $0,%esi | |
11297 | ||
11298 | sqrt_near_exact: | |
11299 | /* This is an easy case because x^1/2 is monotonic. | |
11300 | // We need just find the square of our estimate, compare it | |
11301 | // with the argument, and deduce whether our estimate is | |
11302 | // above, below, or exact. We use the fact that the estimate | |
11303 | // is known to be accurate to about 90 bits. */ | |
11304 | movl %edi,%eax /* ls word of guess*/ | |
11305 | mull %edi | |
11306 | movl %edx,%ebx /* 2nd ls word of square*/ | |
11307 | movl %eax,%ecx /* ls word of square*/ | |
11308 | ||
11309 | movl %edi,%eax | |
11310 | mull %esi | |
11311 | addl %eax,%ebx | |
11312 | addl %eax,%ebx | |
11313 | ||
11314 | #ifdef PARANOID | |
11315 | cmp $0xffffffb0,%ebx | |
11316 | jb sqrt_near_exact_ok | |
11317 | ||
11318 | cmp $0x00000050,%ebx | |
11319 | ja sqrt_near_exact_ok | |
11320 | ||
11321 | pushl EX_INTERNAL|0x214 | |
11322 | call EXCEPTION | |
11323 | ||
11324 | sqrt_near_exact_ok: | |
11325 | #endif PARANOID | |
11326 | ||
11327 | or %ebx,%ebx | |
11328 | js sqrt_near_exact_small | |
11329 | ||
11330 | jnz sqrt_near_exact_large | |
11331 | ||
11332 | or %ebx,%edx | |
11333 | jnz sqrt_near_exact_large | |
11334 | ||
11335 | /* Our estimate is exactly the right answer*/ | |
11336 | xorl %eax,%eax | |
11337 | jmp sqrt_round_result | |
11338 | ||
11339 | sqrt_near_exact_small: | |
11340 | /* Our estimate is too small*/ | |
11341 | movl $0x000000ff,%eax | |
11342 | jmp sqrt_round_result | |
11343 | ||
11344 | sqrt_near_exact_large: | |
11345 | /* Our estimate is too large, we need to decrement it*/ | |
11346 | subl $1,%edi | |
11347 | sbbl $0,%esi | |
11348 | movl $0xffffff00,%eax | |
11349 | jmp sqrt_round_result | |
11350 | ||
11351 | ||
11352 | sqrt_get_more_precision: | |
11353 | /* This case is almost the same as the above, except we start*/ | |
11354 | /* with an extra bit of precision in the estimate.*/ | |
11355 | stc /* The extra bit.*/ | |
11356 | rcll $1,%edi /* Shift the estimate left one bit*/ | |
11357 | rcll $1,%esi | |
11358 | ||
11359 | movl %edi,%eax /* ls word of guess*/ | |
11360 | mull %edi | |
11361 | movl %edx,%ebx /* 2nd ls word of square*/ | |
11362 | movl %eax,%ecx /* ls word of square*/ | |
11363 | ||
11364 | movl %edi,%eax | |
11365 | mull %esi | |
11366 | addl %eax,%ebx | |
11367 | addl %eax,%ebx | |
11368 | ||
11369 | /* Put our estimate back to its original value*/ | |
11370 | stc /* The ms bit.*/ | |
11371 | rcrl $1,%esi /* Shift the estimate left one bit*/ | |
11372 | rcrl $1,%edi | |
11373 | ||
11374 | #ifdef PARANOID | |
11375 | cmp $0xffffff60,%ebx | |
11376 | jb sqrt_more_prec_ok | |
11377 | ||
11378 | cmp $0x000000a0,%ebx | |
11379 | ja sqrt_more_prec_ok | |
11380 | ||
11381 | pushl EX_INTERNAL|0x215 | |
11382 | call EXCEPTION | |
11383 | ||
11384 | sqrt_more_prec_ok: | |
11385 | #endif PARANOID | |
11386 | ||
11387 | or %ebx,%ebx | |
11388 | js sqrt_more_prec_small | |
11389 | ||
11390 | jnz sqrt_more_prec_large | |
11391 | ||
11392 | or %ebx,%ecx | |
11393 | jnz sqrt_more_prec_large | |
11394 | ||
11395 | /* Our estimate is exactly the right answer*/ | |
11396 | movl $0x80000000,%eax | |
11397 | jmp sqrt_round_result | |
11398 | ||
11399 | sqrt_more_prec_small: | |
11400 | /* Our estimate is too small*/ | |
11401 | movl $0x800000ff,%eax | |
11402 | jmp sqrt_round_result | |
11403 | ||
11404 | sqrt_more_prec_large: | |
11405 | /* Our estimate is too large*/ | |
11406 | movl $0x7fffff00,%eax | |
11407 | jmp sqrt_round_result | |
11408 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0fpemul/reg_add_sub.c\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0100644 \0 0 \0 24 \0 20551 5462320164 13222\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0root\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0staff\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0/* | |
11409 | * reg_add_sub.c | |
11410 | * | |
11411 | * Functions to add or subtract two registers and put the result in a third. | |
11412 | * | |
11413 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
11414 | * Vic 3163, Australia. | |
11415 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
11416 | * All rights reserved. | |
11417 | * | |
11418 | * This copyright notice covers the redistribution and use of the | |
11419 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
11420 | * in the 386BSD operating system. Any other use is not permitted | |
11421 | * under this copyright. | |
11422 | * | |
11423 | * Redistribution and use in source and binary forms, with or without | |
11424 | * modification, are permitted provided that the following conditions | |
11425 | * are met: | |
11426 | * 1. Redistributions of source code must retain the above copyright | |
11427 | * notice, this list of conditions and the following disclaimer. | |
11428 | * 2. Redistributions in binary form must include information specifying | |
11429 | * that source code for the emulator is freely available and include | |
11430 | * either: | |
11431 | * a) an offer to provide the source code for a nominal distribution | |
11432 | * fee, or | |
11433 | * b) list at least two alternative methods whereby the source | |
11434 | * can be obtained, e.g. a publically accessible bulletin board | |
11435 | * and an anonymous ftp site from which the software can be | |
11436 | * downloaded. | |
11437 | * 3. All advertising materials specifically mentioning features or use of | |
11438 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
11439 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
11440 | * products derived from this software without specific prior written | |
11441 | * permission. | |
11442 | * | |
11443 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
11444 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
11445 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
11446 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
11447 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
11448 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
11449 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
11450 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
11451 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
11452 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
11453 | * | |
11454 | */ | |
11455 | ||
11456 | /*---------------------------------------------------------------------------+ | |
11457 | | For each function, the destination may be any FPU_REG, including one of | | |
11458 | | the source FPU_REGs. | | |
11459 | +---------------------------------------------------------------------------*/ | |
11460 | ||
11461 | #include "exception.h" | |
11462 | #include "reg_constant.h" | |
11463 | #include "fpu_emu.h" | |
11464 | #include "control_w.h" | |
11465 | #include "fpu_system.h" | |
11466 | ||
11467 | ||
11468 | void | |
11469 | reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w) | |
11470 | { | |
11471 | int diff; | |
11472 | ||
11473 | if (!(a->tag | b->tag)) { | |
11474 | /* Both registers are valid */ | |
11475 | if (!(a->sign ^ b->sign)) { | |
11476 | /* signs are the same */ | |
11477 | reg_u_add(a, b, dest, control_w); | |
11478 | dest->sign = a->sign; | |
11479 | return; | |
11480 | } | |
11481 | /* The signs are different, so do a subtraction */ | |
11482 | diff = a->exp - b->exp; | |
11483 | if (!diff) { | |
11484 | diff = a->sigh - b->sigh; /* Works only if ms bits | |
11485 | * are identical */ | |
11486 | if (!diff) { | |
11487 | diff = a->sigl > b->sigl; | |
11488 | if (!diff) | |
11489 | diff = -(a->sigl < b->sigl); | |
11490 | } | |
11491 | } | |
11492 | if (diff > 0) { | |
11493 | reg_u_sub(a, b, dest, control_w); | |
11494 | dest->sign = a->sign; | |
11495 | } else | |
11496 | if (diff == 0) { | |
11497 | reg_move(&CONST_Z, dest); | |
11498 | /* sign depends upon rounding mode */ | |
11499 | dest->sign = ((control_w & CW_RC) != RC_DOWN) | |
11500 | ? SIGN_POS : SIGN_NEG; | |
11501 | } else { | |
11502 | reg_u_sub(b, a, dest, control_w); | |
11503 | dest->sign = b->sign; | |
11504 | } | |
11505 | return; | |
11506 | } else { | |
11507 | if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) { | |
11508 | real_2op_NaN(a, b, dest); | |
11509 | return; | |
11510 | } else | |
11511 | if (a->tag == TW_Zero) { | |
11512 | if (b->tag == TW_Zero) { | |
11513 | char different_signs = a->sign ^ b->sign; | |
11514 | /* Both are zero, result will be zero. */ | |
11515 | reg_move(a, dest); | |
11516 | if (different_signs) { | |
11517 | /* Signs are different. */ | |
11518 | /* Sign of answer depends upon | |
11519 | * rounding mode. */ | |
11520 | dest->sign = ((control_w & CW_RC) != RC_DOWN) | |
11521 | ? SIGN_POS : SIGN_NEG; | |
11522 | } | |
11523 | } else { | |
11524 | #ifdef DENORM_OPERAND | |
11525 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && | |
11526 | denormal_operand()) | |
11527 | return; | |
11528 | #endif /* DENORM_OPERAND */ | |
11529 | reg_move(b, dest); | |
11530 | } | |
11531 | return; | |
11532 | } else | |
11533 | if (b->tag == TW_Zero) { | |
11534 | #ifdef DENORM_OPERAND | |
11535 | if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && | |
11536 | denormal_operand()) | |
11537 | return; | |
11538 | #endif /* DENORM_OPERAND */ | |
11539 | reg_move(a, dest); | |
11540 | return; | |
11541 | } else | |
11542 | if (a->tag == TW_Infinity) { | |
11543 | if (b->tag != TW_Infinity) { | |
11544 | #ifdef DENORM_OPERAND | |
11545 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && | |
11546 | denormal_operand()) | |
11547 | return; | |
11548 | #endif /* DENORM_OPERAND */ | |
11549 | reg_move(a, dest); | |
11550 | return; | |
11551 | } | |
11552 | if (a->sign == b->sign) { | |
11553 | /* They are both + or | |
11554 | * - infinity */ | |
11555 | reg_move(a, dest); | |
11556 | return; | |
11557 | } | |
11558 | arith_invalid(dest); /* Infinity-Infinity is | |
11559 | * undefined. */ | |
11560 | return; | |
11561 | } else | |
11562 | if (b->tag == TW_Infinity) { | |
11563 | #ifdef DENORM_OPERAND | |
11564 | if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && | |
11565 | denormal_operand()) | |
11566 | return; | |
11567 | #endif /* DENORM_OPERAND */ | |
11568 | reg_move(b, dest); | |
11569 | return; | |
11570 | } | |
11571 | } | |
11572 | #ifdef PARANOID | |
11573 | EXCEPTION(EX_INTERNAL | 0x101); | |
11574 | #endif | |
11575 | } | |
11576 | ||
11577 | ||
11578 | /* Subtract b from a. (a-b) -> dest */ | |
11579 | void | |
11580 | reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w) | |
11581 | { | |
11582 | int diff; | |
11583 | ||
11584 | if (!(a->tag | b->tag)) { | |
11585 | /* Both registers are valid */ | |
11586 | diff = a->exp - b->exp; | |
11587 | if (!diff) { | |
11588 | diff = a->sigh - b->sigh; /* Works only if ms bits | |
11589 | * are identical */ | |
11590 | if (!diff) { | |
11591 | diff = a->sigl > b->sigl; | |
11592 | if (!diff) | |
11593 | diff = -(a->sigl < b->sigl); | |
11594 | } | |
11595 | } | |
11596 | switch (a->sign * 2 + b->sign) { | |
11597 | case 0: /* P - P */ | |
11598 | case 3: /* N - N */ | |
11599 | if (diff > 0) { | |
11600 | reg_u_sub(a, b, dest, control_w); | |
11601 | dest->sign = a->sign; | |
11602 | } else | |
11603 | if (diff == 0) { | |
11604 | #ifdef DENORM_OPERAND | |
11605 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && | |
11606 | denormal_operand()) | |
11607 | return; | |
11608 | #endif /* DENORM_OPERAND */ | |
11609 | reg_move(&CONST_Z, dest); | |
11610 | /* sign depends upon rounding mode */ | |
11611 | dest->sign = ((control_w & CW_RC) != RC_DOWN) | |
11612 | ? SIGN_POS : SIGN_NEG; | |
11613 | } else { | |
11614 | reg_u_sub(b, a, dest, control_w); | |
11615 | dest->sign = a->sign ^ SIGN_POS ^ SIGN_NEG; | |
11616 | } | |
11617 | return; | |
11618 | case 1: /* P - N */ | |
11619 | reg_u_add(a, b, dest, control_w); | |
11620 | dest->sign = SIGN_POS; | |
11621 | return; | |
11622 | case 2: /* N - P */ | |
11623 | reg_u_add(a, b, dest, control_w); | |
11624 | dest->sign = SIGN_NEG; | |
11625 | return; | |
11626 | } | |
11627 | } else { | |
11628 | if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) { | |
11629 | real_2op_NaN(a, b, dest); | |
11630 | return; | |
11631 | } else | |
11632 | if (b->tag == TW_Zero) { | |
11633 | if (a->tag == TW_Zero) { | |
11634 | char same_signs = !(a->sign ^ b->sign); | |
11635 | /* Both are zero, result will be zero. */ | |
11636 | reg_move(a, dest); /* Answer for different | |
11637 | * signs. */ | |
11638 | if (same_signs) { | |
11639 | /* Sign depends upon rounding | |
11640 | * mode */ | |
11641 | dest->sign = ((control_w & CW_RC) != RC_DOWN) | |
11642 | ? SIGN_POS : SIGN_NEG; | |
11643 | } | |
11644 | } else { | |
11645 | #ifdef DENORM_OPERAND | |
11646 | if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && | |
11647 | denormal_operand()) | |
11648 | return; | |
11649 | #endif /* DENORM_OPERAND */ | |
11650 | reg_move(a, dest); | |
11651 | } | |
11652 | return; | |
11653 | } else | |
11654 | if (a->tag == TW_Zero) { | |
11655 | #ifdef DENORM_OPERAND | |
11656 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && | |
11657 | denormal_operand()) | |
11658 | return; | |
11659 | #endif /* DENORM_OPERAND */ | |
11660 | reg_move(b, dest); | |
11661 | dest->sign ^= SIGN_POS ^ SIGN_NEG; | |
11662 | return; | |
11663 | } else | |
11664 | if (a->tag == TW_Infinity) { | |
11665 | if (b->tag != TW_Infinity) { | |
11666 | #ifdef DENORM_OPERAND | |
11667 | if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && | |
11668 | denormal_operand()) | |
11669 | return; | |
11670 | #endif /* DENORM_OPERAND */ | |
11671 | reg_move(a, dest); | |
11672 | return; | |
11673 | } | |
11674 | /* Both args are Infinity */ | |
11675 | if (a->sign == b->sign) { | |
11676 | arith_invalid(dest); /* Infinity-Infinity is | |
11677 | * undefined. */ | |
11678 | return; | |
11679 | } | |
11680 | reg_move(a, dest); | |
11681 | return; | |
11682 | } else | |
11683 | if (b->tag == TW_Infinity) { | |
11684 | #ifdef DENORM_OPERAND | |
11685 | if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && | |
11686 | denormal_operand()) | |
11687 | return; | |
11688 | #endif /* DENORM_OPERAND */ | |
11689 | reg_move(b, dest); | |
11690 | dest->sign ^= SIGN_POS ^ SIGN_NEG; | |
11691 | return; | |
11692 | } | |
11693 | } | |
11694 | #ifdef PARANOID | |
11695 | EXCEPTION(EX_INTERNAL | 0x110); | |
11696 | #endif | |
11697 | } | |
11698 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 |