You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
8.6 KiB
335 lines
8.6 KiB
subttl emarith.asm - Arithmetic Operations
|
|
page
|
|
;*******************************************************************************
|
|
;emarith.asm - Arithmetic Operations
|
|
;
|
|
; Microsoft Confidential
|
|
;
|
|
; Copyright (c) Microsoft Corporation 1991
|
|
; All Rights Reserved
|
|
;
|
|
;Purpose:
|
|
; Arithmetic Operations
|
|
;
|
|
;Revision History:
|
|
;
|
|
; [] 09/05/91 TP Initial 32-bit version.
|
|
;
|
|
;*******************************************************************************
|
|
|
|
NextStackWrap esi,TwoOp ;Tied to NextStackElem below
|
|
|
|
EM_ENTRY eFPREM
|
|
eFPREM:
|
|
and [esp].[OldLongStatus+4],NOT(ConditionCode SHL 16) ;clear C0,C1,C2,C3
|
|
push offset PremCont ;Return address if normal
|
|
PremPointTopTwo:
|
|
push offset PremSpclDone ;Return address if special
|
|
mov ebp,offset tFpremDisp
|
|
PointTopTwo:
|
|
mov esi,edi
|
|
NextStackElem esi,TwoOp
|
|
TwoOpSiDi:
|
|
mov ecx,EMSEG:[esi].ExpSgn
|
|
mov ebx,EMSEG:[esi].lManHi
|
|
mov esi,EMSEG:[esi].lManLo
|
|
TwoOpSetResult:
|
|
mov EMSEG:[Result],edi ;Save result pointer
|
|
TwoOpResultSet:
|
|
mov ah,EMSEG:[edi].bTag
|
|
TwoOpDispAh:
|
|
mov al,cl
|
|
TwoOpDispatch:
|
|
and eax,TAG_MASK + 100H*TAG_MASK ;Look at internal tags only
|
|
shl al,TAG_SHIFT
|
|
or al,ah
|
|
xor ah,ah ;Zero ah
|
|
;UNDONE: masm bug! ebp + scaled index requires a displacement.
|
|
;UNDONE: No displacement is needed here, so masm should generate a
|
|
;UNDONE: zero. It doesn't! dec eax so we can add 4*1 back.
|
|
dec eax ;UNDONE
|
|
jmp dword ptr cs:[ebp+4*eax+4];UNDONE Go to appropriate routine.
|
|
|
|
EM_ENTRY eFPREM1
|
|
eFPREM1:
|
|
and [esp].[OldLongStatus+4],NOT(ConditionCode SHL 16) ;clear C0,C1,C2,C3
|
|
push offset Prem1Cont ;Return address if normal
|
|
jmp PremPointTopTwo
|
|
|
|
EM_ENTRY eFSCALE
|
|
eFSCALE:
|
|
mov ebp,offset tFscaleDisp
|
|
jmp PointTopTwo
|
|
|
|
EM_ENTRY eFPATAN
|
|
eFPATAN:
|
|
mov ebp,offset tFpatanDisp
|
|
TopTwoPop:
|
|
push offset PopWhenDone
|
|
mov esi,edi
|
|
add edi,Reg87Len ;edi = ST(1)
|
|
cmp edi,ENDstk
|
|
jb TwoOpSiDi
|
|
mov edi,BEGstk
|
|
jmp TwoOpSiDi
|
|
|
|
EM_ENTRY eFYL2X
|
|
eFYL2X:
|
|
mov ebp,offset tFyl2xDisp
|
|
jmp TopTwoPop
|
|
|
|
EM_ENTRY eFYL2XP1
|
|
eFYL2XP1:
|
|
mov ebp,offset tFyl2xp1Disp
|
|
jmp TopTwoPop
|
|
|
|
;*******************************************************************************
|
|
|
|
page
|
|
;-----------------------------------------------------------;
|
|
; ;
|
|
; Special Case Routines for Arithmetic Functions ;
|
|
; ;
|
|
;-----------------------------------------------------------;
|
|
|
|
;There are four kinds of "specials", encoded in the tag:
|
|
;
|
|
; Empty
|
|
; Infinity
|
|
; NAN (which can be QNAN or SNAN)
|
|
; Denormal
|
|
;
|
|
;Empty always results in an Invalid Operation exception with Stack Flag set
|
|
;and C1 (O/U#) bit clear, and returns Indefinite (a specific QNAN).
|
|
;
|
|
;Operations on NAN return the same NAN except it is always modified to a
|
|
;QNAN. If both operands are NAN, the one with the larger mantissa is
|
|
;returned. An SNAN causes an Invalid Operation exception except for
|
|
;internal FP stack operations, FCHS, and FABS. A QNAN does not cause
|
|
;and exception.
|
|
;
|
|
;Operations on Infinity return a result depending on the operation.
|
|
;
|
|
;UNDONE: Old code plays with sign of NAN when two NANs with equal
|
|
;mantissas are used. Why?
|
|
|
|
;"***" means entry point from dispatch tables
|
|
|
|
;***
|
|
DivSpclSource:
|
|
cmp cl,bTAG_INF
|
|
jnz SpclSource
|
|
;Division by infinity always returns zero
|
|
xor ch,EMSEG:[edi].bSgn
|
|
jmp SignedZero ;in emfmul.asm
|
|
|
|
;***
|
|
MulSpclSource:
|
|
cmp cl,bTAG_INF
|
|
jnz SpclSource
|
|
MulByInf:
|
|
cmp EMSEG:[edi].bTag,bTAG_ZERO ;Infinity * zero?
|
|
jz ReturnIndefinite
|
|
XorSourceSign:
|
|
xor ch,EMSEG:[edi].bSgn
|
|
jmp SaveResultEdi
|
|
|
|
;***
|
|
AddSpclSource:
|
|
cmp cl,bTAG_INF
|
|
jnz SpclSource
|
|
xor ch,dl ;Flip sign of infinity if subtracting
|
|
jmp SaveResultEdi
|
|
|
|
DenormalSource:
|
|
mov cl,bTAG_VALID ;Change denormal to DOUBLE
|
|
mov EMSEG:[CURerr],Denormal
|
|
test EMSEG:[CWmask],Denormal ;Is denormal exception masked?
|
|
jnz TwoOpResultSet
|
|
AbortOp:
|
|
mov cl,bTAG_NOPOP ;Unmasked, don't pop stack
|
|
ret
|
|
|
|
DenormalDisp:
|
|
;Repeat dispatch, but for normal ops
|
|
jmp dword ptr cs:[ebp+4*(TAG_VALID + TAG_VALID shl TAG_SHIFT)]
|
|
|
|
;***
|
|
DivrSpclSource:
|
|
cmp cl,bTAG_INF
|
|
jz XorSourceSign ;Return infinity
|
|
SpclSource:
|
|
cmp cl,bTAG_DEN
|
|
jz DenormalSource
|
|
cmp cl,bTAG_EMPTY
|
|
jz StackError
|
|
;Must be a NAN
|
|
SourceNAN:
|
|
test ebx,1 shl 30 ;Check for SNAN
|
|
jnz SaveResultEdi ;If QNAN, just use it as result
|
|
SourceSNAN:
|
|
or EMSEG:[CURerr],Invalid ;Flag the error
|
|
or ebx,1 shl 30 ;Make it into a QNAN
|
|
test EMSEG:[CWmask],Invalid ;Is it masked?
|
|
jnz SaveResultEdi ;If so, update with masked response
|
|
mov cl,bTAG_NOPOP ;Unmasked, don't pop stack
|
|
ret
|
|
|
|
|
|
;***
|
|
DivrSpclDest:
|
|
mov eax,EMSEG:[edi].ExpSgn ;Pick up tag
|
|
cmp al,bTAG_INF
|
|
jnz SpclDest
|
|
;Division by infinity always returns zero
|
|
xor ch,ah
|
|
jmp SignedZero ;in emfmul.asm
|
|
|
|
;***
|
|
MulSpclDest:
|
|
mov al,EMSEG:[edi].bTag ;Pick up tag
|
|
cmp al,bTAG_INF
|
|
jnz SpclDest
|
|
cmp cl,bTAG_ZERO ;Infinity * zero?
|
|
jz ReturnIndefinite
|
|
XorDestSign:
|
|
xor EMSEG:[edi].bSgn,ch ;Xor signs
|
|
ret
|
|
|
|
;***
|
|
AddSpclDest:
|
|
mov al,EMSEG:[edi].bTag ;Pick up tag
|
|
cmp al,bTAG_INF
|
|
jnz SpclDest
|
|
xor EMSEG:[edi].bSgn,dh ;Flip sign of infinity if subtracting
|
|
ret
|
|
|
|
DenormalDest:
|
|
mov ah,bTAG_VALID ;Change denormal to DOUBLE
|
|
mov EMSEG:[CURerr],Denormal
|
|
test EMSEG:[CWmask],Denormal ;Is denormal exception masked?
|
|
jnz TwoOpDispAh
|
|
mov cl,bTAG_NOPOP ;Unmasked, don't pop stack
|
|
ret
|
|
|
|
;***
|
|
DivSpclDest:
|
|
mov al,EMSEG:[edi].bTag ;Pick up tag
|
|
cmp al,bTAG_INF
|
|
jz XorDestSign ;Return infinity
|
|
SpclDest:
|
|
cmp al,bTAG_DEN
|
|
jz DenormalDest
|
|
SpclDestNotDen:
|
|
cmp al,bTAG_EMPTY
|
|
jz StackError
|
|
;Must be a NAN
|
|
DestNAN:
|
|
test EMSEG:[edi].bMan7,40H ;Check for SNAN
|
|
jnz ReturnDest ;If QNAN, just use it as result
|
|
DestSNAN:
|
|
or EMSEG:[CURerr],Invalid ;Flag the error
|
|
test EMSEG:[CWmask],Invalid ;Is it masked?
|
|
jz AbortOp ;No - preserve value
|
|
or EMSEG:[edi].bMan7,40H ;Make it into a QNAN
|
|
ret
|
|
|
|
StackError:
|
|
mov EMSEG:[CURerr],Invalid+StackFlag
|
|
ReturnIndefinite:
|
|
or EMSEG:[CURerr],Invalid
|
|
test EMSEG:[CWmask],Invalid ;Is it masked?
|
|
jz AbortOp ;No - preserve value
|
|
mov EMSEG:[edi].lManLo,0
|
|
mov EMSEG:[edi].lManHi,0C0000000H
|
|
mov EMSEG:[edi].ExpSgn,TexpMax shl 16 + bSign shl 8 + bTAG_NAN
|
|
ReturnDest:
|
|
ret
|
|
|
|
|
|
AddTwoInf:
|
|
;Adding two infinites.
|
|
;If signs are the same, return that infinity. Otherwise, Invalid Operation.
|
|
xor ch,dl ;Possibly subtracting source
|
|
xor ah,dh ;Possibly subtracting dest
|
|
xor ch,ah ;Compare signs
|
|
js ReturnIndefinite
|
|
mov EMSEG:[edi].bSgn,ah ;Correct the sign if subtracting
|
|
ret
|
|
|
|
;***
|
|
TwoOpBothSpcl:
|
|
;ebp = dispatch table address
|
|
mov al,EMSEG:[edi].bTag
|
|
mov ah,cl
|
|
cmp ax,(bTAG_NAN shl 8) + bTag_NAN ;Are both NAN?
|
|
jz TwoNANs
|
|
cmp cl,bTAG_EMPTY
|
|
jz StackError
|
|
cmp al,bTAG_EMPTY
|
|
jz StackError
|
|
cmp cl,bTAG_NAN
|
|
jz SourceNAN
|
|
cmp al,bTAG_NAN
|
|
jz DestNAN
|
|
cmp ax,(bTAG_INF shl 8) + bTag_INF ;Are both infinity?
|
|
jz TwoInfs
|
|
;At least one of the operands is a denormal
|
|
mov EMSEG:[CURerr],Denormal
|
|
test EMSEG:[CWmask],Denormal ;Is denormal exception masked?
|
|
jz AbortOp ;If not, don't do operation
|
|
;Denormal exception is masked, treat denormals as VALID
|
|
;Dispatch through operation table in ebp again
|
|
cmp ax,(bTAG_DEN shl 8) + bTag_DEN ;Are both denormal?
|
|
jz DenormalDisp
|
|
;Have an infinity and a denormal
|
|
cmp al,bTAG_INF
|
|
jz DestInf
|
|
;Source is denormal, Dest is infinity
|
|
jmp dword ptr [ebp+4*(TAG_SPCL + TAG_VALID shl TAG_SHIFT)]
|
|
|
|
DestInf:
|
|
;Source is infinity, Dest is denormal
|
|
jmp dword ptr [ebp+4*(TAG_VALID + TAG_SPCL shl TAG_SHIFT)]
|
|
|
|
TwoNANs:
|
|
;Two NANs. Use largest mantissa
|
|
cmp ebx,EMSEG:[edi].lManHi
|
|
ja BiggerNAN
|
|
jb DestBigger
|
|
;Now we know they're both the same type, SNAN or QNAN
|
|
cmp esi,EMSEG:[edi].lManLo
|
|
ja SourceNAN
|
|
;UNDONE: Old code did funny business with signs when mantissas were equal
|
|
jmp DestNAN
|
|
|
|
BiggerNAN:
|
|
test EMSEG:[edi].bMan7,40H ;Is smaller one SNAN?
|
|
jz SourceSNAN
|
|
jmp SourceNAN
|
|
|
|
DestBigger:
|
|
test ebx,40H ;Is smaller one SNAN?
|
|
jz DestSNAN
|
|
jmp DestNAN
|
|
|
|
TwoInfs:
|
|
mov ah,EMSEG:[edi].bSgn
|
|
jmp dword ptr [ebp+4*16] ;Go do code for two infinites
|
|
|
|
|
|
;***
|
|
DivideByMinusZero:
|
|
mov ch,bSign
|
|
;***
|
|
DivideByZero:
|
|
or EMSEG:[CURerr],ZeroDivide
|
|
test EMSEG:[CWmask],ZeroDivide ;Is exception masked?
|
|
jz AbortOp ;No - preserve value
|
|
;Set up a signed infinity
|
|
xor ch,EMSEG:[edi].bSgn ;Get result sign
|
|
and ecx,1 shl 15 ;Keep only sign bit
|
|
or ecx,(4000H+TexpBias) shl 16 + bTAG_INF ;ExpSgn of infinity
|
|
mov ebx,1 shl 31
|
|
xor esi,esi
|
|
jmp SaveResultEdi
|