page	,132
	subttl	emfdiv.asm - Division
;***
;emfdiv.asm - Division
;
;	Copyright (c) 1986-89, Microsoft Corporation
;
;Purpose:
;	Division
;
;	This Module contains Proprietary Information of Microsoft
;	Corporation and should be treated as Confidential.
;
;Revision History:
;	See emulator.hst
;
;*******************************************************************************


;-----------------------------------------;
;					  ;
;		Division		  ;
;					  ;
;-----------------------------------------;

ProfBegin FDIV

RDBRQQ:     ; Routine Div Both	 must see if we have two singles.

if	fastSP
	MOV	BX,DX
	XOR	BX,Single + 256*Single
	TEST	BX,Single + 256*Single
	JNZ	RDDRQQ
	MOV	bx,offset TDSRQQ
	JMP	[bx]
endif	;fastSP


pub	RDDRQQ	; Routine Division Double
; Now we have
;   SI --> numerator   , AX - Expon , DL - Sign
;   DI --> denominator , CX - Expon , DH - Sign

if	fastSP
	CALL	CoerceToDouble	; insure that both args are double
endif	;fastSP

	STC			; exponent will be difference - 1
	SBB	AX,CX		; compute result exponent

; AH has the (tentative) true exponent of the result.  It is correct if the
; result does not need normalizing.  If normalizing is required, then this
; must be incremented to give the correct result exponent

	XOR	DH,DL		; Compute sign
	PUSH	ebp
	PUSH	edx		; Save sign
	PUSH	esi
	PUSH	edi
	ADD	esi,6
	ADD	edi,6
	MOV	ecx,4
	STD
	REP	CMPS  word ptr [esi],word ptr [edi] ; compare numerator mantissa
	CLD			;    with denominator mantissa
	POP	edi
	POP	esi
	PUSHF			; save the flags from the compare
	MOV	BP,AX		; save the exponent
	LODS	word ptr [esi]	; Load up numerator
	MOV	CX,AX
	LODS	word ptr [esi]
	MOV	BX,AX
	LODS	word ptr [esi]
	MOV	DX,AX
	LODS	word ptr [esi]
	XCHG	AX,DX

; Move divisor to DAC so we can get at it easily.

	MOV	esi,edi 	; Move divisor to DAC
	MOV	edi,offset DAC
ifdef	i386
	MOVSD
	MOVSD
else
	MOVSW
	MOVSW
	MOVSW
	MOVSW
endif

; Now we're all set:
;	DX:AX:BX:CX has dividend
;	DAC has divisor (in normal format)
; Both are 64 bits with zeros and have implied bit set.
; Top of stack has sign and tentative exponent.

	XOR	DI,DI
	POPF			; numerator mantissa < denominator?
				; 80286 errata for POPF shouldn't
				; apply because interrupts should be
				; turned on in this context
	JB	short DivNoShift ;    if so bypass numerator shift
	SHR	DX,1		; Make sure dividend is smaller than divisor
	RCR	AX,1		;   by dividing it by two
	RCR	BX,1
	RCR	CX,1
	RCR	DI,1
	INC	BP		; increment result exponent
pub	DivNoShift
	PUSH	ebp		; save result exponent
	MOV	[REMLSW],DI	; Save lsb of remainder
	CALL	DIV16		; Get a quotient digit
	PUSH	edi
	MOV	[REMLSW],0	; Turn off the shifted bit
	CALL	DIV16
	PUSH	edi
	CALL	DIV16
	PUSH	edi
	CALL	DIV16
	MOV	BP,8001H	; turn round and sticky on
	SHL	CX,1
	RCL	BX,1
	RCL	AX,1
	RCL	DX,1		; multiply remainder by 2
	JC	short BPset	; if overflow, then round,sticky valid
	MOV	esi,offset DAC
	CMP	DX,[esi+6]
	JNE	short RemainderNotHalf
	CMP	AX,[esi+4]
	JNE	short RemainderNotHalf
	CMP	BX,[esi+2]
	JNE	short RemainderNotHalf
	CMP	CX,[esi]	; compare 2*remainder with denominator

