subttl  emround.asm - Rounding and Precision Control and FRNDINT
        page
;*******************************************************************************
;emround.asm - Rounding and Precision Control
;
;        Microsoft Confidential
;
;	 Copyright (c) Microsoft Corporation 1991
;        All Rights Reserved
;
;Purpose:
;       Rounding and precision control.  The correct routine is jumped
;	to through the [RoundMode] vector.
;
;Revision History:
;
; []	09/05/91  TP	Initial 32-bit version.
;	02/28/92  JWM   Minor bug fix in NotNearLow
;
;*******************************************************************************


RndIntSpcl:
	cmp	cl,bTAG_INF
	jz	RndIntX			;Leave infinity unchanged
	cmp	cl,bTAG_DEN
	jnz	SpclDestNotDen		;Handle NAN & empty - in emarith.asm
;Handle denormal
	mov	EMSEG:[CURerr],Denormal
	test	EMSEG:[CWmask],Denormal	;Is it masked?
	jnz	NormRndInt		;If so, ignore denormalization
RndIntX:
	ret

;********
EM_ENTRY eFRNDINT
eFRNDINT:
;********
;edi points to top of stack
	mov	ecx,EMSEG:[edi].ExpSgn
	cmp	cl,bTAG_ZERO
.erre	bTAG_VALID lt bTAG_ZERO
.erre	bTAG_SNGL lt bTAG_ZERO
	jz	RndIntX	
	ja	RndIntSpcl
	cmp	ecx,63 shl 16		;Is it already integer?
	jge	RndIntX
NormRndInt:
	mov	ebx,EMSEG:[edi].lManHi
	mov	esi,EMSEG:[edi].lManLo
	mov	EMSEG:[Result],edi	;Save result pointer
	xor	eax,eax			;Extend mantissa
	push	offset SaveResult
	jmp	RoundToBit

;*******************************************************************************

ResultOverflow:
;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl.
;We were all ready to save the rounded result, but the exponent turned out
;to be too large.
	or	EMSEG:[CURerr],Overflow
	sub	ecx,UnderBias shl 16	;Unmasked response
	test	EMSEG:[CWmask],Overflow	;Is exception unmasked?
	jz	SaveResult		;If so, we're ready
;Produce masked overflow response
	mov	ebx,1 shl 31		;Assume infinity
	xor	esi,esi
	mov	cl,bTAG_INF
	mov	al,EMSEG:[CWcntl]	;Get rounding control
	mov	ah,al
	and	ah,RCchop			;Rounding control only
;Return max value if RCup bit = 1 and -, or RCdown bit = 1 and +
;i.e., RCup & sign OR RCdown & not sign
.erre	RCchop eq RCup + RCdown		;Always return max value
.erre	RCnear eq 0			;Never return max value
	sar	ch,7			;Expand sign through whole byte
.erre	(RCdown and bSign) eq 0		;Don't want to change real sign
	xor	ch,RCdown		;Flip sign for RCdown bit
	and	ah,ch			;RCup & sign  OR  RCdown & not sign
	jnz	SaveMax
	and	ecx,0FFFFH
	or	ecx,TexpMax shl 16
	jmp	SaveResult		;Save Infinity
SaveMax:
;Get max value for current precision
	mov	ebx,0FFFFFF00H		;Max value for 24 bits
	and	ecx,bSign shl 8		;Preserve only sign
	or	ecx,(IexpMax-IexpBias-1) shl 16 + bTAG_VALID ;Set up max value
	and	al,PrecisionControl
.erre	PC24 eq 0
	jz	SaveResult		;Save 24-bit max value
	dec	esi			;esi == -1
	mov	ebx,esi
	cmp	al,PC53
	jnz	SaveResult		;Save 64-bit max value
	mov	esi,0FFFFF800H
	jmp	SaveResult		;Save 53-bit max value

;*******************************************************************************
;
;64-bit rounding routines
;

;***********
Round64down:
;***********
	cmp	ecx,(IexpMin-IexpBias+1) shl 16	;Test for Underflow
	jl	RndDenorm64
	or	eax,eax			;Exact result?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision 	;Set flag on inexact result
