Commit | Line | Data |
---|---|---|
f24c459c JH |
1 | .file "reg_u_sub.S" |
2 | /* | |
3 | * reg_u_sub.S | |
4 | * | |
5 | * Core floating point subtraction routine. | |
6 | * | |
7 | * Call from C as: | |
8 | * void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | |
9 | * int control_w) | |
10 | * | |
11 | * | |
12 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, | |
13 | * Vic 3163, Australia. | |
14 | * E-mail apm233m@vaxc.cc.monash.edu.au | |
15 | * All rights reserved. | |
16 | * | |
17 | * This copyright notice covers the redistribution and use of the | |
18 | * FPU emulator developed by W. Metzenthen. It covers only its use | |
19 | * in the 386BSD operating system. Any other use is not permitted | |
20 | * under this copyright. | |
21 | * | |
22 | * Redistribution and use in source and binary forms, with or without | |
23 | * modification, are permitted provided that the following conditions | |
24 | * are met: | |
25 | * 1. Redistributions of source code must retain the above copyright | |
26 | * notice, this list of conditions and the following disclaimer. | |
27 | * 2. Redistributions in binary form must include information specifying | |
28 | * that source code for the emulator is freely available and include | |
29 | * either: | |
30 | * a) an offer to provide the source code for a nominal distribution | |
31 | * fee, or | |
32 | * b) list at least two alternative methods whereby the source | |
33 | * can be obtained, e.g. a publically accessible bulletin board | |
34 | * and an anonymous ftp site from which the software can be | |
35 | * downloaded. | |
36 | * 3. All advertising materials specifically mentioning features or use of | |
37 | * this emulator must acknowledge that it was developed by W. Metzenthen. | |
38 | * 4. The name of W. Metzenthen may not be used to endorse or promote | |
39 | * products derived from this software without specific prior written | |
40 | * permission. | |
41 | * | |
42 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, | |
43 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | |
44 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | |
45 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
46 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
47 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
48 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
49 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
50 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
51 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
52 | * | |
53 | */ | |
54 | ||
55 | /* | |
56 | | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ). | |
57 | | Takes two valid reg f.p. numbers (TW_Valid), which are | |
58 | | treated as unsigned numbers, | |
59 | | and returns their difference as a TW_Valid or TW_Zero f.p. | |
60 | | number. | |
61 | | The first number (arg1) must be the larger. | |
62 | | The returned number is normalized. | |
63 | | Basic checks are performed if PARANOID is defined. | |
64 | */ | |
65 | ||
66 | #include "exception.h" | |
67 | #include "fpu_asm.h" | |
68 | #include "control_w.h" | |
69 | ||
70 | .text | |
71 | .align 2,144 | |
72 | .globl _reg_u_sub | |
73 | _reg_u_sub: | |
74 | pushl %ebp | |
75 | movl %esp,%ebp | |
76 | pushl %esi | |
77 | pushl %edi | |
78 | pushl %ebx | |
79 | ||
80 | movl PARAM1,%esi /* source 1 */ | |
81 | movl PARAM2,%edi /* source 2 */ | |
82 | ||
83 | #ifdef DENORM_OPERAND | |
84 | cmpl EXP_UNDER,EXP(%esi) | |
85 | jg xOp1_not_denorm | |
86 | ||
87 | call _denormal_operand | |
88 | orl %eax,%eax | |
89 | jnz FPU_Arith_exit | |
90 | ||
91 | xOp1_not_denorm: | |
92 | cmpl EXP_UNDER,EXP(%edi) | |
93 | jg xOp2_not_denorm | |
94 | ||
95 | call _denormal_operand | |
96 | orl %eax,%eax | |
97 | jnz FPU_Arith_exit | |
98 | ||
99 | xOp2_not_denorm: | |
100 | #endif DENORM_OPERAND | |
101 | ||
102 | /* xorl %ecx,%ecx */ | |
103 | movl EXP(%esi),%ecx | |
104 | subl EXP(%edi),%ecx /* exp1 - exp2 */ | |
105 | ||
106 | #ifdef PARANOID | |
107 | /* source 2 is always smaller than source 1 */ | |
108 | /* jc L_bugged */ | |
109 | js L_bugged_1 | |
110 | ||
111 | testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ | |
112 | je L_bugged_2 | |
113 | ||
114 | testl $0x80000000,SIGH(%esi) | |
115 | je L_bugged_2 | |
116 | #endif PARANOID | |
117 | ||
118 | /*--------------------------------------+ | |
119 | | Form a register holding the | | |
120 | | smaller number | | |
121 | +--------------------------------------*/ | |
122 | movl SIGH(%edi),%eax /* register ms word */ | |
123 | movl SIGL(%edi),%ebx /* register ls word */ | |
124 | ||
125 | movl PARAM3,%edi /* destination */ | |
126 | movl EXP(%esi),%edx | |
127 | movl %edx,EXP(%edi) /* Copy exponent to destination */ | |
128 | movb SIGN(%esi),%dl | |
129 | movb %dl,SIGN(%edi) /* Copy the sign from the first arg */ | |
130 | ||
131 | xorl %edx,%edx /* register extension */ | |
132 | ||
133 | /*--------------------------------------+ | |
134 | | Shift the temporary register | | |
135 | | right the required number of | | |
136 | | places. | | |
137 | +--------------------------------------*/ | |
138 | L_shift_r: | |
139 | cmpl $32,%ecx /* shrd only works for 0..31 bits */ | |
140 | jnc L_more_than_31 | |
141 | ||
142 | /* less than 32 bits */ | |
143 | shrd %cl,%ebx,%edx | |
144 | shrd %cl,%eax,%ebx | |
145 | shr %cl,%eax | |
146 | jmp L_shift_done | |
147 | ||
148 | L_more_than_31: | |
149 | cmpl $64,%ecx | |
150 | jnc L_more_than_63 | |
151 | ||
152 | subb $32,%cl | |
153 | jz L_exactly_32 | |
154 | ||
155 | shrd %cl,%eax,%edx | |
156 | shr %cl,%eax | |
157 | orl %ebx,%ebx | |
158 | jz L_more_31_no_low /* none of the lowest bits is set */ | |
159 | ||
160 | orl $1,%edx /* record the fact in the extension */ | |
161 | ||
162 | L_more_31_no_low: | |
163 | movl %eax,%ebx | |
164 | xorl %eax,%eax | |
165 | jmp L_shift_done | |
166 | ||
167 | L_exactly_32: | |
168 | movl %ebx,%edx | |
169 | movl %eax,%ebx | |
170 | xorl %eax,%eax | |
171 | jmp L_shift_done | |
172 | ||
173 | L_more_than_63: | |
174 | cmpw $65,%cx | |
175 | jnc L_more_than_64 | |
176 | ||
177 | /* Shift right by 64 bits */ | |
178 | movl %eax,%edx | |
179 | orl %ebx,%ebx | |
180 | jz L_more_63_no_low | |
181 | ||
182 | orl $1,%edx | |
183 | jmp L_more_63_no_low | |
184 | ||
185 | L_more_than_64: | |
186 | jne L_more_than_65 | |
187 | ||
188 | /* Shift right by 65 bits */ | |
189 | /* Carry is clear if we get here */ | |
190 | movl %eax,%edx | |
191 | rcrl %edx | |
192 | jnc L_shift_65_nc | |
193 | ||
194 | orl $1,%edx | |
195 | jmp L_more_63_no_low | |
196 | ||
197 | L_shift_65_nc: | |
198 | orl %ebx,%ebx | |
199 | jz L_more_63_no_low | |
200 | ||
201 | orl $1,%edx | |
202 | jmp L_more_63_no_low | |
203 | ||
204 | L_more_than_65: | |
205 | movl $1,%edx /* The shifted nr always at least one '1' */ | |
206 | ||
207 | L_more_63_no_low: | |
208 | xorl %ebx,%ebx | |
209 | xorl %eax,%eax | |
210 | ||
211 | L_shift_done: | |
212 | L_subtr: | |
213 | /*------------------------------+ | |
214 | | Do the subtraction | | |
215 | +------------------------------*/ | |
216 | xorl %ecx,%ecx | |
217 | subl %edx,%ecx | |
218 | movl %ecx,%edx | |
219 | movl SIGL(%esi),%ecx | |
220 | sbbl %ebx,%ecx | |
221 | movl %ecx,%ebx | |
222 | movl SIGH(%esi),%ecx | |
223 | sbbl %eax,%ecx | |
224 | movl %ecx,%eax | |
225 | ||
226 | #ifdef PARANOID | |
227 | /* We can never get a borrow */ | |
228 | jc L_bugged | |
229 | #endif PARANOID | |
230 | ||
231 | /*--------------------------------------+ | |
232 | | Normalize the result | | |
233 | +--------------------------------------*/ | |
234 | testl $0x80000000,%eax | |
235 | jnz L_round /* no shifting needed */ | |
236 | ||
237 | orl %eax,%eax | |
238 | jnz L_shift_1 /* shift left 1 - 31 bits */ | |
239 | ||
240 | orl %ebx,%ebx | |
241 | jnz L_shift_32 /* shift left 32 - 63 bits */ | |
242 | ||
243 | /* A rare case, the only one which is non-zero if we got here | |
244 | // is: 1000000 .... 0000 | |
245 | // -0111111 .... 1111 1 | |
246 | // -------------------- | |
247 | // 0000000 .... 0000 1 */ | |
248 | ||
249 | cmpl $0x80000000,%edx | |
250 | jnz L_must_be_zero | |
251 | ||
252 | /* Shift left 64 bits */ | |
253 | subl $64,EXP(%edi) | |
254 | movl %edx,%eax | |
255 | jmp L_store | |
256 | ||
257 | L_must_be_zero: | |
258 | #ifdef PARANOID | |
259 | orl %edx,%edx | |
260 | jnz L_bugged_3 | |
261 | #endif PARANOID | |
262 | ||
263 | /* The result is zero */ | |
264 | movb TW_Zero,TAG(%edi) | |
265 | movl $0,EXP(%edi) /* exponent */ | |
266 | movl $0,SIGL(%edi) | |
267 | movl $0,SIGH(%edi) | |
268 | jmp L_exit /* Does not underflow */ | |
269 | ||
270 | L_shift_32: | |
271 | movl %ebx,%eax | |
272 | movl %edx,%ebx | |
273 | movl $0,%edx | |
274 | subl $32,EXP(%edi) /* Can get underflow here */ | |
275 | ||
276 | /* We need to shift left by 1 - 31 bits */ | |
277 | L_shift_1: | |
278 | bsrl %eax,%ecx /* get the required shift in %ecx */ | |
279 | subl $31,%ecx | |
280 | negl %ecx | |
281 | shld %cl,%ebx,%eax | |
282 | shld %cl,%edx,%ebx | |
283 | shl %cl,%edx | |
284 | subl %ecx,EXP(%edi) /* Can get underflow here */ | |
285 | ||
286 | L_round: | |
287 | jmp FPU_round /* Round the result */ | |
288 | ||
289 | ||
290 | #ifdef PARANOID | |
291 | L_bugged_1: | |
292 | pushl EX_INTERNAL|0x206 | |
293 | call EXCEPTION | |
294 | pop %ebx | |
295 | jmp L_exit | |
296 | ||
297 | L_bugged_2: | |
298 | pushl EX_INTERNAL|0x209 | |
299 | call EXCEPTION | |
300 | pop %ebx | |
301 | jmp L_exit | |
302 | ||
303 | L_bugged_3: | |
304 | pushl EX_INTERNAL|0x210 | |
305 | call EXCEPTION | |
306 | pop %ebx | |
307 | jmp L_exit | |
308 | ||
309 | L_bugged_4: | |
310 | pushl EX_INTERNAL|0x211 | |
311 | call EXCEPTION | |
312 | pop %ebx | |
313 | jmp L_exit | |
314 | ||
315 | L_bugged: | |
316 | pushl EX_INTERNAL|0x212 | |
317 | call EXCEPTION | |
318 | pop %ebx | |
319 | jmp L_exit | |
320 | #endif PARANOID | |
321 | ||
322 | ||
323 | L_store: | |
324 | /*------------------------------+ | |
325 | | Store the result | | |
326 | +------------------------------*/ | |
327 | movl %eax,SIGH(%edi) | |
328 | movl %ebx,SIGL(%edi) | |
329 | ||
330 | movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */ | |
331 | ||
332 | cmpl EXP_UNDER,EXP(%edi) | |
333 | jle L_underflow | |
334 | ||
335 | L_exit: | |
336 | popl %ebx | |
337 | popl %edi | |
338 | popl %esi | |
339 | leave | |
340 | ret | |
341 | ||
342 | ||
343 | L_underflow: | |
344 | push %edi | |
345 | call _arith_underflow | |
346 | pop %ebx | |
347 | jmp L_exit | |
348 |