windows-nt/Source/XPSP1/NT/base/ntdll/i386/emxtract.asm
2020-09-26 16:20:57 +08:00

310 lines
9.2 KiB
NASM

subttl emxtract - FXTRACT and FSCALE instructions
page
;*******************************************************************************
;emxtract - FXTRACT and FSCALE instructions
;
; Microsoft Confidential
;
; Copyright (c) Microsoft Corporation 1991
; All Rights Reserved
;
;Inputs:
; edi = [CURstk]
;
;Revision History:
;
; [] 09/05/91 TP Initial 32-bit version.
;
;*******************************************************************************
XtractStackOver:
mov EMSEG:[SWcc],C1 ;Flag stack overflow
XtractEmpty:
;Result is two Indefinites (if exception masked)
call StackError ;Put first indefinite at [edi] = ST(0)
jz XtractExit ;Error was unmasked--just exit
mov EMSEG:[CURstk],edi
mov eax,EMSEG:[edi].ExpSgn
mov EMSEG:[esi].ExpSgn,eax
mov eax,EMSEG:[edi].lManHi
mov EMSEG:[esi].lManHi,eax
mov eax,EMSEG:[edi].lManLo
mov EMSEG:[esi].lManLo,eax
ret
PrevStackWrap edi,Xtract
EM_ENTRY eFXTRACT
eFXTRACT:
;edi = [CURstk]
mov esi,edi ;Save current ST
PrevStackElem edi,Xtract
;edi = ST(0)
;esi = ST(1) (operand)
mov eax,EMSEG:[esi].ExpSgn
;Exception priority requires reporting stack underflow (i.e., using an EMPTY)
;before stack overflow (i.e., no place for result). Yes, both can happen
;together if they've messed with the stack! (ST empty when ST(-1) isn't).
cmp al,bTAG_EMPTY ;Is operand empty?
jz XtractEmpty
cmp EMSEG:[edi].bTag,bTAG_EMPTY ;Is there an empty spot?
jnz XtractStackOver
cmp al,bTAG_ZERO ;Is it special?
jae XtractSpclOrZero
XtractNormal:
mov EMSEG:[CURstk],edi
.erre TexpBias eq 0
movzx ebx,ax ;Zero exponent
;Save mantissa in ST(0)
mov EMSEG:[edi].ExpSgn,ebx
mov ebx,EMSEG:[esi].lManHi
mov EMSEG:[edi].lManHi,ebx
mov ebx,EMSEG:[esi].lManLo
mov EMSEG:[edi].lManLo,ebx
mov edi,esi ;Save ST(1) pointer in edi
shr eax,16 ;Move exponent down
call NormInt16 ;in emload.asm
;mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
mov EMSEG:[edi].lManLo,esi
mov EMSEG:[edi].lManHi,ebx
mov EMSEG:[edi].ExpSgn,ecx
XtractExit:
ret
XtractSpcl:
cmp al,bTAG_INF
jz XtractInf
cmp al,bTAG_NAN
jz XtractNAN
;Must be denormal. Change tag to VALID or SNGL.
cmp EMSEG:[esi].lManLo,0 ;Any bits in low half?
.erre bTAG_VALID eq 1
.erre bTAG_SNGL eq 0
setnz al ;if low half==0 then al=0 else al=1
mov EMSEG:[CURerr],Denormal
test EMSEG:[CWmask],Denormal ;Is it masked?
jnz XtractNormal ;If so, ignore denormalization
ret
XtractSpclOrZero:
ja XtractSpcl
;Operand is zero. Result is ST(0) = 0 (same sign), ST(1) = -infinity
mov EMSEG:[CURerr],ZeroDivide
test EMSEG:[CWmask],ZeroDivide ;Exception masked?
jz XtractExit
mov EMSEG:[CURstk],edi
mov EMSEG:[edi].ExpSgn,eax
mov eax,EMSEG:[esi].lManHi
mov EMSEG:[edi].lManHi,eax
mov eax,EMSEG:[esi].lManLo
mov EMSEG:[edi].lManLo,eax
mov EMSEG:[esi].ExpSgn,(IexpMax-IexpBias+TexpBias) shl 16 + bSign shl 8 + bTAG_INF
mov EMSEG:[esi].bMan7,80H ;Change zero to infinity
ret
XtractInf:
;Result is ST(0) = infinity (same sign), ST(1) = +infinity
mov EMSEG:[esi].bSgn,0 ;Ensure ST(1) is positive
XtractQNAN:
mov EMSEG:[CURstk],edi
mov EMSEG:[edi].ExpSgn,eax
mov eax,EMSEG:[esi].lManHi
mov EMSEG:[edi].lManHi,eax
mov eax,EMSEG:[esi].lManLo
mov EMSEG:[edi].lManLo,eax
ret
XtractNAN:
;Result is two QNANs, signal Invalid Operation if SNAN
test EMSEG:[esi].bMan7,40H ;Is it SNAN?
jnz XtractQNAN
mov EMSEG:[CURerr],Invalid
test EMSEG:[CWmask],Invalid
jz XtractExit
or EMSEG:[esi].bMan7,40H ;Change to QNAN
jmp XtractQNAN
;*******************************************************************************
;
;FSCALE instruction
;Actual instruction entry point is in emarith.asm
;Dispatch table for scale
;
;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
tFscaleDisp label dword ;Source (reg) Dest (*[di] = ST)
dd ScaleDouble ;single single
dd ScaleDouble ;single double
dd ScaleX ;single zero
dd ScaleSpclDest ;single special
dd ScaleDouble ;double single
dd ScaleDouble ;double double
dd ScaleX ;double zero
dd ScaleSpclDest ;double special
dd ScaleX ;zero single
dd ScaleX ;zero double
dd ScaleX ;zero zero
dd ScaleSpclDest ;zero special
dd ScaleSpclSource ;special single
dd ScaleSpclSource ;special double
dd ScaleSpclSource ;special zero
dd TwoOpBothSpcl ;special special
dd ScaleTwoInf ;Two infinites
;The unmasked response to overflow and underflow with FSCALE is complicated
;by the extreme range it can generate. Normally, the exponent is biased
;by 24,576 in the appropriate direction to bring it back into range.
;This may not be enough, however. If it isn't, a result of infinity
;(with the correct sign) is returned for overflow, regardless of the
;rounding mode. For underflow, zero (with the correct sign) is returned,
;even if it could be represented as a denormal. This may be the only
;operation in which the unmasked response destroys the operands beyond
;recovery.
BigScale:
;Scale factor is much too big. Just shift mantissa right two bits to get
;MSB out of sign bit and ensure no overflow when we add.
mov cl,2 ;Always shift 2 bits if it's big
jmp ScaleCont
ScaleDouble:
;ebx:esi = ST(1) mantissa
;ecx = ST(1) sign in bit 15, exponent in high half
;edi = pointer to ST(0)
rol ecx,16 ;Bring exponent down, sign to top
or ch,ch ;Check sign of exponent
js ScaleX ;No work if less than zero
cmp cx,30 ;Scale factor exceed 30 bits?
jge BigScale
not cl ;cl = amount to shift right (mod 32)
ScaleCont:
shr ebx,cl ;ebx = exponent adjustment for ST(0)
;Use two's complement if negative (complement and increment)
mov eax,ecx
cdq ;Extend sign through edx
xor ebx,edx ;Complement if negative
sub ebx,edx ;Increment if negative
;Scale exponent
movsx eax,EMSEG:[edi].wExp ;Get exponent to adjust
add eax,ebx ;Can't overflow
cmp eax,IexpMax-IexpBias ;Within normal range?
jge ScaleOverflow
cmp eax,IexpMin-IexpBias
jle ScaleUnderflow
SaveScaledExp:
;Result fit withing normal range
mov EMSEG:[edi].wExp,ax ;Update exponent of ST(0)
ScaleX:
ret
ScaleOverflow:
;eax = exponent that's too big
mov EMSEG:[CURerr],Overflow
test EMSEG:[CWmask],Overflow ;Is exception unmasked?
jz UnmaskedScaleOvfl
;Produce masked overflow response
mov al,EMSEG:[CWcntl] ;Get rounding control
mov ah,al
;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
jz ScaleToInfinity ;Save Infinity
;Get max value
sub ecx,1 shl 16 ;Drop exponent by 1
xor esi,esi
dec esi ;esi == -1
mov ebx,esi
SaveScaleMax:
mov EMSEG:[edi].lManLo,esi
mov EMSEG:[edi].lManHi,ebx
mov EMSEG:[edi].ExpSgn,ecx
ret
UnmaskedScaleOvfl:
sub eax,UnderBias ;Unmasked response
cmp eax,IexpMax-IexpBias ;Within normal range now?
jl SaveScaledExp ;Use exponent biased by 24K
ScaleToInfinity:
mov ebx,1 shl 31
xor esi,esi
mov ecx,(IexpMax-IexpBias+TexpBias) shl 16 + bTAG_INF
mov ch,EMSEG:[edi].bSgn ;Give it same sign
jmp SaveScaleMax ;Use infinity
ScaleUnderflow:
;eax = exponent that's too big
test EMSEG:[CWmask],Underflow ;Is exception unmasked?
jz ScaleSetUnder
cmp eax,-32768 ;Does exponent fit in 16 bits?
jg @F
mov ax,-32768 ;Max value
@@:
;Set up for denormalizer
mov ebx,EMSEG:[edi].lManHi
mov esi,EMSEG:[edi].lManLo
shrd ecx,eax,16 ;Move exponent to high end of ecx
mov ch,EMSEG:[edi].bSgn ;Keep sign
xor eax,eax ;No sticky bits
mov EMSEG:[Result],edi
jmp Denormalize ;In emround.asm
ScaleSetUnder:
;Underflow exception not masked. Adjust exponent and try again.
mov EMSEG:[CURerr],Underflow
add eax,UnderBias ;Unmasked response
cmp eax,IexpMin-IexpBias ;Within normal range now?
jg SaveScaledExp ;Use exponent biased by 24K
mov EMSEG:[CURerr],Underflow
ScaleToZero:
mov ecx,bTAG_ZERO
mov ch,EMSEG:[edi].bSgn ;Give it same sign
xor ebx,ebx
mov esi,ebx
jmp SaveScaleMax ;Set to zero
;***
ScaleSpclDest:
mov al,EMSEG:[edi].bTag ;Pick up tag
cmp al,bTAG_INF ;Scaling infinity?
jz ScaleRet ;No change if so
jmp SpclDest ;In emarith.asm
ScaleRet:
ret
;***
ScaleSpclSource:
cmp cl,bTAG_INF ;Scaling by infinity?
jnz SpclSource ;in emarith.asm
or ch,ch ;Scaling by -infinity?
js ScaleToZero
cmp EMSEG:[edi].bTag,bTAG_ZERO ;Zero scaled by +infinity?
jnz ScaleToInfinity
jmp ReturnIndefinite ;Invalid operation
;***
ScaleTwoInf:
or ch,ch ;Scaling by +infinity?
jns ScaleRet ;All done then
;Scaling infinity by -infinity
jmp ReturnIndefinite ;Invalid operation