;Chop if positive, increase mantissa if negative
	test	ch,bSign
	jz	SaveValidResult		;Positive, so chop
	jmp	RoundUp64		;Round up if negative

RndDenorm64:
	test	EMSEG:[CWmask],Underflow ;Is exception unmasked?
	jz	RndSetUnder
Denormalize:
;We don't really store in denormalized format, but we need the number 
;to be rounded as if we do.  If the exponent were -IexpBias, we would
;lose 1 bit of precision; as it gets more negative, we lose more bits.
;We'll do this by adjusting the exponent so that the bits we want to 
;keep look like integer bits, and performing round-to-integer.
	add	ecx,(IexpBias+62) shl 16 ;Adjust exponent so we're integer
	call	RoundToBit
;Set underflow exception if precision exception is set
	mov	al,EMSEG:[CURerr]
	and	al,Precision
	ror	al,Precision-Underflow	;Move Precision bit to Underflow pos.
	or	EMSEG:[CURerr],al	;Signal Underflow if inexact
	cmp	cl,bTAG_ZERO
	jz	SaveResult
	sub	ecx,(IexpBias+62) shl 16;Restore unbiased exponent
	cmp	ecx,TexpMin shl 16	;Did we round out of denorm?
	jae	SaveResult
	mov	cl,bTAG_DEN
	jmp	SaveResult

RndSetUnder:
;Underflow exception not masked.  Adjust exponent and try again.
	or	EMSEG:[CURerr],Underflow
	add	ecx,UnderBias shl 16
	jmp	EMSEG:[RoundMode]	;Try again with revised exponent

;***********
Round64near:
;***********
;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm64
	or	eax,eax			;Exact result?
	jz	short SaveValidResult
	or	EMSEG:[CURerr],Precision ;Set flag on inexact result

;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit.  Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set.  If the LSB is zero, then the sticky bits remain zero and we always
;round down.  This rounding rule is implemented by adding RoundBit-1
;(7F..FFH), setting CY if round up.  

	bt	esi,0			;Is mantissa even or odd? (set CY)
	adc	eax,(1 shl 31)-1	;Sum LSB & sticky bits--CY if round up
	jnc	SaveValidResult
RoundUp64:
	mov	EMSEG:[SWcc],RoundUp
	add	esi,1
	adc	ebx,0
	jc	BumpExponent		;Overflowed, increment exponent

SaveValidResult:			;A jump to here requires 9 clocks
	or	esi,esi			;Any bits in low half?
.erre	bTAG_VALID eq 1
.erre	bTAG_SNGL eq 0
	setnz   cl                      ;if low half==0 then cl=0 else cl=1
	cmp	ecx,TexpMax shl 16	;Test for overflow
	jge	ResultOverflow

SaveResult:				;A jump to here requires 10 clocks
;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
	mov	edi,EMSEG:[Result]
SaveResultEdi:
	mov	EMSEG:[edi].lManLo,esi
	mov	EMSEG:[edi].lManHi,ebx
SaveExpSgn:
	mov	EMSEG:[edi].ExpSgn,ecx
	ret

;***********
Round64up:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm64
	or	eax,eax			;Exact result?
	jz	short SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if negative, increase mantissa if positive
	cmp	ch,bSign		;No CY iff sign bit is set
	jc	RoundUp64		;Round up if positive
	jmp	short SaveValidResult

;***********
Round64chop:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm64
	or	eax,eax			;Exact result?
	jz	short SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
	jmp	short SaveValidResult

;*******************************************************************************
;
;53-bit rounding routines
;

;***********
Round53down:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm53
	mov	edx,esi			;Get low bits
	and	edx,(1 shl 11) - 1	;Mask to last 11 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if positive, increase mantissa if negative
	and	esi,not ((1 shl 11)-1)	;Mask off low 11 bits
	test	ch,bSign
	jz	SaveValidResult		;Positive, go chop
	jmp	RoundUp53

RndDenorm53:
	test	EMSEG:[CWmask],Underflow;Is exception unmasked?
	jz	RndSetUnder
;We don't really store in denormalized format, but we need the number 
;to be rounded as if we do.  If the exponent were -IexpBias, we would
;lose 1 bit of precision; as it gets more negative, we lose more bits.
;We'll do this by adjusting the exponent so that the bits we want to 
;keep look like integer bits, and performing round-to-integer.
	add	ecx,(IexpBias+51) shl 16 ;Adjust exponent so we're integer
	call	RoundToBit
