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