diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/dll/i386/emfadd.asm | |
download | NT4.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.asm | 396 |
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 |