;Set underflow exception if precision exception is set
	mov	al,EMSEG:[CURerr]
	and	al,Precision
	ror	al,Precision-Underflow	;Move Precision bit to Underflow pos.
	or	EMSEG:[CURerr],al	;Signal Underflow if inexact
	cmp	cl,bTAG_ZERO
	jz	SaveResult
	sub	ecx,(IexpBias+51) shl 16;Restore unbiased exponent
	cmp	ecx,(IexpMin-IexpBias+1) shl 16	;Did we round out of denorm?
	jae	SaveResult
	mov	cl,bTAG_DEN
	jmp	SaveResult

;***********
Round53near:
;***********
;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm53
	mov	edx,esi			;Get low bits
	and	edx,(1 shl 11) - 1	;Mask to last 11 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result

;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit.  Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set.  If the LSB is zero, then the sticky bits remain zero and we always
;round down.

	mov	edx,esi
	and	esi,not ((1 shl 11)-1)	;Mask off low 11 bits
	test	edx,1 shl 10		;Is round bit set?
	jz	SaveValidResult
	and	edx,(3 shl 10)-1	;Keep only sticky bits and LSB
	or	eax,edx			;Combine with other sticky bits
	jz	SaveValidResult
RoundUp53:
	mov	EMSEG:[SWcc],RoundUp
	add	esi,1 shl 11		;Round
	adc	ebx,0
	jnc	SaveValidResult
BumpExponent:
	add	ecx,1 shl 16		;Mantissa overflowed, bump exponent
	or	ebx,1 shl 31		;Set MSB
	jmp	SaveValidResult

;***********
Round53up:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm53
	mov	edx,esi			;Get low bits
	and	edx,(1 shl 11) - 1	;Mask to last 11 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if negative, increase mantissa if positive
	and	esi,not ((1 shl 11)-1)	;Mask off low 11 bits
	test	ch,bSign
	jz	RoundUp53		;Round up if positive
	jmp	SaveValidResult

;***********
Round53chop:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm53
	mov	edx,esi			;Get low bits
	and	edx,(1 shl 11) - 1	;Mask to last 11 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
	and	esi,not ((1 shl 11)-1)	;Mask off low 11 bits
	jmp	SaveValidResult

;*******************************************************************************
;
;24-bit rounding routines
;

;***********
Round24down:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm24
	or	eax,esi			;Low dword is just sticky bits
	mov	edx,ebx			;Get low bits
	and	edx,(1 shl 8) - 1	;Mask to last 8 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if positive, increase mantissa if negative
	xor	esi,esi
	and	ebx,not ((1 shl 8)-1)	;Mask off low 8 bits
	test	ch,bSign
	jz	SaveValidResult		;Chop if positive
	jmp	RoundUp24

RndDenorm24:
	test	EMSEG:[CWmask],Underflow;Is exception unmasked?
	jz	RndSetUnder
;We don't really store in denormalized format, but we need the number 
;to be rounded as if we do.  If the exponent were -IexpBias, we would
;lose 1 bit of precision; as it gets more negative, we lose more bits.
;We'll do this by adjusting the exponent so that the bits we want to 
;keep look like integer bits, and performing round-to-integer.
	add	ecx,(IexpBias+22) shl 16 ;Adjust exponent so we're integer
	call	RoundToBit
;Set underflow exception if precision exception is set
	mov	al,EMSEG:[CURerr]
	and	al,Precision
	ror	al,Precision-Underflow	;Move Precision bit to Underflow pos.
	or	EMSEG:[CURerr],al	;Signal Underflow if inexact
	cmp	cl,bTAG_ZERO
	jz	SaveResult
	sub	ecx,(IexpBias+22) shl 16;Restore unbiased exponent
	cmp	ecx,(IexpMin-IexpBias+1) shl 16	;Did we round out of denorm?
	jae	SaveResult
	mov	cl,bTAG_DEN
	jmp	SaveResult

;***********
Round24near:
;***********
;mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm24
	or	eax,esi			;Low dword is just sticky bits
	mov	edx,ebx			;Get low bits
	and	edx,(1 shl 8) - 1	;Mask to last 8 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
	xor	esi,esi

