xref: /openbmc/linux/arch/x86/math-emu/reg_round.S (revision bd6be579a79c6d824fd8e24f168f372062fd15d6)
1da957e11SThomas Gleixner	.file "reg_round.S"
2da957e11SThomas Gleixner/*---------------------------------------------------------------------------+
3da957e11SThomas Gleixner |  reg_round.S                                                              |
4da957e11SThomas Gleixner |                                                                           |
5da957e11SThomas Gleixner | Rounding/truncation/etc for FPU basic arithmetic functions.               |
6da957e11SThomas Gleixner |                                                                           |
7da957e11SThomas Gleixner | Copyright (C) 1993,1995,1997                                              |
8da957e11SThomas Gleixner |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
9da957e11SThomas Gleixner |                       Australia.  E-mail billm@suburbia.net               |
10da957e11SThomas Gleixner |                                                                           |
11da957e11SThomas Gleixner | This code has four possible entry points.                                 |
12da957e11SThomas Gleixner | The following must be entered by a jmp instruction:                       |
13da957e11SThomas Gleixner |   fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit.                  |
14da957e11SThomas Gleixner |                                                                           |
15da957e11SThomas Gleixner | The FPU_round entry point is intended to be used by C code.               |
16da957e11SThomas Gleixner | From C, call as:                                                          |
17da957e11SThomas Gleixner |  int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
18da957e11SThomas Gleixner |                                                                           |
19da957e11SThomas Gleixner |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
20da957e11SThomas Gleixner |    one was raised, or -1 on internal error.                               |
21da957e11SThomas Gleixner |                                                                           |
22da957e11SThomas Gleixner | For correct "up" and "down" rounding, the argument must have the correct  |
23da957e11SThomas Gleixner | sign.                                                                     |
24da957e11SThomas Gleixner |                                                                           |
25da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
26da957e11SThomas Gleixner
27da957e11SThomas Gleixner/*---------------------------------------------------------------------------+
28da957e11SThomas Gleixner | Four entry points.                                                        |
29da957e11SThomas Gleixner |                                                                           |
30da957e11SThomas Gleixner | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points:     |
31da957e11SThomas Gleixner |  %eax:%ebx  64 bit significand                                            |
32da957e11SThomas Gleixner |  %edx       32 bit extension of the significand                           |
33da957e11SThomas Gleixner |  %edi       pointer to an FPU_REG for the result to be stored             |
34da957e11SThomas Gleixner |  stack      calling function must have set up a C stack frame and         |
35da957e11SThomas Gleixner |             pushed %esi, %edi, and %ebx                                   |
36da957e11SThomas Gleixner |                                                                           |
37da957e11SThomas Gleixner | Needed just for the fpu_reg_round_sqrt entry point:                       |
38da957e11SThomas Gleixner |  %cx  A control word in the same format as the FPU control word.          |
39da957e11SThomas Gleixner | Otherwise, PARAM4 must give such a value.                                 |
40da957e11SThomas Gleixner |                                                                           |
41da957e11SThomas Gleixner |                                                                           |
42da957e11SThomas Gleixner | The significand and its extension are assumed to be exact in the          |
43da957e11SThomas Gleixner | following sense:                                                          |
44da957e11SThomas Gleixner |   If the significand by itself is the exact result then the significand   |
45da957e11SThomas Gleixner |   extension (%edx) must contain 0, otherwise the significand extension    |
46da957e11SThomas Gleixner |   must be non-zero.                                                       |
47da957e11SThomas Gleixner |   If the significand extension is non-zero then the significand is        |
48da957e11SThomas Gleixner |   smaller than the magnitude of the correct exact result by an amount     |
49da957e11SThomas Gleixner |   greater than zero and less than one ls bit of the significand.          |
50da957e11SThomas Gleixner |   The significand extension is only required to have three possible       |
51da957e11SThomas Gleixner |   non-zero values:                                                        |
52da957e11SThomas Gleixner |       less than 0x80000000  <=> the significand is less than 1/2 an ls    |
53da957e11SThomas Gleixner |                                 bit smaller than the magnitude of the     |
54da957e11SThomas Gleixner |                                 true exact result.                        |
55da957e11SThomas Gleixner |         exactly 0x80000000  <=> the significand is exactly 1/2 an ls bit  |
56da957e11SThomas Gleixner |                                 smaller than the magnitude of the true    |
57da957e11SThomas Gleixner |                                 exact result.                             |
58da957e11SThomas Gleixner |    greater than 0x80000000  <=> the significand is more than 1/2 an ls    |
59da957e11SThomas Gleixner |                                 bit smaller than the magnitude of the     |
60da957e11SThomas Gleixner |                                 true exact result.                        |
61da957e11SThomas Gleixner |                                                                           |
62da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
63da957e11SThomas Gleixner
64da957e11SThomas Gleixner/*---------------------------------------------------------------------------+
65da957e11SThomas Gleixner |  The code in this module has become quite complex, but it should handle   |
66da957e11SThomas Gleixner |  all of the FPU flags which are set at this stage of the basic arithmetic |
67da957e11SThomas Gleixner |  computations.                                                            |
68da957e11SThomas Gleixner |  There are a few rare cases where the results are not set identically to  |
69da957e11SThomas Gleixner |  a real FPU. These require a bit more thought because at this stage the   |
70da957e11SThomas Gleixner |  results of the code here appear to be more consistent...                 |
71da957e11SThomas Gleixner |  This may be changed in a future version.                                 |
72da957e11SThomas Gleixner +---------------------------------------------------------------------------*/
73da957e11SThomas Gleixner
74da957e11SThomas Gleixner
75da957e11SThomas Gleixner#include "fpu_emu.h"
76da957e11SThomas Gleixner#include "exception.h"
77da957e11SThomas Gleixner#include "control_w.h"
78da957e11SThomas Gleixner
79da957e11SThomas Gleixner/* Flags for FPU_bits_lost */
80da957e11SThomas Gleixner#define	LOST_DOWN	$1
81da957e11SThomas Gleixner#define	LOST_UP		$2
82da957e11SThomas Gleixner
83da957e11SThomas Gleixner/* Flags for FPU_denormal */
84da957e11SThomas Gleixner#define	DENORMAL	$1
85da957e11SThomas Gleixner#define	UNMASKED_UNDERFLOW $2
86da957e11SThomas Gleixner
87da957e11SThomas Gleixner
88da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU
89da957e11SThomas Gleixner/*	Make the code re-entrant by putting
90da957e11SThomas Gleixner	local storage on the stack: */
91da957e11SThomas Gleixner#define FPU_bits_lost	(%esp)
92da957e11SThomas Gleixner#define FPU_denormal	1(%esp)
93da957e11SThomas Gleixner
94da957e11SThomas Gleixner#else
95da957e11SThomas Gleixner/*	Not re-entrant, so we can gain speed by putting
96da957e11SThomas Gleixner	local storage in a static area: */
97da957e11SThomas Gleixner.data
98da957e11SThomas Gleixner	.align 4,0
99da957e11SThomas GleixnerFPU_bits_lost:
100da957e11SThomas Gleixner	.byte	0
101da957e11SThomas GleixnerFPU_denormal:
102da957e11SThomas Gleixner	.byte	0
103da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */
104da957e11SThomas Gleixner
105da957e11SThomas Gleixner
106da957e11SThomas Gleixner.text
107da957e11SThomas Gleixner.globl fpu_reg_round
108da957e11SThomas Gleixner.globl fpu_Arith_exit
109da957e11SThomas Gleixner
110da957e11SThomas Gleixner/* Entry point when called from C */
111da957e11SThomas GleixnerENTRY(FPU_round)
112da957e11SThomas Gleixner	pushl	%ebp
113da957e11SThomas Gleixner	movl	%esp,%ebp
114da957e11SThomas Gleixner	pushl	%esi
115da957e11SThomas Gleixner	pushl	%edi
116da957e11SThomas Gleixner	pushl	%ebx
117da957e11SThomas Gleixner
118da957e11SThomas Gleixner	movl	PARAM1,%edi
119da957e11SThomas Gleixner	movl	SIGH(%edi),%eax
120da957e11SThomas Gleixner	movl	SIGL(%edi),%ebx
121da957e11SThomas Gleixner	movl	PARAM2,%edx
122da957e11SThomas Gleixner
123da957e11SThomas Gleixnerfpu_reg_round:			/* Normal entry point */
124da957e11SThomas Gleixner	movl	PARAM4,%ecx
125da957e11SThomas Gleixner
126da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU
127da957e11SThomas Gleixner	pushl	%ebx		/* adjust the stack pointer */
128da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */
129da957e11SThomas Gleixner
130da957e11SThomas Gleixner#ifdef PARANOID
131da957e11SThomas Gleixner/* Cannot use this here yet */
132da957e11SThomas Gleixner/*	orl	%eax,%eax */
133da957e11SThomas Gleixner/*	jns	L_entry_bugged */
134da957e11SThomas Gleixner#endif /* PARANOID */
135da957e11SThomas Gleixner
136da957e11SThomas Gleixner	cmpw	EXP_UNDER,EXP(%edi)
137da957e11SThomas Gleixner	jle	L_Make_denorm			/* The number is a de-normal */
138da957e11SThomas Gleixner
139da957e11SThomas Gleixner	movb	$0,FPU_denormal			/* 0 -> not a de-normal */
140da957e11SThomas Gleixner
141da957e11SThomas GleixnerDenorm_done:
142da957e11SThomas Gleixner	movb	$0,FPU_bits_lost		/* No bits yet lost in rounding */
143da957e11SThomas Gleixner
144da957e11SThomas Gleixner	movl	%ecx,%esi
145da957e11SThomas Gleixner	andl	CW_PC,%ecx
146da957e11SThomas Gleixner	cmpl	PR_64_BITS,%ecx
147da957e11SThomas Gleixner	je	LRound_To_64
148da957e11SThomas Gleixner
149da957e11SThomas Gleixner	cmpl	PR_53_BITS,%ecx
150da957e11SThomas Gleixner	je	LRound_To_53
151da957e11SThomas Gleixner
152da957e11SThomas Gleixner	cmpl	PR_24_BITS,%ecx
153da957e11SThomas Gleixner	je	LRound_To_24
154da957e11SThomas Gleixner
155da957e11SThomas Gleixner#ifdef PECULIAR_486
156da957e11SThomas Gleixner/* With the precision control bits set to 01 "(reserved)", a real 80486
157da957e11SThomas Gleixner   behaves as if the precision control bits were set to 11 "64 bits" */
158da957e11SThomas Gleixner	cmpl	PR_RESERVED_BITS,%ecx
159da957e11SThomas Gleixner	je	LRound_To_64
160da957e11SThomas Gleixner#ifdef PARANOID
161da957e11SThomas Gleixner	jmp	L_bugged_denorm_486
162da957e11SThomas Gleixner#endif /* PARANOID */
163da957e11SThomas Gleixner#else
164da957e11SThomas Gleixner#ifdef PARANOID
165da957e11SThomas Gleixner	jmp	L_bugged_denorm	/* There is no bug, just a bad control word */
166da957e11SThomas Gleixner#endif /* PARANOID */
167da957e11SThomas Gleixner#endif /* PECULIAR_486 */
168da957e11SThomas Gleixner
169da957e11SThomas Gleixner
170da957e11SThomas Gleixner/* Round etc to 24 bit precision */
171da957e11SThomas GleixnerLRound_To_24:
172da957e11SThomas Gleixner	movl	%esi,%ecx
173da957e11SThomas Gleixner	andl	CW_RC,%ecx
174da957e11SThomas Gleixner	cmpl	RC_RND,%ecx
175da957e11SThomas Gleixner	je	LRound_nearest_24
176da957e11SThomas Gleixner
177da957e11SThomas Gleixner	cmpl	RC_CHOP,%ecx
178da957e11SThomas Gleixner	je	LCheck_truncate_24
179da957e11SThomas Gleixner
180da957e11SThomas Gleixner	cmpl	RC_UP,%ecx		/* Towards +infinity */
181da957e11SThomas Gleixner	je	LUp_24
182da957e11SThomas Gleixner
183da957e11SThomas Gleixner	cmpl	RC_DOWN,%ecx		/* Towards -infinity */
184da957e11SThomas Gleixner	je	LDown_24
185da957e11SThomas Gleixner
186da957e11SThomas Gleixner#ifdef PARANOID
187da957e11SThomas Gleixner	jmp	L_bugged_round24
188da957e11SThomas Gleixner#endif /* PARANOID */
189da957e11SThomas Gleixner
190da957e11SThomas GleixnerLUp_24:
191da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
192da957e11SThomas Gleixner	jne	LCheck_truncate_24	/* If negative then  up==truncate */
193da957e11SThomas Gleixner
194da957e11SThomas Gleixner	jmp	LCheck_24_round_up
195da957e11SThomas Gleixner
196da957e11SThomas GleixnerLDown_24:
197da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
198da957e11SThomas Gleixner	je	LCheck_truncate_24	/* If positive then  down==truncate */
199da957e11SThomas Gleixner
200da957e11SThomas GleixnerLCheck_24_round_up:
201da957e11SThomas Gleixner	movl	%eax,%ecx
202da957e11SThomas Gleixner	andl	$0x000000ff,%ecx
203da957e11SThomas Gleixner	orl	%ebx,%ecx
204da957e11SThomas Gleixner	orl	%edx,%ecx
205da957e11SThomas Gleixner	jnz	LDo_24_round_up
206da957e11SThomas Gleixner	jmp	L_Re_normalise
207da957e11SThomas Gleixner
208da957e11SThomas GleixnerLRound_nearest_24:
209da957e11SThomas Gleixner	/* Do rounding of the 24th bit if needed (nearest or even) */
210da957e11SThomas Gleixner	movl	%eax,%ecx
211da957e11SThomas Gleixner	andl	$0x000000ff,%ecx
212da957e11SThomas Gleixner	cmpl	$0x00000080,%ecx
213da957e11SThomas Gleixner	jc	LCheck_truncate_24	/* less than half, no increment needed */
214da957e11SThomas Gleixner
215da957e11SThomas Gleixner	jne	LGreater_Half_24	/* greater than half, increment needed */
216da957e11SThomas Gleixner
217da957e11SThomas Gleixner	/* Possibly half, we need to check the ls bits */
218da957e11SThomas Gleixner	orl	%ebx,%ebx
219da957e11SThomas Gleixner	jnz	LGreater_Half_24	/* greater than half, increment needed */
220da957e11SThomas Gleixner
221da957e11SThomas Gleixner	orl	%edx,%edx
222da957e11SThomas Gleixner	jnz	LGreater_Half_24	/* greater than half, increment needed */
223da957e11SThomas Gleixner
224da957e11SThomas Gleixner	/* Exactly half, increment only if 24th bit is 1 (round to even) */
225da957e11SThomas Gleixner	testl	$0x00000100,%eax
226da957e11SThomas Gleixner	jz	LDo_truncate_24
227da957e11SThomas Gleixner
228da957e11SThomas GleixnerLGreater_Half_24:			/* Rounding: increment at the 24th bit */
229da957e11SThomas GleixnerLDo_24_round_up:
230da957e11SThomas Gleixner	andl	$0xffffff00,%eax	/* Truncate to 24 bits */
231da957e11SThomas Gleixner	xorl	%ebx,%ebx
232da957e11SThomas Gleixner	movb	LOST_UP,FPU_bits_lost
233da957e11SThomas Gleixner	addl	$0x00000100,%eax
234da957e11SThomas Gleixner	jmp	LCheck_Round_Overflow
235da957e11SThomas Gleixner
236da957e11SThomas GleixnerLCheck_truncate_24:
237da957e11SThomas Gleixner	movl	%eax,%ecx
238da957e11SThomas Gleixner	andl	$0x000000ff,%ecx
239da957e11SThomas Gleixner	orl	%ebx,%ecx
240da957e11SThomas Gleixner	orl	%edx,%ecx
241da957e11SThomas Gleixner	jz	L_Re_normalise		/* No truncation needed */
242da957e11SThomas Gleixner
243da957e11SThomas GleixnerLDo_truncate_24:
244da957e11SThomas Gleixner	andl	$0xffffff00,%eax	/* Truncate to 24 bits */
245da957e11SThomas Gleixner	xorl	%ebx,%ebx
246da957e11SThomas Gleixner	movb	LOST_DOWN,FPU_bits_lost
247da957e11SThomas Gleixner	jmp	L_Re_normalise
248da957e11SThomas Gleixner
249da957e11SThomas Gleixner
250da957e11SThomas Gleixner/* Round etc to 53 bit precision */
251da957e11SThomas GleixnerLRound_To_53:
252da957e11SThomas Gleixner	movl	%esi,%ecx
253da957e11SThomas Gleixner	andl	CW_RC,%ecx
254da957e11SThomas Gleixner	cmpl	RC_RND,%ecx
255da957e11SThomas Gleixner	je	LRound_nearest_53
256da957e11SThomas Gleixner
257da957e11SThomas Gleixner	cmpl	RC_CHOP,%ecx
258da957e11SThomas Gleixner	je	LCheck_truncate_53
259da957e11SThomas Gleixner
260da957e11SThomas Gleixner	cmpl	RC_UP,%ecx		/* Towards +infinity */
261da957e11SThomas Gleixner	je	LUp_53
262da957e11SThomas Gleixner
263da957e11SThomas Gleixner	cmpl	RC_DOWN,%ecx		/* Towards -infinity */
264da957e11SThomas Gleixner	je	LDown_53
265da957e11SThomas Gleixner
266da957e11SThomas Gleixner#ifdef PARANOID
267da957e11SThomas Gleixner	jmp	L_bugged_round53
268da957e11SThomas Gleixner#endif /* PARANOID */
269da957e11SThomas Gleixner
270da957e11SThomas GleixnerLUp_53:
271da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
272da957e11SThomas Gleixner	jne	LCheck_truncate_53	/* If negative then  up==truncate */
273da957e11SThomas Gleixner
274da957e11SThomas Gleixner	jmp	LCheck_53_round_up
275da957e11SThomas Gleixner
276da957e11SThomas GleixnerLDown_53:
277da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
278da957e11SThomas Gleixner	je	LCheck_truncate_53	/* If positive then  down==truncate */
279da957e11SThomas Gleixner
280da957e11SThomas GleixnerLCheck_53_round_up:
281da957e11SThomas Gleixner	movl	%ebx,%ecx
282da957e11SThomas Gleixner	andl	$0x000007ff,%ecx
283da957e11SThomas Gleixner	orl	%edx,%ecx
284da957e11SThomas Gleixner	jnz	LDo_53_round_up
285da957e11SThomas Gleixner	jmp	L_Re_normalise
286da957e11SThomas Gleixner
287da957e11SThomas GleixnerLRound_nearest_53:
288da957e11SThomas Gleixner	/* Do rounding of the 53rd bit if needed (nearest or even) */
289da957e11SThomas Gleixner	movl	%ebx,%ecx
290da957e11SThomas Gleixner	andl	$0x000007ff,%ecx
291da957e11SThomas Gleixner	cmpl	$0x00000400,%ecx
292da957e11SThomas Gleixner	jc	LCheck_truncate_53	/* less than half, no increment needed */
293da957e11SThomas Gleixner
294da957e11SThomas Gleixner	jnz	LGreater_Half_53	/* greater than half, increment needed */
295da957e11SThomas Gleixner
296da957e11SThomas Gleixner	/* Possibly half, we need to check the ls bits */
297da957e11SThomas Gleixner	orl	%edx,%edx
298da957e11SThomas Gleixner	jnz	LGreater_Half_53	/* greater than half, increment needed */
299da957e11SThomas Gleixner
300da957e11SThomas Gleixner	/* Exactly half, increment only if 53rd bit is 1 (round to even) */
301da957e11SThomas Gleixner	testl	$0x00000800,%ebx
302da957e11SThomas Gleixner	jz	LTruncate_53
303da957e11SThomas Gleixner
304da957e11SThomas GleixnerLGreater_Half_53:			/* Rounding: increment at the 53rd bit */
305da957e11SThomas GleixnerLDo_53_round_up:
306da957e11SThomas Gleixner	movb	LOST_UP,FPU_bits_lost
307da957e11SThomas Gleixner	andl	$0xfffff800,%ebx	/* Truncate to 53 bits */
308da957e11SThomas Gleixner	addl	$0x00000800,%ebx
309da957e11SThomas Gleixner	adcl	$0,%eax
310da957e11SThomas Gleixner	jmp	LCheck_Round_Overflow
311da957e11SThomas Gleixner
312da957e11SThomas GleixnerLCheck_truncate_53:
313da957e11SThomas Gleixner	movl	%ebx,%ecx
314da957e11SThomas Gleixner	andl	$0x000007ff,%ecx
315da957e11SThomas Gleixner	orl	%edx,%ecx
316da957e11SThomas Gleixner	jz	L_Re_normalise
317da957e11SThomas Gleixner
318da957e11SThomas GleixnerLTruncate_53:
319da957e11SThomas Gleixner	movb	LOST_DOWN,FPU_bits_lost
320da957e11SThomas Gleixner	andl	$0xfffff800,%ebx	/* Truncate to 53 bits */
321da957e11SThomas Gleixner	jmp	L_Re_normalise
322da957e11SThomas Gleixner
323da957e11SThomas Gleixner
324da957e11SThomas Gleixner/* Round etc to 64 bit precision */
325da957e11SThomas GleixnerLRound_To_64:
326da957e11SThomas Gleixner	movl	%esi,%ecx
327da957e11SThomas Gleixner	andl	CW_RC,%ecx
328da957e11SThomas Gleixner	cmpl	RC_RND,%ecx
329da957e11SThomas Gleixner	je	LRound_nearest_64
330da957e11SThomas Gleixner
331da957e11SThomas Gleixner	cmpl	RC_CHOP,%ecx
332da957e11SThomas Gleixner	je	LCheck_truncate_64
333da957e11SThomas Gleixner
334da957e11SThomas Gleixner	cmpl	RC_UP,%ecx		/* Towards +infinity */
335da957e11SThomas Gleixner	je	LUp_64
336da957e11SThomas Gleixner
337da957e11SThomas Gleixner	cmpl	RC_DOWN,%ecx		/* Towards -infinity */
338da957e11SThomas Gleixner	je	LDown_64
339da957e11SThomas Gleixner
340da957e11SThomas Gleixner#ifdef PARANOID
341da957e11SThomas Gleixner	jmp	L_bugged_round64
342da957e11SThomas Gleixner#endif /* PARANOID */
343da957e11SThomas Gleixner
344da957e11SThomas GleixnerLUp_64:
345da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
346da957e11SThomas Gleixner	jne	LCheck_truncate_64	/* If negative then  up==truncate */
347da957e11SThomas Gleixner
348da957e11SThomas Gleixner	orl	%edx,%edx
349da957e11SThomas Gleixner	jnz	LDo_64_round_up
350da957e11SThomas Gleixner	jmp	L_Re_normalise
351da957e11SThomas Gleixner
352da957e11SThomas GleixnerLDown_64:
353da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
354da957e11SThomas Gleixner	je	LCheck_truncate_64	/* If positive then  down==truncate */
355da957e11SThomas Gleixner
356da957e11SThomas Gleixner	orl	%edx,%edx
357da957e11SThomas Gleixner	jnz	LDo_64_round_up
358da957e11SThomas Gleixner	jmp	L_Re_normalise
359da957e11SThomas Gleixner
360da957e11SThomas GleixnerLRound_nearest_64:
361da957e11SThomas Gleixner	cmpl	$0x80000000,%edx
362da957e11SThomas Gleixner	jc	LCheck_truncate_64
363da957e11SThomas Gleixner
364da957e11SThomas Gleixner	jne	LDo_64_round_up
365da957e11SThomas Gleixner
366da957e11SThomas Gleixner	/* Now test for round-to-even */
367da957e11SThomas Gleixner	testb	$1,%bl
368da957e11SThomas Gleixner	jz	LCheck_truncate_64
369da957e11SThomas Gleixner
370da957e11SThomas GleixnerLDo_64_round_up:
371da957e11SThomas Gleixner	movb	LOST_UP,FPU_bits_lost
372da957e11SThomas Gleixner	addl	$1,%ebx
373da957e11SThomas Gleixner	adcl	$0,%eax
374da957e11SThomas Gleixner
375da957e11SThomas GleixnerLCheck_Round_Overflow:
376da957e11SThomas Gleixner	jnc	L_Re_normalise
377da957e11SThomas Gleixner
378da957e11SThomas Gleixner	/* Overflow, adjust the result (significand to 1.0) */
379da957e11SThomas Gleixner	rcrl	$1,%eax
380da957e11SThomas Gleixner	rcrl	$1,%ebx
381da957e11SThomas Gleixner	incw	EXP(%edi)
382da957e11SThomas Gleixner	jmp	L_Re_normalise
383da957e11SThomas Gleixner
384da957e11SThomas GleixnerLCheck_truncate_64:
385da957e11SThomas Gleixner	orl	%edx,%edx
386da957e11SThomas Gleixner	jz	L_Re_normalise
387da957e11SThomas Gleixner
388da957e11SThomas GleixnerLTruncate_64:
389da957e11SThomas Gleixner	movb	LOST_DOWN,FPU_bits_lost
390da957e11SThomas Gleixner
391da957e11SThomas GleixnerL_Re_normalise:
392da957e11SThomas Gleixner	testb	$0xff,FPU_denormal
393da957e11SThomas Gleixner	jnz	Normalise_result
394da957e11SThomas Gleixner
395da957e11SThomas GleixnerL_Normalised:
396da957e11SThomas Gleixner	movl	TAG_Valid,%edx
397da957e11SThomas Gleixner
398da957e11SThomas GleixnerL_deNormalised:
399da957e11SThomas Gleixner	cmpb	LOST_UP,FPU_bits_lost
400da957e11SThomas Gleixner	je	L_precision_lost_up
401da957e11SThomas Gleixner
402da957e11SThomas Gleixner	cmpb	LOST_DOWN,FPU_bits_lost
403da957e11SThomas Gleixner	je	L_precision_lost_down
404da957e11SThomas Gleixner
405da957e11SThomas GleixnerL_no_precision_loss:
406da957e11SThomas Gleixner	/* store the result */
407da957e11SThomas Gleixner
408da957e11SThomas GleixnerL_Store_significand:
409da957e11SThomas Gleixner	movl	%eax,SIGH(%edi)
410da957e11SThomas Gleixner	movl	%ebx,SIGL(%edi)
411da957e11SThomas Gleixner
412da957e11SThomas Gleixner	cmpw	EXP_OVER,EXP(%edi)
413da957e11SThomas Gleixner	jge	L_overflow
414da957e11SThomas Gleixner
415da957e11SThomas Gleixner	movl	%edx,%eax
416da957e11SThomas Gleixner
417da957e11SThomas Gleixner	/* Convert the exponent to 80x87 form. */
418da957e11SThomas Gleixner	addw	EXTENDED_Ebias,EXP(%edi)
419da957e11SThomas Gleixner	andw	$0x7fff,EXP(%edi)
420da957e11SThomas Gleixner
421da957e11SThomas Gleixnerfpu_reg_round_signed_special_exit:
422da957e11SThomas Gleixner
423da957e11SThomas Gleixner	cmpb	SIGN_POS,PARAM5
424da957e11SThomas Gleixner	je	fpu_reg_round_special_exit
425da957e11SThomas Gleixner
426da957e11SThomas Gleixner	orw	$0x8000,EXP(%edi)	/* Negative sign for the result. */
427da957e11SThomas Gleixner
428da957e11SThomas Gleixnerfpu_reg_round_special_exit:
429da957e11SThomas Gleixner
430da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU
431da957e11SThomas Gleixner	popl	%ebx		/* adjust the stack pointer */
432da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */
433da957e11SThomas Gleixner
434da957e11SThomas Gleixnerfpu_Arith_exit:
435da957e11SThomas Gleixner	popl	%ebx
436da957e11SThomas Gleixner	popl	%edi
437da957e11SThomas Gleixner	popl	%esi
438da957e11SThomas Gleixner	leave
439da957e11SThomas Gleixner	ret
440da957e11SThomas Gleixner
441da957e11SThomas Gleixner
442da957e11SThomas Gleixner/*
443da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to
444da957e11SThomas Gleixner * round-up.
445da957e11SThomas Gleixner */
446da957e11SThomas GleixnerL_precision_lost_up:
447da957e11SThomas Gleixner	push	%edx
448da957e11SThomas Gleixner	push	%eax
449da957e11SThomas Gleixner	call	set_precision_flag_up
450da957e11SThomas Gleixner	popl	%eax
451da957e11SThomas Gleixner	popl	%edx
452da957e11SThomas Gleixner	jmp	L_no_precision_loss
453da957e11SThomas Gleixner
454da957e11SThomas Gleixner/*
455da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to
456da957e11SThomas Gleixner * truncation.
457da957e11SThomas Gleixner */
458da957e11SThomas GleixnerL_precision_lost_down:
459da957e11SThomas Gleixner	push	%edx
460da957e11SThomas Gleixner	push	%eax
461da957e11SThomas Gleixner	call	set_precision_flag_down
462da957e11SThomas Gleixner	popl	%eax
463da957e11SThomas Gleixner	popl	%edx
464da957e11SThomas Gleixner	jmp	L_no_precision_loss
465da957e11SThomas Gleixner
466da957e11SThomas Gleixner
467da957e11SThomas Gleixner/*
468da957e11SThomas Gleixner * The number is a denormal (which might get rounded up to a normal)
469da957e11SThomas Gleixner * Shift the number right the required number of bits, which will
470da957e11SThomas Gleixner * have to be undone later...
471da957e11SThomas Gleixner */
472da957e11SThomas GleixnerL_Make_denorm:
473da957e11SThomas Gleixner	/* The action to be taken depends upon whether the underflow
474da957e11SThomas Gleixner	   exception is masked */
475da957e11SThomas Gleixner	testb	CW_Underflow,%cl		/* Underflow mask. */
476da957e11SThomas Gleixner	jz	Unmasked_underflow		/* Do not make a denormal. */
477da957e11SThomas Gleixner
478da957e11SThomas Gleixner	movb	DENORMAL,FPU_denormal
479da957e11SThomas Gleixner
480da957e11SThomas Gleixner	pushl	%ecx		/* Save */
481da957e11SThomas Gleixner	movw	EXP_UNDER+1,%cx
482da957e11SThomas Gleixner	subw	EXP(%edi),%cx
483da957e11SThomas Gleixner
484da957e11SThomas Gleixner	cmpw	$64,%cx	/* shrd only works for 0..31 bits */
485da957e11SThomas Gleixner	jnc	Denorm_shift_more_than_63
486da957e11SThomas Gleixner
487da957e11SThomas Gleixner	cmpw	$32,%cx	/* shrd only works for 0..31 bits */
488da957e11SThomas Gleixner	jnc	Denorm_shift_more_than_32
489da957e11SThomas Gleixner
490da957e11SThomas Gleixner/*
491da957e11SThomas Gleixner * We got here without jumps by assuming that the most common requirement
492da957e11SThomas Gleixner *   is for a small de-normalising shift.
493da957e11SThomas Gleixner * Shift by [1..31] bits
494da957e11SThomas Gleixner */
495da957e11SThomas Gleixner	addw	%cx,EXP(%edi)
496da957e11SThomas Gleixner	orl	%edx,%edx	/* extension */
497da957e11SThomas Gleixner	setne	%ch		/* Save whether %edx is non-zero */
498da957e11SThomas Gleixner	xorl	%edx,%edx
499da957e11SThomas Gleixner	shrd	%cl,%ebx,%edx
500da957e11SThomas Gleixner	shrd	%cl,%eax,%ebx
501da957e11SThomas Gleixner	shr	%cl,%eax
502da957e11SThomas Gleixner	orb	%ch,%dl
503da957e11SThomas Gleixner	popl	%ecx
504da957e11SThomas Gleixner	jmp	Denorm_done
505da957e11SThomas Gleixner
506da957e11SThomas Gleixner/* Shift by [32..63] bits */
507da957e11SThomas GleixnerDenorm_shift_more_than_32:
508da957e11SThomas Gleixner	addw	%cx,EXP(%edi)
509da957e11SThomas Gleixner	subb	$32,%cl
510da957e11SThomas Gleixner	orl	%edx,%edx
511da957e11SThomas Gleixner	setne	%ch
512da957e11SThomas Gleixner	orb	%ch,%bl
513da957e11SThomas Gleixner	xorl	%edx,%edx
514da957e11SThomas Gleixner	shrd	%cl,%ebx,%edx
515da957e11SThomas Gleixner	shrd	%cl,%eax,%ebx
516da957e11SThomas Gleixner	shr	%cl,%eax
517da957e11SThomas Gleixner	orl	%edx,%edx		/* test these 32 bits */
518da957e11SThomas Gleixner	setne	%cl
519da957e11SThomas Gleixner	orb	%ch,%bl
520da957e11SThomas Gleixner	orb	%cl,%bl
521da957e11SThomas Gleixner	movl	%ebx,%edx
522da957e11SThomas Gleixner	movl	%eax,%ebx
523da957e11SThomas Gleixner	xorl	%eax,%eax
524da957e11SThomas Gleixner	popl	%ecx
525da957e11SThomas Gleixner	jmp	Denorm_done
526da957e11SThomas Gleixner
527da957e11SThomas Gleixner/* Shift by [64..) bits */
528da957e11SThomas GleixnerDenorm_shift_more_than_63:
529da957e11SThomas Gleixner	cmpw	$64,%cx
530da957e11SThomas Gleixner	jne	Denorm_shift_more_than_64
531da957e11SThomas Gleixner
532da957e11SThomas Gleixner/* Exactly 64 bit shift */
533da957e11SThomas Gleixner	addw	%cx,EXP(%edi)
534da957e11SThomas Gleixner	xorl	%ecx,%ecx
535da957e11SThomas Gleixner	orl	%edx,%edx
536da957e11SThomas Gleixner	setne	%cl
537da957e11SThomas Gleixner	orl	%ebx,%ebx
538da957e11SThomas Gleixner	setne	%ch
539da957e11SThomas Gleixner	orb	%ch,%cl
540da957e11SThomas Gleixner	orb	%cl,%al
541da957e11SThomas Gleixner	movl	%eax,%edx
542da957e11SThomas Gleixner	xorl	%eax,%eax
543da957e11SThomas Gleixner	xorl	%ebx,%ebx
544da957e11SThomas Gleixner	popl	%ecx
545da957e11SThomas Gleixner	jmp	Denorm_done
546da957e11SThomas Gleixner
547da957e11SThomas GleixnerDenorm_shift_more_than_64:
548da957e11SThomas Gleixner	movw	EXP_UNDER+1,EXP(%edi)
549da957e11SThomas Gleixner/* This is easy, %eax must be non-zero, so.. */
550da957e11SThomas Gleixner	movl	$1,%edx
551da957e11SThomas Gleixner	xorl	%eax,%eax
552da957e11SThomas Gleixner	xorl	%ebx,%ebx
553da957e11SThomas Gleixner	popl	%ecx
554da957e11SThomas Gleixner	jmp	Denorm_done
555da957e11SThomas Gleixner
556da957e11SThomas Gleixner
557da957e11SThomas GleixnerUnmasked_underflow:
558da957e11SThomas Gleixner	movb	UNMASKED_UNDERFLOW,FPU_denormal
559da957e11SThomas Gleixner	jmp	Denorm_done
560da957e11SThomas Gleixner
561da957e11SThomas Gleixner
562da957e11SThomas Gleixner/* Undo the de-normalisation. */
563da957e11SThomas GleixnerNormalise_result:
564da957e11SThomas Gleixner	cmpb	UNMASKED_UNDERFLOW,FPU_denormal
565da957e11SThomas Gleixner	je	Signal_underflow
566da957e11SThomas Gleixner
567da957e11SThomas Gleixner/* The number must be a denormal if we got here. */
568da957e11SThomas Gleixner#ifdef PARANOID
569da957e11SThomas Gleixner	/* But check it... just in case. */
570da957e11SThomas Gleixner	cmpw	EXP_UNDER+1,EXP(%edi)
571da957e11SThomas Gleixner	jne	L_norm_bugged
572da957e11SThomas Gleixner#endif /* PARANOID */
573da957e11SThomas Gleixner
574da957e11SThomas Gleixner#ifdef PECULIAR_486
575da957e11SThomas Gleixner	/*
576da957e11SThomas Gleixner	 * This implements a special feature of 80486 behaviour.
577da957e11SThomas Gleixner	 * Underflow will be signalled even if the number is
578da957e11SThomas Gleixner	 * not a denormal after rounding.
579da957e11SThomas Gleixner	 * This difference occurs only for masked underflow, and not
580da957e11SThomas Gleixner	 * in the unmasked case.
581da957e11SThomas Gleixner	 * Actual 80486 behaviour differs from this in some circumstances.
582da957e11SThomas Gleixner	 */
583da957e11SThomas Gleixner	orl	%eax,%eax		/* ms bits */
584da957e11SThomas Gleixner	js	LPseudoDenormal		/* Will be masked underflow */
585da957e11SThomas Gleixner#else
586da957e11SThomas Gleixner	orl	%eax,%eax		/* ms bits */
587da957e11SThomas Gleixner	js	L_Normalised		/* No longer a denormal */
588da957e11SThomas Gleixner#endif /* PECULIAR_486 */
589da957e11SThomas Gleixner
590da957e11SThomas Gleixner	jnz	LDenormal_adj_exponent
591da957e11SThomas Gleixner
592da957e11SThomas Gleixner	orl	%ebx,%ebx
593da957e11SThomas Gleixner	jz	L_underflow_to_zero	/* The contents are zero */
594da957e11SThomas Gleixner
595da957e11SThomas GleixnerLDenormal_adj_exponent:
596da957e11SThomas Gleixner	decw	EXP(%edi)
597da957e11SThomas Gleixner
598da957e11SThomas GleixnerLPseudoDenormal:
599da957e11SThomas Gleixner	testb	$0xff,FPU_bits_lost	/* bits lost == underflow */
600da957e11SThomas Gleixner	movl	TAG_Special,%edx
601da957e11SThomas Gleixner	jz	L_deNormalised
602da957e11SThomas Gleixner
603da957e11SThomas Gleixner	/* There must be a masked underflow */
604da957e11SThomas Gleixner	push	%eax
605da957e11SThomas Gleixner	pushl	EX_Underflow
606da957e11SThomas Gleixner	call	EXCEPTION
607da957e11SThomas Gleixner	popl	%eax
608da957e11SThomas Gleixner	popl	%eax
609da957e11SThomas Gleixner	movl	TAG_Special,%edx
610da957e11SThomas Gleixner	jmp	L_deNormalised
611da957e11SThomas Gleixner
612da957e11SThomas Gleixner
613da957e11SThomas Gleixner/*
614da957e11SThomas Gleixner * The operations resulted in a number too small to represent.
615da957e11SThomas Gleixner * Masked response.
616da957e11SThomas Gleixner */
617da957e11SThomas GleixnerL_underflow_to_zero:
618da957e11SThomas Gleixner	push	%eax
619da957e11SThomas Gleixner	call	set_precision_flag_down
620da957e11SThomas Gleixner	popl	%eax
621da957e11SThomas Gleixner
622da957e11SThomas Gleixner	push	%eax
623da957e11SThomas Gleixner	pushl	EX_Underflow
624da957e11SThomas Gleixner	call	EXCEPTION
625da957e11SThomas Gleixner	popl	%eax
626da957e11SThomas Gleixner	popl	%eax
627da957e11SThomas Gleixner
628da957e11SThomas Gleixner/* Reduce the exponent to EXP_UNDER */
629da957e11SThomas Gleixner	movw	EXP_UNDER,EXP(%edi)
630da957e11SThomas Gleixner	movl	TAG_Zero,%edx
631da957e11SThomas Gleixner	jmp	L_Store_significand
632da957e11SThomas Gleixner
633da957e11SThomas Gleixner
634da957e11SThomas Gleixner/* The operations resulted in a number too large to represent. */
635da957e11SThomas GleixnerL_overflow:
636da957e11SThomas Gleixner	addw	EXTENDED_Ebias,EXP(%edi)	/* Set for unmasked response. */
637da957e11SThomas Gleixner	push	%edi
638da957e11SThomas Gleixner	call	arith_overflow
639da957e11SThomas Gleixner	pop	%edi
640da957e11SThomas Gleixner	jmp	fpu_reg_round_signed_special_exit
641da957e11SThomas Gleixner
642da957e11SThomas Gleixner
643da957e11SThomas GleixnerSignal_underflow:
644da957e11SThomas Gleixner	/* The number may have been changed to a non-denormal */
645da957e11SThomas Gleixner	/* by the rounding operations. */
646da957e11SThomas Gleixner	cmpw	EXP_UNDER,EXP(%edi)
647da957e11SThomas Gleixner	jle	Do_unmasked_underflow
648da957e11SThomas Gleixner
649da957e11SThomas Gleixner	jmp	L_Normalised
650da957e11SThomas Gleixner
651da957e11SThomas GleixnerDo_unmasked_underflow:
652da957e11SThomas Gleixner	/* Increase the exponent by the magic number */
653da957e11SThomas Gleixner	addw	$(3*(1<<13)),EXP(%edi)
654da957e11SThomas Gleixner	push	%eax
655da957e11SThomas Gleixner	pushl	EX_Underflow
656da957e11SThomas Gleixner	call	EXCEPTION
657da957e11SThomas Gleixner	popl	%eax
658da957e11SThomas Gleixner	popl	%eax
659da957e11SThomas Gleixner	jmp	L_Normalised
660da957e11SThomas Gleixner
661da957e11SThomas Gleixner
662da957e11SThomas Gleixner#ifdef PARANOID
663da957e11SThomas Gleixner#ifdef PECULIAR_486
664da957e11SThomas GleixnerL_bugged_denorm_486:
665da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x236
666da957e11SThomas Gleixner	call	EXCEPTION
667da957e11SThomas Gleixner	popl	%ebx
668da957e11SThomas Gleixner	jmp	L_exception_exit
669da957e11SThomas Gleixner#else
670da957e11SThomas GleixnerL_bugged_denorm:
671da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x230
672da957e11SThomas Gleixner	call	EXCEPTION
673da957e11SThomas Gleixner	popl	%ebx
674da957e11SThomas Gleixner	jmp	L_exception_exit
675da957e11SThomas Gleixner#endif /* PECULIAR_486 */
676da957e11SThomas Gleixner
677da957e11SThomas GleixnerL_bugged_round24:
678da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x231
679da957e11SThomas Gleixner	call	EXCEPTION
680da957e11SThomas Gleixner	popl	%ebx
681da957e11SThomas Gleixner	jmp	L_exception_exit
682da957e11SThomas Gleixner
683da957e11SThomas GleixnerL_bugged_round53:
684da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x232
685da957e11SThomas Gleixner	call	EXCEPTION
686da957e11SThomas Gleixner	popl	%ebx
687da957e11SThomas Gleixner	jmp	L_exception_exit
688da957e11SThomas Gleixner
689da957e11SThomas GleixnerL_bugged_round64:
690da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x233
691da957e11SThomas Gleixner	call	EXCEPTION
692da957e11SThomas Gleixner	popl	%ebx
693da957e11SThomas Gleixner	jmp	L_exception_exit
694da957e11SThomas Gleixner
695da957e11SThomas GleixnerL_norm_bugged:
696da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x234
697da957e11SThomas Gleixner	call	EXCEPTION
698da957e11SThomas Gleixner	popl	%ebx
699da957e11SThomas Gleixner	jmp	L_exception_exit
700da957e11SThomas Gleixner
701da957e11SThomas GleixnerL_entry_bugged:
702da957e11SThomas Gleixner	pushl	EX_INTERNAL|0x235
703da957e11SThomas Gleixner	call	EXCEPTION
704da957e11SThomas Gleixner	popl	%ebx
705da957e11SThomas GleixnerL_exception_exit:
706da957e11SThomas Gleixner	mov	$-1,%eax
707da957e11SThomas Gleixner	jmp	fpu_reg_round_special_exit
708da957e11SThomas Gleixner#endif /* PARANOID */
709*bd6be579SJiri Slaby
710*bd6be579SJiri SlabyENDPROC(FPU_round)
711