Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / gnu / fpemul / reg_div.s
1         .file   "reg_div.S"
2 /*
3  *  reg_div.S
4  *
5  * Divide one FPU_REG by another and put the result in a destination FPU_REG.
6  *
7  * Call from C as:
8  *   void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,
9  *
10  *
11  * Copyright (C) 1992,1993,1994
12  *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
13  *                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au
14  * All rights reserved.
15  *
16  * This copyright notice covers the redistribution and use of the
17  * FPU emulator developed by W. Metzenthen. It covers only its use
18  * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
19  * use is not permitted under this copyright.
20  *
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions
23  * are met:
24  * 1. Redistributions of source code must retain the above copyright
25  *    notice, this list of conditions and the following disclaimer.
26  * 2. Redistributions in binary form must include information specifying
27  *    that source code for the emulator is freely available and include
28  *    either:
29  *      a) an offer to provide the source code for a nominal distribution
30  *         fee, or
31  *      b) list at least two alternative methods whereby the source
32  *         can be obtained, e.g. a publically accessible bulletin board
33  *         and an anonymous ftp site from which the software can be
34  *         downloaded.
35  * 3. All advertising materials specifically mentioning features or use of
36  *    this emulator must acknowledge that it was developed by W. Metzenthen.
37  * 4. The name of W. Metzenthen may not be used to endorse or promote
38  *    products derived from this software without specific prior written
39  *    permission.
40  *
41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
42  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
43  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
44  * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51  *
52  *
53  * The purpose of this copyright, based upon the Berkeley copyright, is to
54  * ensure that the covered software remains freely available to everyone.
55  *
56  * The software (with necessary differences) is also available, but under
57  * the terms of the GNU copyleft, for the Linux operating system and for
58  * the djgpp ms-dos extender.
59  *
60  * W. Metzenthen   June 1994.
61  *
62  * 
63  * $FreeBSD: src/sys/gnu/i386/fpemul/reg_div.s,v 1.9.2.1 2000/07/07 00:38:42 obrien Exp $
64  *
65  */
66
67 #include <gnu/i386/fpemul/fpu_asm.h>
68
69 .text
70 ENTRY(reg_div)
71         pushl   %ebp
72         movl    %esp,%ebp
73
74         pushl   %esi
75         pushl   %edi
76         pushl   %ebx
77
78         movl    PARAM1,%esi
79         movl    PARAM2,%ebx
80         movl    PARAM3,%edi
81
82         movb    TAG(%esi),%al
83         orb     TAG(%ebx),%al
84
85         jne     L_div_special           /* Not (both numbers TW_Valid) */
86
87 #ifdef DENORM_OPERAND
88 /* Check for denormals */
89         cmpl    EXP_UNDER,EXP(%esi)
90         jg      xL_arg1_not_denormal
91
92         call    _denormal_operand
93         orl     %eax,%eax
94         jnz     FPU_Arith_exit
95
96 xL_arg1_not_denormal:
97         cmpl    EXP_UNDER,EXP(%ebx)
98         jg      xL_arg2_not_denormal
99
100         call    _denormal_operand
101         orl     %eax,%eax
102         jnz     FPU_Arith_exit
103
104 xL_arg2_not_denormal:
105 #endif DENORM_OPERAND
106
107 /* Both arguments are TW_Valid */
108         movb    TW_Valid,TAG(%edi)
109
110         movb    SIGN(%esi),%cl
111         cmpb    %cl,SIGN(%ebx)
112         setne   (%edi)     /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
113
114         movl    EXP(%esi),%edx
115         movl    EXP(%ebx),%eax
116         subl    %eax,%edx
117         addl    EXP_BIAS,%edx
118         movl    %edx,EXP(%edi)
119
120         jmp     _divide_kernel
121
122
123 /*-----------------------------------------------------------------------*/
124 L_div_special:
125         cmpb    TW_NaN,TAG(%esi)        /* A NaN with anything to give NaN */
126         je      L_arg1_NaN
127
128         cmpb    TW_NaN,TAG(%ebx)        /* A NaN with anything to give NaN */
129         jne     L_no_NaN_arg
130
131 /*  Operations on NaNs */
132 L_arg1_NaN:
133 L_arg2_NaN:
134         pushl   %edi                    /* Destination */
135         pushl   %ebx
136         pushl   %esi
137         call    _real_2op_NaN
138         jmp     LDiv_exit
139
140 /* Invalid operations */
141 L_zero_zero:
142 L_inf_inf:
143         pushl   %edi                    /* Destination */
144         call    _arith_invalid          /* 0/0 or Infinity/Infinity */
145         jmp     LDiv_exit
146
147 L_no_NaN_arg:
148         cmpb    TW_Infinity,TAG(%esi)
149         jne     L_arg1_not_inf
150
151         cmpb    TW_Infinity,TAG(%ebx)
152         je      L_inf_inf               /* invalid operation */
153
154         cmpb    TW_Valid,TAG(%ebx)
155         je      L_inf_valid
156
157 #ifdef PARANOID
158         /* arg2 must be zero or valid */
159         cmpb    TW_Zero,TAG(%ebx)
160         ja      L_unknown_tags
161 #endif PARANOID
162
163         /* Note that p16-9 says that infinity/0 returns infinity */
164         jmp     L_copy_arg1             /* Answer is Inf */
165
166 L_inf_valid:
167 #ifdef DENORM_OPERAND
168         cmpl    EXP_UNDER,EXP(%ebx)
169         jg      L_copy_arg1             /* Answer is Inf */
170
171         call    _denormal_operand
172         orl     %eax,%eax
173         jnz     FPU_Arith_exit
174 #endif DENORM_OPERAND
175
176         jmp     L_copy_arg1             /* Answer is Inf */
177
178 L_arg1_not_inf:
179         cmpb    TW_Zero,TAG(%ebx)       /* Priority to div-by-zero error */
180         jne     L_arg2_not_zero
181
182         cmpb    TW_Zero,TAG(%esi)
183         je      L_zero_zero             /* invalid operation */
184
185 #ifdef PARANOID
186         /* arg1 must be valid */
187         cmpb    TW_Valid,TAG(%esi)
188         ja      L_unknown_tags
189 #endif PARANOID
190
191 /* Division by zero error */
192         pushl   %edi                    /* destination */
193         movb    SIGN(%esi),%al
194         xorb    SIGN(%ebx),%al
195         pushl   %eax                    /* lower 8 bits have the sign */
196         call    _divide_by_zero
197         jmp     LDiv_exit
198
199 L_arg2_not_zero:
200         cmpb    TW_Infinity,TAG(%ebx)
201         jne     L_arg2_not_inf
202
203 #ifdef DENORM_OPERAND
204         cmpb    TW_Valid,TAG(%esi)
205         jne     L_return_zero
206
207         cmpl    EXP_UNDER,EXP(%esi)
208         jg      L_return_zero           /* Answer is zero */
209
210         call    _denormal_operand
211         orl     %eax,%eax
212         jnz     FPU_Arith_exit
213 #endif DENORM_OPERAND
214
215         jmp     L_return_zero           /* Answer is zero */
216
217 L_arg2_not_inf:
218
219 #ifdef PARANOID
220         cmpb    TW_Zero,TAG(%esi)
221         jne     L_unknown_tags
222 #endif PARANOID
223
224         /* arg1 is zero, arg2 is not Infinity or a NaN */
225
226 #ifdef DENORM_OPERAND
227         cmpl    EXP_UNDER,EXP(%ebx)
228         jg      L_copy_arg1             /* Answer is zero */
229
230         call    _denormal_operand
231         orl     %eax,%eax
232         jnz     FPU_Arith_exit
233 #endif DENORM_OPERAND
234
235 L_copy_arg1:
236         movb    TAG(%esi),%al
237         movb    %al,TAG(%edi)
238         movl    EXP(%esi),%eax
239         movl    %eax,EXP(%edi)
240         movl    SIGL(%esi),%eax
241         movl    %eax,SIGL(%edi)
242         movl    SIGH(%esi),%eax
243         movl    %eax,SIGH(%edi)
244
245         movb    SIGN(%esi),%cl
246         cmpb    %cl,SIGN(%ebx)
247         jne     LDiv_negative_result
248
249         movb    SIGN_POS,SIGN(%edi)
250         jmp     LDiv_exit
251
252 LDiv_set_result_sign:
253         movb    SIGN(%esi),%cl
254         cmpb    %cl,SIGN(%edi)
255         jne     LDiv_negative_result
256
257         movb    SIGN_POS,SIGN(%ebx)
258         jmp     LDiv_exit
259
260 LDiv_negative_result:
261         movb    SIGN_NEG,SIGN(%edi)
262
263 LDiv_exit:
264         leal    -12(%ebp),%esp
265
266         popl    %ebx
267         popl    %edi
268         popl    %esi
269         leave
270         ret
271
272
273 L_return_zero:
274         movb    TW_Zero,TAG(%edi)
275         jmp     LDiv_set_result_sign
276
277 #ifdef PARANOID
278 L_unknown_tags:
279         push    EX_INTERNAL | 0x208
280         call    EXCEPTION
281
282         /* Generate a NaN for unknown tags */
283         movl    _CONST_QNaN,%eax
284         movl    %eax,(%edi)
285         movl    _CONST_QNaN+4,%eax
286         movl    %eax,SIGL(%edi)
287         movl    _CONST_QNaN+8,%eax
288         movl    %eax,SIGH(%edi)
289         jmp     LDiv_exit
290 #endif PARANOID