;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit.  Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set.  If the LSB is zero, then the sticky bits remain zero and we always
;round down.  

	mov	edx,ebx
	and	ebx,not ((1 shl 8)-1)	;Mask off low 8 bits
	test	dl,1 shl 7		;Round bit set?
	jz	SaveValidResult
	and	edx,(3 shl 7)-1		;Mask to LSB and sticky bits
	or	eax,edx			;Combine all sticky bits
	jz	SaveValidResult
RoundUp24:
	mov	EMSEG:[SWcc],RoundUp
	add	ebx,1 shl 8
	jnc	SaveValidResult
	jmp	BumpExponent		;Overflowed, increment exponent

;***********
Round24up:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm24
	or	eax,esi			;Low dword is just sticky bits
	mov	edx,ebx			;Get low bits
	and	edx,(1 shl 8) - 1	;Mask to last 8 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
;Chop if negative, increase mantissa if positive
	xor	esi,esi
	and	ebx,not ((1 shl 8)-1)	;Mask off low 8 bits
	test	ch,bSign
	jz	RoundUp24		;Round up if positive
	jmp	SaveValidResult

;***********
Round24chop:
;***********
	cmp	ecx,TexpMin shl 16	;Test for Underflow
	jl	RndDenorm24
	or	eax,esi			;Low dword is just sticky bits
	mov	edx,ebx			;Get low bits
	and	edx,(1 shl 8) - 1	;Mask to last 8 bits
	or	edx,eax			;Throwing away any bits?
	jz	SaveValidResult
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
	xor	esi,esi
	and	ebx,not ((1 shl 8)-1)	;Mask off low 8 bits
	jmp	SaveValidResult

;*******************************************************************************

;*** RoundToInteger
;
;This routine is used by FISTP Int64 and BSTP.  Unlike RoundToBit, this
;unnormalizes the number into a 64-bit integer.
;
;Inputs:
;	edi = pointer to number to round in stack
;Outputs:
;	CY set if invalid operation
;	ebx:edi = rounded integer if CY clear
;	ch = sign if CY clear
;Note:
;	FIST/FISTP/BSTP exception rules are used:  If the number is too big,
;	Invalid Operation occurs.  Denormals are ignored.
;
;esi preserved

RoundSpcl64Int:
	cmp	cl,bTAG_DEN
	jz	NormRound64Int		;Ignore denormal
	cmp	cl,bTAG_EMPTY
	jnz	RoundInvalid		;All other specials are invalid
	mov	EMSEG:[CURerr],StackFlag+Invalid
	stc				;Flag exception to caller
	ret

RoundInvalid:
;Overflow on integer store is invalid according to IEEE
	mov	EMSEG:[CURerr],Invalid
	stc				;Flag exception to caller
	ret

RoundToInteger:
	mov	ebx,EMSEG:[edi].lManHi
	mov	ecx,EMSEG:[edi].ExpSgn
	mov	edi,EMSEG:[edi].lManLo
;mantissa in ebx:edi, exponent in high ecx, sign in ch bit 7, tag in cl
	mov	al,ch			;Save sign bit
	cmp	cl,bTAG_ZERO
.erre	bTAG_VALID lt bTAG_ZERO
.erre	bTAG_SNGL lt bTAG_ZERO
	jz	RoundIntX		;Just return zero
	ja	RoundSpcl64Int
NormRound64Int:
	xor	edx,edx
	sar	ecx,16			;Bring exponent down
	cmp	ecx,-1			;Is it less than 1?
	jle	Under64Int
	cmp	ecx,63
	jg	RoundInvalid
	sub	ecx,63
	neg	ecx			;cl = amount to shift right
	mov	ch,al			;Get sign out of al
	xor	eax,eax
	cmp	cl,32			;Too big for one shift?
	jl	ShortShft64
;32-bit shift right
	xchg	edx,edi
	xchg	ebx,edi			;ebx=0 now
	shrd	eax,edx,cl
;Max total shift is 63 bits, so we know that the LSB of eax is still zero.
;We can rotate this zero to the MSB so the sticky bits in eax can be combined
;with those in edx without affecting the rounding bit in the MSB of edx.
	ror	eax,1			;MSB is now zero
