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 $
69 * $DragonFly: src/sys/platform/pc32/gnu/fpemul/Attic/reg_round.s,v 1.4 2003/08/07 21:17:20 dillon Exp $
74 /*---------------------------------------------------------------------------+
75 | Four entry points. |
77 | Needed by both the FPU_round and FPU_round_sqrt entry points: |
78 | %eax:%ebx 64 bit significand |
79 | %edx 32 bit extension of the significand |
80 | %edi pointer to an FPU_REG for the result to be stored |
81 | stack calling function must have set up a C stack frame and |
82 | pushed %esi, %edi, and %ebx |
84 | Needed just for the FPU_round_sqrt entry point: |
85 | %cx A control word in the same format as the FPU control word. |
86 | Otherwise, PARAM4 must give such a value. |
89 | The significand and its extension are assumed to be exact in the |
91 | If the significand by itself is the exact result then the significand |
92 | extension (%edx) must contain 0, otherwise the significand extension |
94 | If the significand extension is non-zero then the significand is |
95 | smaller than the magnitude of the correct exact result by an amount |
96 | greater than zero and less than one ls bit of the significand. |
97 | The significand extension is only required to have three possible |
99 | less than 0x80000000 <=> the significand is less than 1/2 an ls |
100 | bit smaller than the magnitude of the |
101 | true exact result. |
102 | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
103 | smaller than the magnitude of the true |
105 | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
106 | bit smaller than the magnitude of the |
107 | true exact result. |
109 +---------------------------------------------------------------------------*/
111 /*---------------------------------------------------------------------------+
112 | The code in this module has become quite complex, but it should handle |
113 | all of the FPU flags which are set at this stage of the basic arithmetic |
115 | There are a few rare cases where the results are not set identically to |
116 | a real FPU. These require a bit more thought because at this stage the |
117 | results of the code here appear to be more consistent... |
118 | This may be changed in a future version. |
119 +---------------------------------------------------------------------------*/
122 #include "exception.h"
123 #include "control_w.h"
128 #define UNMASKED_UNDERFLOW $2
139 .globl FPU_round_sqrt
140 .globl FPU_Arith_exit
142 /* Entry point when called from C */
157 FPU_round: /* Normal entry point */
160 FPU_round_sqrt: /* Entry point from wm_sqrt.S */
163 /* Cannot use this here yet */
165 /* jns L_entry_bugged */
168 cmpl EXP_UNDER,EXP(%edi)
169 jle xMake_denorm /* The number is a de-normal*/
171 movb $0,FPU_denormal /* 0 -> not a de-normal*/
174 movb $0,FPU_bits_lost /*No bits yet lost in rounding*/
188 jmp L_bugged /* There is no bug, just a bad control word */
192 /* Round etc to 24 bit precision */
200 je LCheck_truncate_24
202 cmpl RC_UP,%ecx /* Towards +infinity */
205 cmpl RC_DOWN,%ecx /* Towards -infinity */
213 cmpb SIGN_POS,SIGN(%edi)
214 jne LCheck_truncate_24 /* If negative then up==truncate */
216 jmp LCheck_24_round_up
219 cmpb SIGN_POS,SIGN(%edi)
220 je LCheck_truncate_24 /* If positive then down==truncate */
224 andl $0x000000ff,%ecx
231 /* Do rounding of the 24th bit if needed (nearest or even) */
233 andl $0x000000ff,%ecx
234 cmpl $0x00000080,%ecx
235 jc LCheck_truncate_24 /*less than half, no increment needed*/
237 jne LGreater_Half_24 /* greater than half, increment needed*/
239 /* Possibly half, we need to check the ls bits */
241 jnz LGreater_Half_24 /* greater than half, increment needed*/
244 jnz LGreater_Half_24 /* greater than half, increment needed*/
246 /* Exactly half, increment only if 24th bit is 1 (round to even)*/
247 testl $0x00000100,%eax
250 LGreater_Half_24: /*Rounding: increment at the 24th bit*/
252 andl $0xffffff00,%eax /*Truncate to 24 bits*/
254 movb LOST_UP,FPU_bits_lost
255 addl $0x00000100,%eax
256 jmp LCheck_Round_Overflow
260 andl $0x000000ff,%ecx
263 jz LRe_normalise /* No truncation needed*/
266 andl $0xffffff00,%eax /* Truncate to 24 bits*/
268 movb LOST_DOWN,FPU_bits_lost
272 /* Round etc to 53 bit precision */
280 je LCheck_truncate_53
282 cmpl RC_UP,%ecx /* Towards +infinity*/
285 cmpl RC_DOWN,%ecx /* Towards -infinity*/
293 cmpb SIGN_POS,SIGN(%edi)
294 jne LCheck_truncate_53 /* If negative then up==truncate*/
296 jmp LCheck_53_round_up
299 cmpb SIGN_POS,SIGN(%edi)
300 je LCheck_truncate_53 /* If positive then down==truncate*/
304 andl $0x000007ff,%ecx
310 /*Do rounding of the 53rd bit if needed (nearest or even)*/
312 andl $0x000007ff,%ecx
313 cmpl $0x00000400,%ecx
314 jc LCheck_truncate_53 /* less than half, no increment needed*/
316 jnz LGreater_Half_53 /* greater than half, increment needed*/
318 /*Possibly half, we need to check the ls bits*/
320 jnz LGreater_Half_53 /* greater than half, increment needed*/
322 /* Exactly half, increment only if 53rd bit is 1 (round to even)*/
323 testl $0x00000800,%ebx
326 LGreater_Half_53: /*Rounding: increment at the 53rd bit*/
328 movb LOST_UP,FPU_bits_lost
329 andl $0xfffff800,%ebx /* Truncate to 53 bits*/
330 addl $0x00000800,%ebx
332 jmp LCheck_Round_Overflow
336 andl $0x000007ff,%ecx
341 movb LOST_DOWN,FPU_bits_lost
342 andl $0xfffff800,%ebx /* Truncate to 53 bits*/
346 /* Round etc to 64 bit precision*/
354 je LCheck_truncate_64
356 cmpl RC_UP,%ecx /* Towards +infinity*/
359 cmpl RC_DOWN,%ecx /* Towards -infinity*/
367 cmpb SIGN_POS,SIGN(%edi)
368 jne LCheck_truncate_64 /* If negative then up==truncate*/
375 cmpb SIGN_POS,SIGN(%edi)
376 je LCheck_truncate_64 /*If positive then down==truncate*/
383 cmpl $0x80000000,%edx
384 jc LCheck_truncate_64
388 /* Now test for round-to-even */
390 jz LCheck_truncate_64
393 movb LOST_UP,FPU_bits_lost
397 LCheck_Round_Overflow:
398 jnc LRe_normalise /* Rounding done, no overflow */
400 /* Overflow, adjust the result (to 1.0) */
411 movb LOST_DOWN,FPU_bits_lost
414 testb $0xff,FPU_denormal
415 jnz xNormalise_result
418 cmpb LOST_UP,FPU_bits_lost
419 je xL_precision_lost_up
421 cmpb LOST_DOWN,FPU_bits_lost
422 je xL_precision_lost_down
424 xL_no_precision_loss:
425 cmpl EXP_OVER,EXP(%edi)
428 /* store the result */
429 movb TW_Valid,TAG(%edi)
431 xL_Store_significand:
443 /* Set the FPU status flags to represent precision loss due to*/
445 xL_precision_lost_up:
447 call set_precision_flag_up
449 jmp xL_no_precision_loss
451 /* Set the FPU status flags to represent precision loss due to*/
453 xL_precision_lost_down:
455 call set_precision_flag_down
457 jmp xL_no_precision_loss
460 /* The number is a denormal (which might get rounded up to a normal)
461 // Shift the number right the required number of bits, which will
462 // have to be undone later...*/
464 /* The action to be taken depends upon whether the underflow
465 // exception is masked*/
466 testb CW_Underflow,%cl /* Underflow mask.*/
467 jz xUnmasked_underflow /* Do not make a denormal.*/
469 movb DENORMAL,FPU_denormal
473 subl EXP_UNDER+1,%ecx
476 cmpl $64,%ecx /* shrd only works for 0..31 bits */
477 jnc xDenorm_shift_more_than_63
479 cmpl $32,%ecx /* shrd only works for 0..31 bits */
480 jnc xDenorm_shift_more_than_32
482 /* We got here without jumps by assuming that the most common requirement
483 // is for a small de-normalising shift.
484 // Shift by [1..31] bits */
486 orl %edx,%edx /* extension*/
496 /* Shift by [32..63] bits*/
497 xDenorm_shift_more_than_32:
507 orl %edx,%edx /*test these 32 bits*/
517 /* Shift by [64..) bits*/
518 xDenorm_shift_more_than_63:
520 jne xDenorm_shift_more_than_64
522 /* Exactly 64 bit shift*/
537 xDenorm_shift_more_than_64:
538 movl EXP_UNDER+1,EXP(%edi)
539 /* This is easy, %eax must be non-zero, so..*/
548 /* Increase the exponent by the magic number*/
549 addl $(3*(1<<13)),EXP(%edi)
550 movb UNMASKED_UNDERFLOW,FPU_denormal
554 /* Undo the de-normalisation.*/
556 cmpb UNMASKED_UNDERFLOW,FPU_denormal
559 /* The number must be a denormal if we got here.*/
561 /* But check it... just in case.*/
562 cmpl EXP_UNDER+1,EXP(%edi)
566 orl %eax,%eax /* ms bits*/
567 jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits*/
570 jz L_underflow_to_zero /* The contents are zero*/
572 /* Shift left 32 - 63 bits*/
577 LNormalise_shift_up_to_31:
578 bsrl %eax,%ecx /* get the required shift in %ecx */
585 LNormalise_shift_done:
586 testb $0xff,FPU_bits_lost /* bits lost == underflow*/
589 /* There must be a masked underflow*/
598 /* The operations resulted in a number too small to represent.
599 // Masked response.*/
602 call set_precision_flag_down
611 movb TW_Zero,TAG(%edi)
612 jmp xL_Store_significand
615 /* The operations resulted in a number too large to represent.*/
633 /* If we ever get here then we have problems! */
635 pushl EX_INTERNAL|0x201
641 pushl EX_INTERNAL|0x216
647 pushl EX_INTERNAL|0x217