5 * Rounding/truncation/etc for FPU basic arithmetic functions.
7 * This code has four possible entry points.
8 * The following must be entered by a jmp intruction:
9 * FPU_round, FPU_round_sqrt, and FPU_Arith_exit.
11 * The _round_reg entry point is intended to be used by C code.
13 * void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w)
16 * Copyright (C) 1992,1993,1994
17 * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
18 * Australia. E-mail billm@vaxc.cc.monash.edu.au
19 * All rights reserved.
21 * This copyright notice covers the redistribution and use of the
22 * FPU emulator developed by W. Metzenthen. It covers only its use
23 * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
24 * use is not permitted under this copyright.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must include information specifying
32 * that source code for the emulator is freely available and include
34 * a) an offer to provide the source code for a nominal distribution
36 * b) list at least two alternative methods whereby the source
37 * can be obtained, e.g. a publically accessible bulletin board
38 * and an anonymous ftp site from which the software can be
40 * 3. All advertising materials specifically mentioning features or use of
41 * this emulator must acknowledge that it was developed by W. Metzenthen.
42 * 4. The name of W. Metzenthen may not be used to endorse or promote
43 * products derived from this software without specific prior written
46 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
47 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
48 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
49 * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
50 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
52 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
54 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
55 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 * The purpose of this copyright, based upon the Berkeley copyright, is to
59 * ensure that the covered software remains freely available to everyone.
61 * The software (with necessary differences) is also available, but under
62 * the terms of the GNU copyleft, for the Linux operating system and for
63 * the djgpp ms-dos extender.
65 * W. Metzenthen June 1994.
68 * $FreeBSD: src/sys/gnu/i386/fpemul/reg_round.s,v 1.9.2.1 2000/07/07 00:38:42 obrien Exp $
73 /*---------------------------------------------------------------------------+
74 | Four entry points. |
76 | Needed by both the FPU_round and FPU_round_sqrt entry points: |
77 | %eax:%ebx 64 bit significand |
78 | %edx 32 bit extension of the significand |
79 | %edi pointer to an FPU_REG for the result to be stored |
80 | stack calling function must have set up a C stack frame and |
81 | pushed %esi, %edi, and %ebx |
83 | Needed just for the FPU_round_sqrt entry point: |
84 | %cx A control word in the same format as the FPU control word. |
85 | Otherwise, PARAM4 must give such a value. |
88 | The significand and its extension are assumed to be exact in the |
90 | If the significand by itself is the exact result then the significand |
91 | extension (%edx) must contain 0, otherwise the significand extension |
93 | If the significand extension is non-zero then the significand is |
94 | smaller than the magnitude of the correct exact result by an amount |
95 | greater than zero and less than one ls bit of the significand. |
96 | The significand extension is only required to have three possible |
98 | less than 0x80000000 <=> the significand is less than 1/2 an ls |
99 | bit smaller than the magnitude of the |
100 | true exact result. |
101 | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
102 | smaller than the magnitude of the true |
104 | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
105 | bit smaller than the magnitude of the |
106 | true exact result. |
108 +---------------------------------------------------------------------------*/
110 /*---------------------------------------------------------------------------+
111 | The code in this module has become quite complex, but it should handle |
112 | all of the FPU flags which are set at this stage of the basic arithmetic |
114 | There are a few rare cases where the results are not set identically to |
115 | a real FPU. These require a bit more thought because at this stage the |
116 | results of the code here appear to be more consistent... |
117 | This may be changed in a future version. |
118 +---------------------------------------------------------------------------*/
121 #include <gnu/i386/fpemul/exception.h>
122 #include <gnu/i386/fpemul/control_w.h>
127 #define UNMASKED_UNDERFLOW $2
138 .globl FPU_round_sqrt
139 .globl FPU_Arith_exit
141 /* Entry point when called from C */
156 FPU_round: /* Normal entry point */
159 FPU_round_sqrt: /* Entry point from wm_sqrt.S */
162 /* Cannot use this here yet */
164 /* jns L_entry_bugged */
167 cmpl EXP_UNDER,EXP(%edi)
168 jle xMake_denorm /* The number is a de-normal*/
170 movb $0,FPU_denormal /* 0 -> not a de-normal*/
173 movb $0,FPU_bits_lost /*No bits yet lost in rounding*/
187 jmp L_bugged /* There is no bug, just a bad control word */
191 /* Round etc to 24 bit precision */
199 je LCheck_truncate_24
201 cmpl RC_UP,%ecx /* Towards +infinity */
204 cmpl RC_DOWN,%ecx /* Towards -infinity */
212 cmpb SIGN_POS,SIGN(%edi)
213 jne LCheck_truncate_24 /* If negative then up==truncate */
215 jmp LCheck_24_round_up
218 cmpb SIGN_POS,SIGN(%edi)
219 je LCheck_truncate_24 /* If positive then down==truncate */
223 andl $0x000000ff,%ecx
230 /* Do rounding of the 24th bit if needed (nearest or even) */
232 andl $0x000000ff,%ecx
233 cmpl $0x00000080,%ecx
234 jc LCheck_truncate_24 /*less than half, no increment needed*/
236 jne LGreater_Half_24 /* greater than half, increment needed*/
238 /* Possibly half, we need to check the ls bits */
240 jnz LGreater_Half_24 /* greater than half, increment needed*/
243 jnz LGreater_Half_24 /* greater than half, increment needed*/
245 /* Exactly half, increment only if 24th bit is 1 (round to even)*/
246 testl $0x00000100,%eax
249 LGreater_Half_24: /*Rounding: increment at the 24th bit*/
251 andl $0xffffff00,%eax /*Truncate to 24 bits*/
253 movb LOST_UP,FPU_bits_lost
254 addl $0x00000100,%eax
255 jmp LCheck_Round_Overflow
259 andl $0x000000ff,%ecx
262 jz LRe_normalise /* No truncation needed*/
265 andl $0xffffff00,%eax /* Truncate to 24 bits*/
267 movb LOST_DOWN,FPU_bits_lost
271 /* Round etc to 53 bit precision */
279 je LCheck_truncate_53
281 cmpl RC_UP,%ecx /* Towards +infinity*/
284 cmpl RC_DOWN,%ecx /* Towards -infinity*/
292 cmpb SIGN_POS,SIGN(%edi)
293 jne LCheck_truncate_53 /* If negative then up==truncate*/
295 jmp LCheck_53_round_up
298 cmpb SIGN_POS,SIGN(%edi)
299 je LCheck_truncate_53 /* If positive then down==truncate*/
303 andl $0x000007ff,%ecx
309 /*Do rounding of the 53rd bit if needed (nearest or even)*/
311 andl $0x000007ff,%ecx
312 cmpl $0x00000400,%ecx
313 jc LCheck_truncate_53 /* less than half, no increment needed*/
315 jnz LGreater_Half_53 /* greater than half, increment needed*/
317 /*Possibly half, we need to check the ls bits*/
319 jnz LGreater_Half_53 /* greater than half, increment needed*/
321 /* Exactly half, increment only if 53rd bit is 1 (round to even)*/
322 testl $0x00000800,%ebx
325 LGreater_Half_53: /*Rounding: increment at the 53rd bit*/
327 movb LOST_UP,FPU_bits_lost
328 andl $0xfffff800,%ebx /* Truncate to 53 bits*/
329 addl $0x00000800,%ebx
331 jmp LCheck_Round_Overflow
335 andl $0x000007ff,%ecx
340 movb LOST_DOWN,FPU_bits_lost
341 andl $0xfffff800,%ebx /* Truncate to 53 bits*/
345 /* Round etc to 64 bit precision*/
353 je LCheck_truncate_64
355 cmpl RC_UP,%ecx /* Towards +infinity*/
358 cmpl RC_DOWN,%ecx /* Towards -infinity*/
366 cmpb SIGN_POS,SIGN(%edi)
367 jne LCheck_truncate_64 /* If negative then up==truncate*/
374 cmpb SIGN_POS,SIGN(%edi)
375 je LCheck_truncate_64 /*If positive then down==truncate*/
382 cmpl $0x80000000,%edx
383 jc LCheck_truncate_64
387 /* Now test for round-to-even */
389 jz LCheck_truncate_64
392 movb LOST_UP,FPU_bits_lost
396 LCheck_Round_Overflow:
397 jnc LRe_normalise /* Rounding done, no overflow */
399 /* Overflow, adjust the result (to 1.0) */
410 movb LOST_DOWN,FPU_bits_lost
413 testb $0xff,FPU_denormal
414 jnz xNormalise_result
417 cmpb LOST_UP,FPU_bits_lost
418 je xL_precision_lost_up
420 cmpb LOST_DOWN,FPU_bits_lost
421 je xL_precision_lost_down
423 xL_no_precision_loss:
424 cmpl EXP_OVER,EXP(%edi)
427 /* store the result */
428 movb TW_Valid,TAG(%edi)
430 xL_Store_significand:
442 /* Set the FPU status flags to represent precision loss due to*/
444 xL_precision_lost_up:
446 call _set_precision_flag_up
448 jmp xL_no_precision_loss
450 /* Set the FPU status flags to represent precision loss due to*/
452 xL_precision_lost_down:
454 call _set_precision_flag_down
456 jmp xL_no_precision_loss
459 /* The number is a denormal (which might get rounded up to a normal)
460 // Shift the number right the required number of bits, which will
461 // have to be undone later...*/
463 /* The action to be taken depends upon whether the underflow
464 // exception is masked*/
465 testb CW_Underflow,%cl /* Underflow mask.*/
466 jz xUnmasked_underflow /* Do not make a denormal.*/
468 movb DENORMAL,FPU_denormal
472 subl EXP_UNDER+1,%ecx
475 cmpl $64,%ecx /* shrd only works for 0..31 bits */
476 jnc xDenorm_shift_more_than_63
478 cmpl $32,%ecx /* shrd only works for 0..31 bits */
479 jnc xDenorm_shift_more_than_32
481 /* We got here without jumps by assuming that the most common requirement
482 // is for a small de-normalising shift.
483 // Shift by [1..31] bits */
485 orl %edx,%edx /* extension*/
495 /* Shift by [32..63] bits*/
496 xDenorm_shift_more_than_32:
506 orl %edx,%edx /*test these 32 bits*/
516 /* Shift by [64..) bits*/
517 xDenorm_shift_more_than_63:
519 jne xDenorm_shift_more_than_64
521 /* Exactly 64 bit shift*/
536 xDenorm_shift_more_than_64:
537 movl EXP_UNDER+1,EXP(%edi)
538 /* This is easy, %eax must be non-zero, so..*/
547 /* Increase the exponent by the magic number*/
548 addl $(3*(1<<13)),EXP(%edi)
549 movb UNMASKED_UNDERFLOW,FPU_denormal
553 /* Undo the de-normalisation.*/
555 cmpb UNMASKED_UNDERFLOW,FPU_denormal
558 /* The number must be a denormal if we got here.*/
560 /* But check it... just in case.*/
561 cmpl EXP_UNDER+1,EXP(%edi)
565 orl %eax,%eax /* ms bits*/
566 jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits*/
569 jz L_underflow_to_zero /* The contents are zero*/
571 /* Shift left 32 - 63 bits*/
576 LNormalise_shift_up_to_31:
577 bsrl %eax,%ecx /* get the required shift in %ecx */
584 LNormalise_shift_done:
585 testb $0xff,FPU_bits_lost /* bits lost == underflow*/
588 /* There must be a masked underflow*/
597 /* The operations resulted in a number too small to represent.
598 // Masked response.*/
601 call _set_precision_flag_down
610 movb TW_Zero,TAG(%edi)
611 jmp xL_Store_significand
614 /* The operations resulted in a number too large to represent.*/
632 /* If we ever get here then we have problems! */
634 pushl EX_INTERNAL|0x201
640 pushl EX_INTERNAL|0x216
646 pushl EX_INTERNAL|0x217