ShortShft64:
;Shift count in cl is modulo-32
	shrd	edx,edi,cl
	shrd	edi,ebx,cl
	shr	ebx,cl
	or	edx,eax			;Collapse sticky bits into one dword
	jz	RoundIntX		;No sticky or round bits, so don't round
;Result will not be exact--check rounding mode
Round64Int:
	mov	EMSEG:[CURerr],Precision;Set flag on inexact result
	test	EMSEG:[CWcntl],RoundControl	;Check rounding control bits
.erre	RCnear eq 0
	jnz	NotNearest64Int		;Not just round-to-nearest

;To perform "round even" when the round bit is set and the sticky bits
;are zero, we treat the LSB as if it were a sticky bit.  Thus if the LSB
;is set, that will always force a round up (to even) if the round bit is
;set.  If the LSB is zero, then the sticky bits remain zero and we always
;round down.

	bt	edi,0			;Look at LSB (for round even)
	adc	edx,(1 shl 31)-1	;CY set if round up
	jnc	RoundIntX
	mov	EMSEG:[SWcc],RoundUp
	add	edi,1			;Round
	adc	ebx,0
	jc	RoundInvalid
RoundIntX:
	ret				;CY clear, no Invalid exception

Shift64Round:
	or	edi,edi
	setnz	dl			;Set sticky bit in edx
	xor	edi,edi			;Mantissa is all zero
	jmp	Round64Int

Under64Int:
;ZF set if exponent is -1
	xchg	ebx,edx			;64-bit right shift
	mov	ch,al			;Restore sign to ch
	jz	Shift64Round		;Exp. is -1, could need to round up
	xor	edi,edi			;Mantissa is all zero
	mov	EMSEG:[CURerr],Precision;Set flag on inexact result
NotNearest64Int:
;We want to increase the magnitude if RCup and +, or RCdown and -
	mov	al,EMSEG:[CWcntl]	;Get rounding control
.erre	(not RCup and RoundControl) eq RCdown
	sar	ch,7			;Expand sign through whole byte
	xor	al,ch			;Flip round mode if -
	and	al,RoundControl
	cmp	al,RCup			;Rounding up?
	jnz	RoundIntOk		;No, chop it
	mov	EMSEG:[SWcc],RoundUp
	add	edi,1
	adc	ebx,0
	jc	RoundInvalid
RoundIntOk:
	clc
	ret

;*******************************************************************************

;*** RoundToBit
;
;This is a relatively low performance routine used by FRNDINT and to
;generate internal-format denormals.  It can round to any bit position.
;
;Inputs:
;	mantissa in ebx:esi:eax, exponent in high ecx, sign in ch bit 7
;Purpose:
;	Round number to integer.  Zero exponent means number is in the
;	range [1,2), so only the MSB will survive (MSB-1 is round bit).  
;	Larger exponents keep more bits; 63 would mean no rounding.
;Outputs:
;	mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
;
;Does NOT detect overflow.

NoSigBits:
;Exponent was negative: no integer part
	and	ecx,bSign shl 8		;Zero exponent, preserve sign
	mov	cl,bTAG_ZERO
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
	test	EMSEG:[CWcntl],RoundControl	;Check rounding control bits
.erre	RCnear eq 0
	jnz	NotNearNoSig		;Not just round-to-nearest
	cmp	edx,-1			;Exponent of -1 ==> range [.5,1)
	je	HalfBitRound
RndIntToZero:
	xor	ebx,ebx
	mov	esi,ebx			;Just return zero
	ret

NotNearNoSig:
;We want to increase the magnitude if RCup and +, or RCdown and -
	mov	al,EMSEG:[CWcntl]	;Get rounding control
	sar	ch,7			;Expand sign through whole byte
	xor	al,ch			;Flip rounding bits if negative
	and	al,RoundControl
	cmp	al,RCup			;Rounding up?
	jnz	RndIntToZero		;No, chop it
RndIntToOne:
	mov	ebx,1 shl 31
	xor	esi,esi
	mov	cl,bTAG_SNGL
	mov	EMSEG:[SWcc],RoundUp
	ret

