xref: /OK3568_Linux_fs/kernel/arch/x86/math-emu/reg_u_div.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun	.file	"reg_u_div.S"
3*4882a593Smuzhiyun/*---------------------------------------------------------------------------+
4*4882a593Smuzhiyun |  reg_u_div.S                                                              |
5*4882a593Smuzhiyun |                                                                           |
6*4882a593Smuzhiyun | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
7*4882a593Smuzhiyun |                                                                           |
8*4882a593Smuzhiyun | Copyright (C) 1992,1993,1995,1997                                         |
9*4882a593Smuzhiyun |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
10*4882a593Smuzhiyun |                  E-mail   billm@suburbia.net                              |
11*4882a593Smuzhiyun |                                                                           |
12*4882a593Smuzhiyun |                                                                           |
13*4882a593Smuzhiyun +---------------------------------------------------------------------------*/
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun/*---------------------------------------------------------------------------+
16*4882a593Smuzhiyun | Call from C as:                                                           |
17*4882a593Smuzhiyun |    int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                   |
18*4882a593Smuzhiyun |                unsigned int control_word, char *sign)                     |
19*4882a593Smuzhiyun |                                                                           |
20*4882a593Smuzhiyun |  Does not compute the destination exponent, but does adjust it.           |
21*4882a593Smuzhiyun |                                                                           |
22*4882a593Smuzhiyun |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
23*4882a593Smuzhiyun |    one was raised, or -1 on internal error.                               |
24*4882a593Smuzhiyun +---------------------------------------------------------------------------*/
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun#include "exception.h"
27*4882a593Smuzhiyun#include "fpu_emu.h"
28*4882a593Smuzhiyun#include "control_w.h"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun/* #define	dSIGL(x)	(x) */
32*4882a593Smuzhiyun/* #define	dSIGH(x)	4(x) */
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun#ifndef NON_REENTRANT_FPU
36*4882a593Smuzhiyun/*
37*4882a593Smuzhiyun	Local storage on the stack:
38*4882a593Smuzhiyun	Result:		FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
39*4882a593Smuzhiyun	Overflow flag:	ovfl_flag
40*4882a593Smuzhiyun */
41*4882a593Smuzhiyun#define FPU_accum_3	-4(%ebp)
42*4882a593Smuzhiyun#define FPU_accum_2	-8(%ebp)
43*4882a593Smuzhiyun#define FPU_accum_1	-12(%ebp)
44*4882a593Smuzhiyun#define FPU_accum_0	-16(%ebp)
45*4882a593Smuzhiyun#define FPU_result_1	-20(%ebp)
46*4882a593Smuzhiyun#define FPU_result_2	-24(%ebp)
47*4882a593Smuzhiyun#define FPU_ovfl_flag	-28(%ebp)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun#else
50*4882a593Smuzhiyun.data
51*4882a593Smuzhiyun/*
52*4882a593Smuzhiyun	Local storage in a static area:
53*4882a593Smuzhiyun	Result:		FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0
54*4882a593Smuzhiyun	Overflow flag:	ovfl_flag
55*4882a593Smuzhiyun */
56*4882a593Smuzhiyun	.align 4,0
57*4882a593SmuzhiyunFPU_accum_3:
58*4882a593Smuzhiyun	.long	0
59*4882a593SmuzhiyunFPU_accum_2:
60*4882a593Smuzhiyun	.long	0
61*4882a593SmuzhiyunFPU_accum_1:
62*4882a593Smuzhiyun	.long	0
63*4882a593SmuzhiyunFPU_accum_0:
64*4882a593Smuzhiyun	.long	0
65*4882a593SmuzhiyunFPU_result_1:
66*4882a593Smuzhiyun	.long	0
67*4882a593SmuzhiyunFPU_result_2:
68*4882a593Smuzhiyun	.long	0
69*4882a593SmuzhiyunFPU_ovfl_flag:
70*4882a593Smuzhiyun	.byte	0
71*4882a593Smuzhiyun#endif /* NON_REENTRANT_FPU */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun#define REGA	PARAM1
74*4882a593Smuzhiyun#define REGB	PARAM2
75*4882a593Smuzhiyun#define DEST	PARAM3
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun.text
78*4882a593SmuzhiyunSYM_FUNC_START(FPU_u_div)
79*4882a593Smuzhiyun	pushl	%ebp
80*4882a593Smuzhiyun	movl	%esp,%ebp
81*4882a593Smuzhiyun#ifndef NON_REENTRANT_FPU
82*4882a593Smuzhiyun	subl	$28,%esp
83*4882a593Smuzhiyun#endif /* NON_REENTRANT_FPU */
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun	pushl	%esi
86*4882a593Smuzhiyun	pushl	%edi
87*4882a593Smuzhiyun	pushl	%ebx
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun	movl	REGA,%esi
90*4882a593Smuzhiyun	movl	REGB,%ebx
91*4882a593Smuzhiyun	movl	DEST,%edi
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun	movswl	EXP(%esi),%edx
94*4882a593Smuzhiyun	movswl	EXP(%ebx),%eax
95*4882a593Smuzhiyun	subl	%eax,%edx
96*4882a593Smuzhiyun	addl	EXP_BIAS,%edx
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun	/* A denormal and a large number can cause an exponent underflow */
99*4882a593Smuzhiyun	cmpl	EXP_WAY_UNDER,%edx
100*4882a593Smuzhiyun	jg	xExp_not_underflow
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun	/* Set to a really low value allow correct handling */
103*4882a593Smuzhiyun	movl	EXP_WAY_UNDER,%edx
104*4882a593Smuzhiyun
105*4882a593SmuzhiyunxExp_not_underflow:
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun	movw    %dx,EXP(%edi)
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun#ifdef PARANOID
110*4882a593Smuzhiyun/*	testl	$0x80000000, SIGH(%esi)	// Dividend */
111*4882a593Smuzhiyun/*	je	L_bugged */
112*4882a593Smuzhiyun	testl	$0x80000000, SIGH(%ebx)	/* Divisor */
113*4882a593Smuzhiyun	je	L_bugged
114*4882a593Smuzhiyun#endif /* PARANOID */
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun/* Check if the divisor can be treated as having just 32 bits */
117*4882a593Smuzhiyun	cmpl	$0,SIGL(%ebx)
118*4882a593Smuzhiyun	jnz	L_Full_Division	/* Can't do a quick divide */
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun/* We should be able to zip through the division here */
121*4882a593Smuzhiyun	movl	SIGH(%ebx),%ecx	/* The divisor */
122*4882a593Smuzhiyun	movl	SIGH(%esi),%edx	/* Dividend */
123*4882a593Smuzhiyun	movl	SIGL(%esi),%eax	/* Dividend */
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun	cmpl	%ecx,%edx
126*4882a593Smuzhiyun	setaeb	FPU_ovfl_flag	/* Keep a record */
127*4882a593Smuzhiyun	jb	L_no_adjust
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun	subl	%ecx,%edx	/* Prevent the overflow */
130*4882a593Smuzhiyun
131*4882a593SmuzhiyunL_no_adjust:
132*4882a593Smuzhiyun	/* Divide the 64 bit number by the 32 bit denominator */
133*4882a593Smuzhiyun	divl	%ecx
134*4882a593Smuzhiyun	movl	%eax,FPU_result_2
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun	/* Work on the remainder of the first division */
137*4882a593Smuzhiyun	xorl	%eax,%eax
138*4882a593Smuzhiyun	divl	%ecx
139*4882a593Smuzhiyun	movl	%eax,FPU_result_1
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun	/* Work on the remainder of the 64 bit division */
142*4882a593Smuzhiyun	xorl	%eax,%eax
143*4882a593Smuzhiyun	divl	%ecx
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun	testb	$255,FPU_ovfl_flag	/* was the num > denom ? */
146*4882a593Smuzhiyun	je	L_no_overflow
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun	/* Do the shifting here */
149*4882a593Smuzhiyun	/* increase the exponent */
150*4882a593Smuzhiyun	incw	EXP(%edi)
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun	/* shift the mantissa right one bit */
153*4882a593Smuzhiyun	stc			/* To set the ms bit */
154*4882a593Smuzhiyun	rcrl	FPU_result_2
155*4882a593Smuzhiyun	rcrl	FPU_result_1
156*4882a593Smuzhiyun	rcrl	%eax
157*4882a593Smuzhiyun
158*4882a593SmuzhiyunL_no_overflow:
159*4882a593Smuzhiyun	jmp	LRound_precision	/* Do the rounding as required */
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun/*---------------------------------------------------------------------------+
163*4882a593Smuzhiyun |  Divide:   Return  arg1/arg2 to arg3.                                     |
164*4882a593Smuzhiyun |                                                                           |
165*4882a593Smuzhiyun |  This routine does not use the exponents of arg1 and arg2, but does       |
166*4882a593Smuzhiyun |  adjust the exponent of arg3.                                             |
167*4882a593Smuzhiyun |                                                                           |
168*4882a593Smuzhiyun |  The maximum returned value is (ignoring exponents)                       |
169*4882a593Smuzhiyun |               .ffffffff ffffffff                                          |
170*4882a593Smuzhiyun |               ------------------  =  1.ffffffff fffffffe                  |
171*4882a593Smuzhiyun |               .80000000 00000000                                          |
172*4882a593Smuzhiyun | and the minimum is                                                        |
173*4882a593Smuzhiyun |               .80000000 00000000                                          |
174*4882a593Smuzhiyun |               ------------------  =  .80000000 00000001   (rounded)       |
175*4882a593Smuzhiyun |               .ffffffff ffffffff                                          |
176*4882a593Smuzhiyun |                                                                           |
177*4882a593Smuzhiyun +---------------------------------------------------------------------------*/
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun
180*4882a593SmuzhiyunL_Full_Division:
181*4882a593Smuzhiyun	/* Save extended dividend in local register */
182*4882a593Smuzhiyun	movl	SIGL(%esi),%eax
183*4882a593Smuzhiyun	movl	%eax,FPU_accum_2
184*4882a593Smuzhiyun	movl	SIGH(%esi),%eax
185*4882a593Smuzhiyun	movl	%eax,FPU_accum_3
186*4882a593Smuzhiyun	xorl	%eax,%eax
187*4882a593Smuzhiyun	movl	%eax,FPU_accum_1	/* zero the extension */
188*4882a593Smuzhiyun	movl	%eax,FPU_accum_0	/* zero the extension */
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun	movl	SIGL(%esi),%eax	/* Get the current num */
191*4882a593Smuzhiyun	movl	SIGH(%esi),%edx
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun/*----------------------------------------------------------------------*/
194*4882a593Smuzhiyun/* Initialization done.
195*4882a593Smuzhiyun   Do the first 32 bits. */
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun	movb	$0,FPU_ovfl_flag
198*4882a593Smuzhiyun	cmpl	SIGH(%ebx),%edx	/* Test for imminent overflow */
199*4882a593Smuzhiyun	jb	LLess_than_1
200*4882a593Smuzhiyun	ja	LGreater_than_1
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun	cmpl	SIGL(%ebx),%eax
203*4882a593Smuzhiyun	jb	LLess_than_1
204*4882a593Smuzhiyun
205*4882a593SmuzhiyunLGreater_than_1:
206*4882a593Smuzhiyun/* The dividend is greater or equal, would cause overflow */
207*4882a593Smuzhiyun	setaeb	FPU_ovfl_flag		/* Keep a record */
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun	subl	SIGL(%ebx),%eax
210*4882a593Smuzhiyun	sbbl	SIGH(%ebx),%edx	/* Prevent the overflow */
211*4882a593Smuzhiyun	movl	%eax,FPU_accum_2
212*4882a593Smuzhiyun	movl	%edx,FPU_accum_3
213*4882a593Smuzhiyun
214*4882a593SmuzhiyunLLess_than_1:
215*4882a593Smuzhiyun/* At this point, we have a dividend < divisor, with a record of
216*4882a593Smuzhiyun   adjustment in FPU_ovfl_flag */
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun	/* We will divide by a number which is too large */
219*4882a593Smuzhiyun	movl	SIGH(%ebx),%ecx
220*4882a593Smuzhiyun	addl	$1,%ecx
221*4882a593Smuzhiyun	jnc	LFirst_div_not_1
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun	/* here we need to divide by 100000000h,
224*4882a593Smuzhiyun	   i.e., no division at all.. */
225*4882a593Smuzhiyun	mov	%edx,%eax
226*4882a593Smuzhiyun	jmp	LFirst_div_done
227*4882a593Smuzhiyun
228*4882a593SmuzhiyunLFirst_div_not_1:
229*4882a593Smuzhiyun	divl	%ecx		/* Divide the numerator by the augmented
230*4882a593Smuzhiyun				   denom ms dw */
231*4882a593Smuzhiyun
232*4882a593SmuzhiyunLFirst_div_done:
233*4882a593Smuzhiyun	movl	%eax,FPU_result_2	/* Put the result in the answer */
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun	mull	SIGH(%ebx)	/* mul by the ms dw of the denom */
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun	subl	%eax,FPU_accum_2	/* Subtract from the num local reg */
238*4882a593Smuzhiyun	sbbl	%edx,FPU_accum_3
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun	movl	FPU_result_2,%eax	/* Get the result back */
241*4882a593Smuzhiyun	mull	SIGL(%ebx)	/* now mul the ls dw of the denom */
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun	subl	%eax,FPU_accum_1	/* Subtract from the num local reg */
244*4882a593Smuzhiyun	sbbl	%edx,FPU_accum_2
245*4882a593Smuzhiyun	sbbl	$0,FPU_accum_3
246*4882a593Smuzhiyun	je	LDo_2nd_32_bits		/* Must check for non-zero result here */
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun#ifdef PARANOID
249*4882a593Smuzhiyun	jb	L_bugged_1
250*4882a593Smuzhiyun#endif /* PARANOID */
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun	/* need to subtract another once of the denom */
253*4882a593Smuzhiyun	incl	FPU_result_2	/* Correct the answer */
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun	movl	SIGL(%ebx),%eax
256*4882a593Smuzhiyun	movl	SIGH(%ebx),%edx
257*4882a593Smuzhiyun	subl	%eax,FPU_accum_1	/* Subtract from the num local reg */
258*4882a593Smuzhiyun	sbbl	%edx,FPU_accum_2
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun#ifdef PARANOID
261*4882a593Smuzhiyun	sbbl	$0,FPU_accum_3
262*4882a593Smuzhiyun	jne	L_bugged_1	/* Must check for non-zero result here */
263*4882a593Smuzhiyun#endif /* PARANOID */
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun/*----------------------------------------------------------------------*/
266*4882a593Smuzhiyun/* Half of the main problem is done, there is just a reduced numerator
267*4882a593Smuzhiyun   to handle now.
268*4882a593Smuzhiyun   Work with the second 32 bits, FPU_accum_0 not used from now on */
269*4882a593SmuzhiyunLDo_2nd_32_bits:
270*4882a593Smuzhiyun	movl	FPU_accum_2,%edx	/* get the reduced num */
271*4882a593Smuzhiyun	movl	FPU_accum_1,%eax
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun	/* need to check for possible subsequent overflow */
274*4882a593Smuzhiyun	cmpl	SIGH(%ebx),%edx
275*4882a593Smuzhiyun	jb	LDo_2nd_div
276*4882a593Smuzhiyun	ja	LPrevent_2nd_overflow
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun	cmpl	SIGL(%ebx),%eax
279*4882a593Smuzhiyun	jb	LDo_2nd_div
280*4882a593Smuzhiyun
281*4882a593SmuzhiyunLPrevent_2nd_overflow:
282*4882a593Smuzhiyun/* The numerator is greater or equal, would cause overflow */
283*4882a593Smuzhiyun	/* prevent overflow */
284*4882a593Smuzhiyun	subl	SIGL(%ebx),%eax
285*4882a593Smuzhiyun	sbbl	SIGH(%ebx),%edx
286*4882a593Smuzhiyun	movl	%edx,FPU_accum_2
287*4882a593Smuzhiyun	movl	%eax,FPU_accum_1
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun	incl	FPU_result_2	/* Reflect the subtraction in the answer */
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun#ifdef PARANOID
292*4882a593Smuzhiyun	je	L_bugged_2	/* Can't bump the result to 1.0 */
293*4882a593Smuzhiyun#endif /* PARANOID */
294*4882a593Smuzhiyun
295*4882a593SmuzhiyunLDo_2nd_div:
296*4882a593Smuzhiyun	cmpl	$0,%ecx		/* augmented denom msw */
297*4882a593Smuzhiyun	jnz	LSecond_div_not_1
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun	/* %ecx == 0, we are dividing by 1.0 */
300*4882a593Smuzhiyun	mov	%edx,%eax
301*4882a593Smuzhiyun	jmp	LSecond_div_done
302*4882a593Smuzhiyun
303*4882a593SmuzhiyunLSecond_div_not_1:
304*4882a593Smuzhiyun	divl	%ecx		/* Divide the numerator by the denom ms dw */
305*4882a593Smuzhiyun
306*4882a593SmuzhiyunLSecond_div_done:
307*4882a593Smuzhiyun	movl	%eax,FPU_result_1	/* Put the result in the answer */
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun	mull	SIGH(%ebx)	/* mul by the ms dw of the denom */
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun	subl	%eax,FPU_accum_1	/* Subtract from the num local reg */
312*4882a593Smuzhiyun	sbbl	%edx,FPU_accum_2
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun#ifdef PARANOID
315*4882a593Smuzhiyun	jc	L_bugged_2
316*4882a593Smuzhiyun#endif /* PARANOID */
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun	movl	FPU_result_1,%eax	/* Get the result back */
319*4882a593Smuzhiyun	mull	SIGL(%ebx)	/* now mul the ls dw of the denom */
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun	subl	%eax,FPU_accum_0	/* Subtract from the num local reg */
322*4882a593Smuzhiyun	sbbl	%edx,FPU_accum_1	/* Subtract from the num local reg */
323*4882a593Smuzhiyun	sbbl	$0,FPU_accum_2
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun#ifdef PARANOID
326*4882a593Smuzhiyun	jc	L_bugged_2
327*4882a593Smuzhiyun#endif /* PARANOID */
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun	jz	LDo_3rd_32_bits
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun#ifdef PARANOID
332*4882a593Smuzhiyun	cmpl	$1,FPU_accum_2
333*4882a593Smuzhiyun	jne	L_bugged_2
334*4882a593Smuzhiyun#endif /* PARANOID */
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun	/* need to subtract another once of the denom */
337*4882a593Smuzhiyun	movl	SIGL(%ebx),%eax
338*4882a593Smuzhiyun	movl	SIGH(%ebx),%edx
339*4882a593Smuzhiyun	subl	%eax,FPU_accum_0	/* Subtract from the num local reg */
340*4882a593Smuzhiyun	sbbl	%edx,FPU_accum_1
341*4882a593Smuzhiyun	sbbl	$0,FPU_accum_2
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun#ifdef PARANOID
344*4882a593Smuzhiyun	jc	L_bugged_2
345*4882a593Smuzhiyun	jne	L_bugged_2
346*4882a593Smuzhiyun#endif /* PARANOID */
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun	addl	$1,FPU_result_1	/* Correct the answer */
349*4882a593Smuzhiyun	adcl	$0,FPU_result_2
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun#ifdef PARANOID
352*4882a593Smuzhiyun	jc	L_bugged_2	/* Must check for non-zero result here */
353*4882a593Smuzhiyun#endif /* PARANOID */
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun/*----------------------------------------------------------------------*/
356*4882a593Smuzhiyun/* The division is essentially finished here, we just need to perform
357*4882a593Smuzhiyun   tidying operations.
358*4882a593Smuzhiyun   Deal with the 3rd 32 bits */
359*4882a593SmuzhiyunLDo_3rd_32_bits:
360*4882a593Smuzhiyun	movl	FPU_accum_1,%edx		/* get the reduced num */
361*4882a593Smuzhiyun	movl	FPU_accum_0,%eax
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun	/* need to check for possible subsequent overflow */
364*4882a593Smuzhiyun	cmpl	SIGH(%ebx),%edx	/* denom */
365*4882a593Smuzhiyun	jb	LRound_prep
366*4882a593Smuzhiyun	ja	LPrevent_3rd_overflow
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun	cmpl	SIGL(%ebx),%eax	/* denom */
369*4882a593Smuzhiyun	jb	LRound_prep
370*4882a593Smuzhiyun
371*4882a593SmuzhiyunLPrevent_3rd_overflow:
372*4882a593Smuzhiyun	/* prevent overflow */
373*4882a593Smuzhiyun	subl	SIGL(%ebx),%eax
374*4882a593Smuzhiyun	sbbl	SIGH(%ebx),%edx
375*4882a593Smuzhiyun	movl	%edx,FPU_accum_1
376*4882a593Smuzhiyun	movl	%eax,FPU_accum_0
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun	addl	$1,FPU_result_1	/* Reflect the subtraction in the answer */
379*4882a593Smuzhiyun	adcl	$0,FPU_result_2
380*4882a593Smuzhiyun	jne	LRound_prep
381*4882a593Smuzhiyun	jnc	LRound_prep
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun	/* This is a tricky spot, there is an overflow of the answer */
384*4882a593Smuzhiyun	movb	$255,FPU_ovfl_flag		/* Overflow -> 1.000 */
385*4882a593Smuzhiyun
386*4882a593SmuzhiyunLRound_prep:
387*4882a593Smuzhiyun/*
388*4882a593Smuzhiyun * Prepare for rounding.
389*4882a593Smuzhiyun * To test for rounding, we just need to compare 2*accum with the
390*4882a593Smuzhiyun * denom.
391*4882a593Smuzhiyun */
392*4882a593Smuzhiyun	movl	FPU_accum_0,%ecx
393*4882a593Smuzhiyun	movl	FPU_accum_1,%edx
394*4882a593Smuzhiyun	movl	%ecx,%eax
395*4882a593Smuzhiyun	orl	%edx,%eax
396*4882a593Smuzhiyun	jz	LRound_ovfl		/* The accumulator contains zero. */
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun	/* Multiply by 2 */
399*4882a593Smuzhiyun	clc
400*4882a593Smuzhiyun	rcll	$1,%ecx
401*4882a593Smuzhiyun	rcll	$1,%edx
402*4882a593Smuzhiyun	jc	LRound_large		/* No need to compare, denom smaller */
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun	subl	SIGL(%ebx),%ecx
405*4882a593Smuzhiyun	sbbl	SIGH(%ebx),%edx
406*4882a593Smuzhiyun	jnc	LRound_not_small
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun	movl	$0x70000000,%eax	/* Denom was larger */
409*4882a593Smuzhiyun	jmp	LRound_ovfl
410*4882a593Smuzhiyun
411*4882a593SmuzhiyunLRound_not_small:
412*4882a593Smuzhiyun	jnz	LRound_large
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun	movl	$0x80000000,%eax	/* Remainder was exactly 1/2 denom */
415*4882a593Smuzhiyun	jmp	LRound_ovfl
416*4882a593Smuzhiyun
417*4882a593SmuzhiyunLRound_large:
418*4882a593Smuzhiyun	movl	$0xff000000,%eax	/* Denom was smaller */
419*4882a593Smuzhiyun
420*4882a593SmuzhiyunLRound_ovfl:
421*4882a593Smuzhiyun/* We are now ready to deal with rounding, but first we must get
422*4882a593Smuzhiyun   the bits properly aligned */
423*4882a593Smuzhiyun	testb	$255,FPU_ovfl_flag	/* was the num > denom ? */
424*4882a593Smuzhiyun	je	LRound_precision
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun	incw	EXP(%edi)
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun	/* shift the mantissa right one bit */
429*4882a593Smuzhiyun	stc			/* Will set the ms bit */
430*4882a593Smuzhiyun	rcrl	FPU_result_2
431*4882a593Smuzhiyun	rcrl	FPU_result_1
432*4882a593Smuzhiyun	rcrl	%eax
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun/* Round the result as required */
435*4882a593SmuzhiyunLRound_precision:
436*4882a593Smuzhiyun	decw	EXP(%edi)	/* binary point between 1st & 2nd bits */
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun	movl	%eax,%edx
439*4882a593Smuzhiyun	movl	FPU_result_1,%ebx
440*4882a593Smuzhiyun	movl	FPU_result_2,%eax
441*4882a593Smuzhiyun	jmp	fpu_reg_round
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun#ifdef PARANOID
445*4882a593Smuzhiyun/* The logic is wrong if we got here */
446*4882a593SmuzhiyunL_bugged:
447*4882a593Smuzhiyun	pushl	EX_INTERNAL|0x202
448*4882a593Smuzhiyun	call	EXCEPTION
449*4882a593Smuzhiyun	pop	%ebx
450*4882a593Smuzhiyun	jmp	L_exit
451*4882a593Smuzhiyun
452*4882a593SmuzhiyunL_bugged_1:
453*4882a593Smuzhiyun	pushl	EX_INTERNAL|0x203
454*4882a593Smuzhiyun	call	EXCEPTION
455*4882a593Smuzhiyun	pop	%ebx
456*4882a593Smuzhiyun	jmp	L_exit
457*4882a593Smuzhiyun
458*4882a593SmuzhiyunL_bugged_2:
459*4882a593Smuzhiyun	pushl	EX_INTERNAL|0x204
460*4882a593Smuzhiyun	call	EXCEPTION
461*4882a593Smuzhiyun	pop	%ebx
462*4882a593Smuzhiyun	jmp	L_exit
463*4882a593Smuzhiyun
464*4882a593SmuzhiyunL_exit:
465*4882a593Smuzhiyun	movl	$-1,%eax
466*4882a593Smuzhiyun	popl	%ebx
467*4882a593Smuzhiyun	popl	%edi
468*4882a593Smuzhiyun	popl	%esi
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun	leave
471*4882a593Smuzhiyun	RET
472*4882a593Smuzhiyun#endif /* PARANOID */
473*4882a593Smuzhiyun
474*4882a593SmuzhiyunSYM_FUNC_END(FPU_u_div)
475