;Observe, oh wondering one, how you can assume the result of this last
;compare is not equality.  Use the following notation: n=numerator,
;d=denominator,q=quotient,r=remainder,b=base(2^64 here).  If
;initially we had n < d then there was no shift and we will find q and r
;so that q*d+r=n*b, if initially we had n >= d then there was a shift and
;we will find q and r so that q*d+r=n*b/2.  If we have equality here
;then r=d/2  ==>  n={possibly 2*}(2*q+1)*d/(2*b), since this can only
;be integral if d is a multiple of b, but by definition b/2 <= d < b, we
;have a contradiction.	Equality is thus impossible at this point.

pub	RemainderNotHalf	; if 2*remainder > denominator
	JAE	short BPset	;    then round and sticky are valid
	OR	AX,DX
	OR	AX,CX
	OR	AX,BX
	OR	AL,AH		; otherwise or sticky bits into AL
	XOR	AH,AH		; clear round bit
	MOV	BP,AX		; move round and sticky into BP
pub	BPset
	MOV	DX,DI		; get low 16 bits into proper location
	POP	ecx
	POP	ebx
	POP	edi
	POP	esi		; Now restore exponent

	JMP	ROUND		; Result is normalized, round it


;	Remainder in DX:AX:BX:CX:REMLSW

pub	DIV16
	MOV	SI,[DAC+6]	; Get high word of divisor
	XOR	DI,DI		; Initialize quotient digit to zero
	CMP	DX,SI		; Will we overflow?
	JAE	MAXQUO		; If so, go handle special
	OR	DX,DX		; Is dividend small?
	JNZ	short DDIV
	CMP	SI,AX		; Will divisor fit at all?
	JA	short ZERQUO	; No - quotient is zero

pub	DDIV
	DIV	SI		; AX is our digit "guess"
	PUSH	edx		; Save remainder -
	PUSH	ebx		;   top 32 bits
	XCHG	AX,DI		; Quotient digit in DI
	XOR	BP,BP		; Initialize quotient * divisor
	MOV	SI,BP
	MOV	AX,[DAC]
	OR	AX,AX		; If zero, save multiply time
	JZ	short REM2
	MUL	DI		; Begin computing quotient * divisor
	MOV	SI,DX

pub	REM2
	PUSH	eax		; Save lowest word of quotient * divisor
	MOV	AX,[DAC+2]
	OR	AX,AX
	JZ	short REM3
	MUL	DI
	ADD	SI,AX
	ADC	BP,DX

pub	REM3
	MOV	AX,[DAC+4]
	OR	AX,AX
	JZ	short REM4
	MUL	DI
	ADD	BP,AX
	ADC	DX,0
	XCHG	AX,DX

;	Remainder - Quotient * divisor
;	[SP+4]:[SP+2]:CX:REMLSW - AX:BP:SI:[SP]

pub	REM4
	MOV	DX,[REMLSW]	; Low word of remainder
	POP	ebx		; Recover lowest word of quotient * divisor
	SUB	DX,BX
	SBB	CX,SI
	POP	ebx
	SBB	BX,BP
	POP	ebp		; Remainder from DIV
	SBB	BP,AX
	XCHG	AX,BP

pub	ZERQUO			; Remainder in AX:BX:CX:DX
	XCHG	AX,DX
	XCHG	AX,CX
	XCHG	AX,BX
	JNC	short DRET	; Remainder in DX:AX:BX:CX

pub	RESTORE
	DEC	DI		; Drop quotient since it didn't fit
	ADD	CX,[DAC]	; Add divisor back in until remainder goes +
	ADC	BX,[DAC+2]
	ADC	AX,[DAC+4]
	ADC	DX,[DAC+6]
	JNC	RESTORE 	; Loop is performed at most twice

pub	DRET
	RET

pub	MAXQUO
	DEC	DI		; DI=FFFF=2**16-1, DX:AX:BX:CX is remainder,
	SUB	CX,[DAC]	;    DX = [DAC+6], d = divisor = [DAC]
	SBB	BX,[DAC+2]
	SBB	AX,[DAC+4]	; subtract 2^16*d from DX:AX:BX:CX:0000H
	ADD	CX,[DAC+2]	;    (DX-[DAC+6] = 0 is implied)
	ADC	BX,[DAC+4]
	ADC	AX,DX		; add high 48 bits of d to AX:BX:CX:0000H
	MOV	DX,[DAC]	; add low 16 bits of d to zero giving DX
	CMC			; DI should be FFFEH if no carry from add
	JMP	ZERQUO

ProfEnd  FDIV