HalfBitRound:
	add	ebx,ebx			;Shift off MSB (round bit)
	or	ebx,esi
	or	ebx,eax
	jnz	RndIntToOne
	ret				;Return zero

;**********
RoundToBit:
;**********
	mov	edx,ecx			;Make copy of exponent
	sar	edx,16			;Bring rounding exponent down
	jl	NoSigBits
	mov	cl,dl
	cmp	cl,32			;Rounding in low word?
	jae	RoundLow
;When cl = 31, the RoundBit is in the low half while the LSB is in the 
;high half.  We must preserve the RoundBit when we move it to eax.
	xchg    eax,esi                 ;Low half becomes sticky bits
	or      ah,al                   ;Preserve lowest bits in ah
	add     esi,-1                  ;Set CY if any original sticky bits
	sbb     al,al                   ;Put original sticky bits in al
	mov	esi,ebx
	xor	ebx,ebx			;Shift mantissa right 32 bits
RoundLow:
	mov	edx,(1 shl 31) - 1
	shr	edx,cl			;Make mask
;Note in the case of cl = 31, edx is now zero.
	mov	edi,esi
	and	edi,edx
	or	edi,eax			;Any bits being lost?
	jz	RndSetTag		;All done
	inc	edx			;Mask for LSB
	or	EMSEG:[CURerr],Precision;Set flag on inexact result
	test	EMSEG:[CWcntl],RoundControl	;Check rounding control bits
.erre	RCnear eq 0
	jnz	NotNearLow		;Not just round-to-nearest
	mov	edi,edx			;Save LSB mask
	shr	edi,1			;Mask for round bit
	jc	SplitRound		;Round bit in eax?
	test	esi,edi			;Round bit set?
	jz	MaskOffLow
	dec	edi			;Mask for sticky bits
	or	edi,edx			;Sticky bits + LSB
	and	edi,esi
	or	edi,eax			;Any sticky bits set?
	jz	MaskOffLow
RoundUpThenMask:
	mov	EMSEG:[SWcc],RoundUp
	add	esi,edx			;Round up
	adc	ebx,0
	jc	RoundBumpExp
MaskOffLow:
	dec	edx			;Mask for round & sticky bits
	not	edx
	and	esi,edx			;Zero out low bits
RndSetTag:
	or	ebx,ebx			;Is it normalized?
        jns     RoundedHighHalf
        or      esi,esi                 ;Any bits in low half?
.erre   bTAG_VALID eq 1
.erre   bTAG_SNGL eq 0
        setnz   cl                      ;if low half==0 then cl=0 else cl=1
        ret

SplitRound:
;Rounding high half in esi on rounding bit in eax
	bt	esi,0			;Look at LSB
	adc	eax,(1 shl 31) - 1	;Set CY if round up
	jc	RoundUpThenMask
        or      ebx,ebx                 ;Will set ZF for jnz below
RoundedHighHalf:
;Rounding occured in high half, which had been moved low.
;Move it back up high.
;
;ZF set here on content of ebx.  If not zero, rounding high half in esi
;rippled forward into zero in ebx.
        mov     cl,bTAG_SNGL
        jnz     RndIntNorm              ;Present high half should be zero
        xchg    ebx,esi                 ;Shift left 32 bits
        ret

RndIntNorm:
;Rounded up high half of mantissa, which rolled over to 0.
	add	ecx,1 shl 16		;Increase exponent
	mov	ebx,1 shl 31		;Restore MSB
	ret				;Tag already set to SNGL

RoundBumpExp:
;Mantissa was FFFFF... and rolled over to 0 when we rounded
	add	ecx,1 shl 16		;Increase exponent
	mov	ebx,1 shl 31		;Restore MSB
	jmp	MaskOffLow

NotNearLow:
;We want to increase the magnitude if RCup and +, or RCdown and -
	mov	al,EMSEG:[CWcntl]	;Get rounding control
	sar	ch,7			;Expand sign through whole byte
.erre	(not RCup and RoundControl) eq RCdown
	xor	al,ch			;Flip rounding bits if negative
	and	al,RoundControl
	cmp	al,RCup			;Rounding up?
	jz	RoundUpThenMask		;yes
	jmp	MaskOffLow		;No, chop it