summaryrefslogtreecommitdiffstats
path: root/private/ntos/dll/i386/emfadd.asm
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/dll/i386/emfadd.asm
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/dll/i386/emfadd.asm')
-rw-r--r--private/ntos/dll/i386/emfadd.asm396
1 files changed, 396 insertions, 0 deletions
diff --git a/private/ntos/dll/i386/emfadd.asm b/private/ntos/dll/i386/emfadd.asm
new file mode 100644
index 000000000..cdd0a8f58
--- /dev/null
+++ b/private/ntos/dll/i386/emfadd.asm
@@ -0,0 +1,396 @@
+ subttl emfadd.asm - Addition and Subtraction
+ page
+;*******************************************************************************
+; Copyright (c) Microsoft Corporation 1991
+; All Rights Reserved
+;
+;emfadd.asm - long double add and subtract
+; by Tim Paterson
+;
+;Purpose:
+; Long double add/subtract.
+;Outputs:
+; Jumps to [RoundMode] to round and store result.
+;
+;Revision History:
+;
+; [] 09/05/91 TP Initial 32-bit version.
+;
+;*******************************************************************************
+
+;*******************************************************************************
+; Dispatch for Add/Sub/Subr
+;
+; Signs are passed in dx:
+; xor source sign with dl
+; xor dest sign with dh
+;
+;One operand has been loaded into ecx:ebx:esi ("source"), the other is
+;pointed to by edi ("dest").
+;
+;Tag of source is shifted. Tag values are as follows:
+.erre TAG_SNGL eq 0 ;SINGLE: low 32 bits are zero
+.erre TAG_VALID eq 1
+.erre TAG_ZERO eq 2
+.erre TAG_SPCL eq 3 ;NAN, Infinity, Denormal, Empty
+;Any special case routines not found in this file are in emarith.asm
+tFaddDisp label dword ;Source (reg) Dest (*[di])
+ dd AddDouble ;single single
+ dd AddDouble ;single double
+ dd AddSourceSign ;single zero
+ dd AddSpclDest ;single special
+ dd AddDouble ;double single
+ dd AddDouble ;double double
+ dd AddSourceSign ;double zero
+ dd AddSpclDest ;double special
+ dd AddDestSign ;zero single
+ dd AddDestSign ;zero double
+ dd AddZeroZero ;zero zero
+ dd AddSpclDest ;zero special
+ dd AddSpclSource ;special single
+ dd AddSpclSource ;special double
+ dd AddSpclSource ;special zero
+ dd TwoOpBothSpcl ;special special
+ dd AddTwoInf ;Two infinities
+
+EM_ENTRY eFISUB16
+eFISUB16:
+ call Load16Int
+ mov dx,bSign ;Change sign of source
+ jmp AddSetResult
+
+EM_ENTRY eFISUBR16
+eFISUBR16:
+ call Load16Int
+ mov dx,bSign shl 8 ;Change sign of dest
+ jmp AddSetResult
+
+EM_ENTRY eFIADD16
+eFIADD16:
+ call Load16Int
+ xor edx,edx ;Both signs positive
+ jmp AddSetResult
+
+EM_ENTRY eFISUB32
+eFISUB32:
+ call Load32Int
+ mov dx,bSign ;Change sign of source
+ jmp AddSetResult
+
+EM_ENTRY eFISUBR32
+eFISUBR32:
+ call Load32Int
+ mov dx,bSign shl 8 ;Change sign of dest
+ jmp AddSetResult
+
+EM_ENTRY eFIADD32
+eFIADD32:
+ call Load32Int
+ xor edx,edx ;Both signs positive
+ jmp AddSetResult
+
+EM_ENTRY eFSUB32
+eFSUB32:
+ call Load32Real
+ mov dx,bSign ;Change sign of source
+ jmp AddSetResult
+
+EM_ENTRY eFSUBR32
+eFSUBR32:
+ call Load32Real
+ mov dx,bSign shl 8 ;Change sign of dest
+ jmp AddSetResult
+
+EM_ENTRY eFADD32
+eFADD32:
+ call Load32Real
+ xor edx,edx ;Both signs positive
+ jmp AddSetResult
+
+EM_ENTRY eFSUB64
+eFSUB64:
+ call Load64Real
+ mov dx,bSign ;Change sign of source
+ jmp AddSetResult
+
+EM_ENTRY eFSUBR64
+eFSUBR64:
+ call Load64Real
+ mov dx,bSign shl 8 ;Change sign of dest
+ jmp AddSetResult
+
+EM_ENTRY eFADD64
+eFADD64:
+ call Load64Real
+ xor edx,edx ;Both signs positive
+ jmp AddSetResult
+
+
+PolyAddDouble:
+;This entry point is used by polynomial evaluator.
+;It checks the operand in registers for zero, and doesn't require
+;signs to be set up in dx.
+;
+;op1 mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
+;edi = pointer to op2 in ds
+ xor edx,edx ;Addition
+ cmp cl,bTAG_ZERO ;Adding to zero?
+ jnz AddDouble
+;Number in registers is zero, so just return value from memory.
+ mov ecx,EMSEG:[edi].ExpSgn
+ mov ebx,EMSEG:[edi].lManHi
+ mov esi,EMSEG:[edi].lManLo
+ ret
+
+EM_ENTRY eFSUBPreg
+eFSUBPreg:
+ push offset PopWhenDone
+
+EM_ENTRY eFSUBreg
+eFSUBreg:
+ xchg esi,edi
+
+EM_ENTRY eFSUBtop
+eFSUBtop:
+ mov dx,bSign ;Change sign of source
+ jmp AddHaveSgn
+
+EM_ENTRY eFSUBRPreg
+eFSUBRPreg:
+ push offset PopWhenDone
+
+EM_ENTRY eFSUBRreg
+eFSUBRreg:
+ xchg esi,edi
+
+EM_ENTRY eFSUBRtop
+eFSUBRtop:
+ mov dx,bSign shl 8 ;Change sign of dest
+ jmp AddHaveSgn
+
+
+InsignifAdd:
+ mov eax,1 ;Set sticky bit
+ shl ch,1 ;Get sign, CY set IFF subtracting mant.
+ jnc ReturnOp1
+ sub esi,eax ;Subtract 1 from mantissa
+ sbb ebx,0
+ neg eax
+ReturnOp1:
+;ebx:esi:eax = normalized unrounded mantissa
+;high half of ecx = exponent
+;high bit of ch = sign
+ jmp EMSEG:[RoundMode]
+
+EM_ENTRY eFADDPreg
+eFADDPreg:
+ push offset PopWhenDone
+
+EM_ENTRY eFADDreg
+eFADDreg:
+ xchg esi,edi
+
+EM_ENTRY eFADDtop
+eFADDtop:
+ xor edx,edx ;Both signs positive
+AddHaveSgn:
+ mov ecx,EMSEG:[esi].ExpSgn
+ mov ebx,EMSEG:[esi].lManHi
+ mov esi,EMSEG:[esi].lManLo
+AddSetResult:
+ mov ebp,offset tFaddDisp
+ mov EMSEG:[Result],edi ;Save result pointer
+ mov al,cl
+ mov ah,EMSEG:[edi].bTag
+ test ax,ZEROorSPCL * 100H + ZEROorSPCL
+ jnz TwoOpDispatch
+
+;.erre AddDouble eq $ ;Fall into AddDouble
+
+;*********
+AddDouble:
+;*********
+;
+;op1 mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7
+;dl = sign change for op1
+;dh = sign change for op2
+;edi = pointer to op2
+
+ xor ch,dl ;Flip sign if subtracting
+ mov eax,EMSEG:[edi].ExpSgn
+ xor ah,dh ;Flip sign if subtracting
+ mov edx,EMSEG:[edi].lManHi
+ mov edi,EMSEG:[edi].lManLo
+
+AddDoubleReg:
+;op1 mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7
+;op2 mantissa in edx:edi, exponent in high eax, sign in ah bit 7
+
+ cmp eax,ecx ;Compare exponents
+.erre TexpBias eq 0 ;Not biased, use signed jump
+ jle short HavLg ;op1 is larger, we have the right order
+ xchg esi,edi
+ xchg ebx,edx
+ xchg eax,ecx
+HavLg:
+;Larger in ebx:esi. Note that if the exponents were equal, things like
+;the sign bit or tag may have determined which is "larger". It doesn't
+;matter which is which if the exponents are equal, however.
+ and ah,80H ;Keep sign bit
+ sar ch,1 ;Extend sign into bit 6 of byte
+ xor ch,ah ;See if signs are the same
+ xor ax,ax ;Clear out sign and tag
+ neg eax ;ax still 0
+ add eax,ecx ;Get exponent difference
+ shr eax,16 ;Bring exp. difference down to low end
+ jz short Aligned
+ cmp eax,64+1 ;Is difference in range?
+;CONSIDER: tell me again why 1/4 LSB could have effect. It seems like
+;CONSIDER: 1/2 LSB is the limit.
+ ja short InsignifAdd ; (Even 1/4 LSB could have effect)
+ mov cl,al ;Shift count to cl
+;High half ecx = exponent
+;ch bit 7 = sign difference
+;ch bit 6 = sign
+;cl = shift count
+ xor eax,eax ;Prepare to take bits shifted out
+ cmp cl,32 ;More than a whole word?
+ jb short ShortShift
+ xchg eax,edx ;Save bits shifted out in eax
+ xchg edi,eax
+ sub cl,32
+ cmp cl,8 ;Safe to shift this much
+ jb short ShortSticky
+;Collapse all (sticky) bits of eax into LSB of edi
+ neg eax ;Sets CY if eax was not zero
+ sbb eax,eax ;-1 if CY was set, zero otherwise
+ neg eax ;Sticky bit in LSB only
+ or di,ax ;Move sticky bit up
+ cmp cl,32 ;Less than another Dword?
+ jb short ShortShift
+ mov eax,edi
+ xor edi,edi ;edx = edi = 0
+ShortSticky:
+;Shift will not be more than 8 bits
+ or ah,al ;Move up sticky bits
+ShortShift:
+ shrd eax,edi,cl ;Save bits shifted out in eax
+ shrd edi,edx,cl
+ shr edx,cl
+Aligned:
+ shl ch,1 ;Were signs the same?
+ jc short SubMant ;No--go subtract mantissas
+;Add mantissas
+ add esi,edi
+ adc ebx,edx
+ jnc short AddExit
+;Addition of mantissas overflowed. Bump exponent and shift right
+ shrd eax,esi,1
+ shrd esi,ebx,1 ;Faster than RCR
+ sar ebx,1
+ or ebx,1 shl 31 ;Set MSB
+ add ecx,1 shl 16
+AddExit:
+;ebx:esi:eax = normalized unrounded mantissa
+;high half of ecx = exponent
+;high bit of ch = sign
+ jmp EMSEG:[RoundMode]
+
+NegMant:
+;To get here, exponents must have been equal and op2 was bigger than op1.
+;Note that this means nothing ever got shifted into eax.
+ not ch ;Change sign of result
+ not ebx
+ neg esi
+ sbb ebx,-1
+ js short AddExit ;Already normalized?
+ test ebx,40000000H ;Only one bit out of normal?
+ jz short NormalizeAdd
+ jmp short NormOneBit
+
+SubMant:
+;Subtract mantissas
+ neg eax ;Pretend minuend is zero extended
+ sbb esi,edi
+ sbb ebx,edx
+ jc short NegMant
+ js short AddExit ;Already normalized?
+NormChk:
+ test ebx,40000000H ;Only one bit out of normal?
+ jz short NormalizeAdd
+;One bit normalization
+NormOneBit:
+ sub ecx,1 shl 16 ;Adjust exponent
+ShiftOneBit: ;Entry point from emfmul.asm
+ shld ebx,esi,1
+ shld esi,eax,1
+ shl eax,1
+ jmp EMSEG:[RoundMode]
+
+;***********
+AddZeroZero: ;Entry point for adding two zeros
+;***********
+ mov ah,EMSEG:[edi].bSgn ;Get sign of op
+ xor ch,dl ;Possibly subtracting source
+ xor ah,dh ;Possibly subtracting dest
+ xor ch,ah ;Do signs match?
+ js FindZeroSign ;No - use rounding mode to set sign
+ mov EMSEG:[edi].bSgn,ah ;Correct the sign if subtracting
+ ret ;Result at [edi] is now correct
+
+ZeroChk:
+;Upper 64 bits were all zero, but there could be 1 bit in the MSB
+;of eax.
+ or eax,eax
+ jnz short OneBitLeft
+ mov ebx,eax
+ mov esi,eax ;Zero mantissa
+FindZeroSign:
+;Round to -0 if "round down" mode, round to +0 otherwise
+ xor ecx,ecx ;Zero exponent, positive sign
+ mov dl,EMSEG:[CWcntl] ;Get control word
+ and dl,RoundControl
+ cmp dl,RCdown ;Rounding down?
+ jnz ZeroJmp
+ mov ch,80H ;Set sign bit
+ZeroJmp:
+ mov cl,bTAG_ZERO
+ jmp EMSEG:[ZeroVector]
+
+OneBitLeft:
+ xchg ebx,eax ;Bit now normalized
+ sub ecx,64 shl 16 ;Adjust exponent
+ jmp EMSEG:[RoundMode]
+
+NormalizeAdd:
+;Inputs:
+; ebx:esi:eax = 65-bit number
+; ecx high half = exponent
+;
+;Since we are more than 1 bit out of normalization, exponents must have
+;differed by 0 or 1. Thus rounding will not be necessary for 64 bits.
+ bsr edx,ebx ;Scan for MSB
+ jnz short ShortNorm
+ bsr edx,esi
+ jz short ZeroChk
+ sub ecx,32 shl 16 ;Adjust exponent
+ mov ebx,esi ;Push it up 32 bits
+ mov esi,eax
+ShortNorm:
+;Bit number in edx ranges from 0 to 31
+ mov cl,dl
+ not cl ;Convert bit number to shift count
+ shld ebx,esi,cl
+ shld esi,eax,cl
+ shl edx,16 ;Move exp. adjustment to high end
+ lea ecx,[ecx+edx-(31 shl 16)] ;Adjust exponent
+ xor eax,eax ;No extra bits
+ jmp EMSEG:[RoundMode]
+
+AddDestSign:
+ xor EMSEG:[edi].bSgn,dh
+ ret
+
+AddSourceSign:
+ xor ch,dl
+ jmp SaveResult