Initial import from FreeBSD RELENG_4:
[games.git] / sys / platform / pc32 / gnu / fpemul / reg_u_sub.s
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,1994
13  *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
14  *                       Australia.  E-mail   billm@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, FreeBSD and NetBSD operating systems. Any other
20  * use is not permitted 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  * The purpose of this copyright, based upon the Berkeley copyright, is to
55  * ensure that the covered software remains freely available to everyone.
56  *
57  * The software (with necessary differences) is also available, but under
58  * the terms of the GNU copyleft, for the Linux operating system and for
59  * the djgpp ms-dos extender.
60  *
61  * W. Metzenthen   June 1994.
62  *
63  *
64  * $FreeBSD: src/sys/gnu/i386/fpemul/reg_u_sub.s,v 1.9 1999/08/28 00:42:58 peter Exp $
65  *
66  */
67
68 /*
69  |    Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
70  |    Takes two valid reg f.p. numbers (TW_Valid), which are
71  |    treated as unsigned numbers,
72  |    and returns their difference as a TW_Valid or TW_Zero f.p.
73  |    number.
74  |    The first number (arg1) must be the larger.
75  |    The returned number is normalized.
76  |    Basic checks are performed if PARANOID is defined.
77  */
78
79 #include <gnu/i386/fpemul/fpu_asm.h>
80
81 .text
82 ENTRY(reg_u_sub)
83         pushl   %ebp
84         movl    %esp,%ebp
85         pushl   %esi
86         pushl   %edi
87         pushl   %ebx
88
89         movl    PARAM1,%esi     /* source 1 */
90         movl    PARAM2,%edi     /* source 2 */
91
92 #ifdef DENORM_OPERAND
93         cmpl    EXP_UNDER,EXP(%esi)
94         jg      xOp1_not_denorm
95
96         call    _denormal_operand
97         orl     %eax,%eax
98         jnz     FPU_Arith_exit
99
100 xOp1_not_denorm:
101         cmpl    EXP_UNDER,EXP(%edi)
102         jg      xOp2_not_denorm
103
104         call    _denormal_operand
105         orl     %eax,%eax
106         jnz     FPU_Arith_exit
107
108 xOp2_not_denorm:
109 #endif DENORM_OPERAND
110
111 /*      xorl    %ecx,%ecx */
112         movl    EXP(%esi),%ecx
113         subl    EXP(%edi),%ecx  /* exp1 - exp2 */
114
115 #ifdef PARANOID
116         /* source 2 is always smaller than source 1 */
117 /*      jc      L_bugged */
118         js      L_bugged_1
119
120         testl   $0x80000000,SIGH(%edi)  /* The args are assumed to be be normalized */
121         je      L_bugged_2
122
123         testl   $0x80000000,SIGH(%esi)
124         je      L_bugged_2
125 #endif PARANOID
126
127 /*--------------------------------------+
128  |      Form a register holding the     |
129  |      smaller number                  |
130  +--------------------------------------*/
131         movl    SIGH(%edi),%eax /* register ms word */
132         movl    SIGL(%edi),%ebx /* register ls word */
133
134         movl    PARAM3,%edi     /* destination */
135         movl    EXP(%esi),%edx
136         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
137         movb    SIGN(%esi),%dl
138         movb    %dl,SIGN(%edi)  /* Copy the sign from the first arg */
139
140         xorl    %edx,%edx       /* register extension */
141
142 /*--------------------------------------+
143  |      Shift the temporary register    |
144  |      right the required number of    |
145  |      places.                         |
146  +--------------------------------------*/
147 L_shift_r:
148         cmpl    $32,%ecx                /* shrd only works for 0..31 bits */
149         jnc     L_more_than_31
150
151 /* less than 32 bits */
152         shrd    %cl,%ebx,%edx
153         shrd    %cl,%eax,%ebx
154         shr     %cl,%eax
155         jmp     L_shift_done
156
157 L_more_than_31:
158         cmpl    $64,%ecx
159         jnc     L_more_than_63
160
161         subb    $32,%cl
162         jz      L_exactly_32
163
164         shrd    %cl,%eax,%edx
165         shr     %cl,%eax
166         orl     %ebx,%ebx
167         jz      L_more_31_no_low        /* none of the lowest bits is set */
168
169         orl     $1,%edx                 /* record the fact in the extension */
170
171 L_more_31_no_low:
172         movl    %eax,%ebx
173         xorl    %eax,%eax
174         jmp     L_shift_done
175
176 L_exactly_32:
177         movl    %ebx,%edx
178         movl    %eax,%ebx
179         xorl    %eax,%eax
180         jmp     L_shift_done
181
182 L_more_than_63:
183         cmpw    $65,%cx
184         jnc     L_more_than_64
185
186         /* Shift right by 64 bits */
187         movl    %eax,%edx
188         orl     %ebx,%ebx
189         jz      L_more_63_no_low
190
191         orl     $1,%edx
192         jmp     L_more_63_no_low
193
194 L_more_than_64:
195         jne     L_more_than_65
196
197         /* Shift right by 65 bits */
198         /* Carry is clear if we get here */
199         movl    %eax,%edx
200         rcrl    %edx
201         jnc     L_shift_65_nc
202
203         orl     $1,%edx
204         jmp     L_more_63_no_low
205
206 L_shift_65_nc:
207         orl     %ebx,%ebx
208         jz      L_more_63_no_low
209
210         orl     $1,%edx
211         jmp     L_more_63_no_low
212
213 L_more_than_65:
214         movl    $1,%edx         /* The shifted nr always at least one '1' */
215
216 L_more_63_no_low:
217         xorl    %ebx,%ebx
218         xorl    %eax,%eax
219
220 L_shift_done:
221 L_subtr:
222 /*------------------------------+
223  |      Do the subtraction      |
224  +------------------------------*/
225         xorl    %ecx,%ecx
226         subl    %edx,%ecx
227         movl    %ecx,%edx
228         movl    SIGL(%esi),%ecx
229         sbbl    %ebx,%ecx
230         movl    %ecx,%ebx
231         movl    SIGH(%esi),%ecx
232         sbbl    %eax,%ecx
233         movl    %ecx,%eax
234
235 #ifdef PARANOID
236         /* We can never get a borrow */
237         jc      L_bugged
238 #endif PARANOID
239
240 /*--------------------------------------+
241  |      Normalize the result            |
242  +--------------------------------------*/
243         testl   $0x80000000,%eax
244         jnz     L_round         /* no shifting needed */
245
246         orl     %eax,%eax
247         jnz     L_shift_1       /* shift left 1 - 31 bits */
248
249         orl     %ebx,%ebx
250         jnz     L_shift_32      /* shift left 32 - 63 bits */
251
252 /*       A rare case, the only one which is non-zero if we got here
253 //         is:           1000000 .... 0000
254 //                      -0111111 .... 1111 1
255 //                       -------------------- 
256 //                       0000000 .... 0000 1  */
257
258         cmpl    $0x80000000,%edx
259         jnz     L_must_be_zero
260
261         /* Shift left 64 bits */
262         subl    $64,EXP(%edi)
263         movl    %edx,%eax
264         jmp     L_store
265
266 L_must_be_zero:
267 #ifdef PARANOID
268         orl     %edx,%edx
269         jnz     L_bugged_3
270 #endif PARANOID
271
272         /* The result is zero */
273         movb    TW_Zero,TAG(%edi)
274         movl    $0,EXP(%edi)            /* exponent */
275         movl    $0,SIGL(%edi)
276         movl    $0,SIGH(%edi)
277         jmp     L_exit          /* Does not underflow */
278
279 L_shift_32:
280         movl    %ebx,%eax
281         movl    %edx,%ebx
282         movl    $0,%edx
283         subl    $32,EXP(%edi)   /* Can get underflow here */
284
285 /* We need to shift left by 1 - 31 bits */
286 L_shift_1:
287         bsrl    %eax,%ecx       /* get the required shift in %ecx */
288         subl    $31,%ecx
289         negl    %ecx
290         shld    %cl,%ebx,%eax
291         shld    %cl,%edx,%ebx
292         shl     %cl,%edx
293         subl    %ecx,EXP(%edi)  /* Can get underflow here */
294
295 L_round:
296         jmp     FPU_round       /* Round the result */
297
298
299 #ifdef PARANOID
300 L_bugged_1:
301         pushl   EX_INTERNAL|0x206
302         call    EXCEPTION
303         pop     %ebx
304         jmp     L_exit
305
306 L_bugged_2:
307         pushl   EX_INTERNAL|0x209
308         call    EXCEPTION
309         pop     %ebx
310         jmp     L_exit
311
312 L_bugged_3:
313         pushl   EX_INTERNAL|0x210
314         call    EXCEPTION
315         pop     %ebx
316         jmp     L_exit
317
318 L_bugged_4:
319         pushl   EX_INTERNAL|0x211
320         call    EXCEPTION
321         pop     %ebx
322         jmp     L_exit
323
324 L_bugged:
325         pushl   EX_INTERNAL|0x212
326         call    EXCEPTION
327         pop     %ebx
328         jmp     L_exit
329 #endif PARANOID
330
331
332 L_store:
333 /*------------------------------+
334  |      Store the result        |
335  +------------------------------*/
336         movl    %eax,SIGH(%edi)
337         movl    %ebx,SIGL(%edi)
338
339         movb    TW_Valid,TAG(%edi)              /* Set the tags to TW_Valid */
340
341         cmpl    EXP_UNDER,EXP(%edi)
342         jle     L_underflow
343
344 L_exit:
345         popl    %ebx
346         popl    %edi
347         popl    %esi
348         leave
349         ret
350
351
352 L_underflow:
353         push    %edi
354         call    _arith_underflow
355         pop     %ebx
356         jmp     L_exit
357