page ,132
subttl emftran.asm - Transcendentals
;***
;emftran.asm - Transcendentals
;
; Copyright (c) 1986-89, Microsoft Corporation
;
;Purpose:
; Transcendentals
;
; This Module contains Proprietary Information of Microsoft
; Corporation and should be treated as Confidential.
;
;Revision History:
; See emulator.hst
;
;*******************************************************************************
;-----------------------------------------;
; ;
; Transcendentals ;
; ;
;-----------------------------------------;
ProfBegin FTRAN
pub MoveCodeSItoDataSI
PUSH edi
MOV edi,offset COEFFICIENT
ifdef i386
rept Reg87Len/4
MOVS dword ptr es:[edi],dword ptr cs:[esi]
endm
else
rept Reg87Len/2
MOVS word ptr es:[edi],word ptr cs:[esi]
endm
endif
MOV esi,offset COEFFICIENT
POP edi
RET
;---------------------------------------------------
; !
; 8087 emulator transcendental utilities !
; !
;---------------------------------------------------
; COMPcsSIDI is analogous to the 8086 CMP instruction with operands
; cs:[SI],[DI]. All registers except CX and DX are left unaltered.
; Zero and negative zero are determined to be unequal. NAN's and
; infinities may not be compared with this routine.
;
; FRAT2X performs {TOS=[DI]} <-- {TOS=[SI]}*PNUM({TOS=[SI]}^2),
; and program created {temp=[SI]} <-- PDEN({TOS=[SI]}^2). On input,
; [BX] must contain the degree of PNUM, the coefficients of PNUM
; in descending order, the degree-1 of PDEN and the coefficients
; of PDEN in descending order. PDEN is evaluated assuming an implied
; highest coefficient of one. [BX] is left unaltered, ARG2 is loaded
; with {TOS}^2, DENORX is used, all registers are destroyed with
; DI returning the value input in SI.
pub BOTHZERO
CMP CH,CH ;set flags to equal
JMP short COMPDONE ;compare finished
pub COMPcsSIDI
MOV CX,CS
MOV DS,CX
MOV CX,[esi+Flag] ;get sign byte of [SI]
AND CL,Sign ;mask for sign
MOV DX,ES:[edi+Flag] ;get sign byte of [DI]
AND DL,Sign ;mask for sign
CMP DL,CL ;compare signs
JNE short SIGNDIFF
PUSH ES
PUSH esi
PUSH edi ;save pointers
OR CL,CL ;if signs are +
JNS short BOTHPOS ; don't exchange pointers
PUSH DS
PUSH ES
POP DS
POP ES
XCHG esi,edi ;exchange pointers
XCHG CX,DX ;exchange flags
pub BOTHPOS
AND CH,ZROorINF ;mask for zero
AND DH,ZROorINF ;mask for zero
CMP DH,CH ;if exactly one zero
JNE short COMPDONE ; then finished
OR CH,CH ;if both zero
JA BOTHZERO ; then done after flags set
MOV CX,[esi+Expon] ;get exponent of [SI]
ADD CX,IexpBias ;make it unbiased
MOV DX,ES:[edi+Expon] ;get exponent of [DI]
ADD DX,IexpBias ;make it unbiased
CMP CX,DX
JNE short COMPDONE ;compare exponents
ADD esi,MB6
ADD edi,MB6
STD
CMPS word ptr [edi],word ptr [esi]
JNE short COMPDONE
CMPS word ptr [edi],word ptr [esi]
JNE short COMPDONE
CMPS word ptr [edi],word ptr [esi]
JNE short COMPDONE
CMPS word ptr [edi],word ptr [esi] ;compare mantissas
pub COMPDONE
CLD
POP edi
POP esi
POP ES
pub SIGNDIFF
MOV CX,ES
MOV DS,CX
RET
pub FRAT2X
MOV edi,offset DENORX ;[DI]=temp
CALL MOVRQQ ;[DI]=x=temp
PUSH edi ;save ptr to x=temp
PUSH esi ;save ptr to TOS
PUSH ebx ;save ptr to polynomials
MOV edi,offset ARG2 ;get ptr to space for x^2
CALL MOVRQQ ;copy x to space for x^2
MOV [RESULT],edi ;result=[DI]
CALL MUDRQQ ;ARG2 gets x^2
POP esi ;get ptr to numerator poly
ifdef i386
xor ecx,ecx
endif
LODS word ptr CS:[esi]
XCHG CX,AX ;CX=denominator degree-1
POP edi ;[DI]=TOS
CALL csMOVRQQ ;[DI]=first coeff=TOS
MOV [RESULT],edi ;result=[DI]
pub POLYLOOPA
PUSH ecx ;save no. of terms left
PUSH esi ;save ptr to next coeff
MOV esi,offset ARG2 ;get ptr to x^2
CALL MUDRQQ ;multiply TOS by x^2
POP esi ;get pointer to coeff
ADD esi,Reg87Len ;point to next coeff
PUSH esi ;save pointer to coeff
CALL MoveCodeSItoDataSI
CALL ADDRQQ ;add coeff to TOS
POP esi ;get ptr to coeff
POP ecx ;get no. of terms remaining
LOOP POLYLOOPA ;loop until no terms left
MOV ebx,esi ;move poly ptr
POP esi ;[SI]=x=temp
PUSH esi ;save ptr to x
PUSH ebx ;save poly ptr
CALL MUDRQQ ;multiply poly by x
POP esi ;get ptr to poly
ADD esi,12 ;[SI]=denominator degree-1
ifdef i386
xor ecx,ecx
endif
LODS word ptr CS:[esi]
XCHG CX,AX ;CX=denominator degree-1
POP ebx ;[BX]=temp
PUSH edi ;save denominator ptr
MOV edi,ebx ;[DI]=temp
CALL csMOVRQQ ;move second coeff to temp
PUSH ecx ;save poly degree-1
PUSH esi ;save ptr to denominator poly
MOV esi,offset ARG2 ;get ptr to x^2
MOV [RESULT],edi ;result=[DI]
CALL ADDRQQ ;add x^2 to temp
POP esi ;get ptr to second coeff
POP ecx ;get poly degree-1
pub POLYLOOPB
PUSH ecx ;save no. of terms left
ADD esi,Reg87Len ;point to next coeff
PUSH esi ;save ptr to next coeff
MOV esi,offset ARG2 ;get ptr to x^2
CALL MUDRQQ ;multiply temp by x^2
POP esi ;get pointer to coeff
PUSH esi ;save pointer to coeff
CALL MoveCodeSItoDataSI
CALL ADDRQQ ;add coeff to temp
POP esi ;get ptr to coeff
POP ecx ;get no. of terms remaining
LOOP POLYLOOPB ;loop until no terms left
MOV esi,edi ;[SI]=denominator=temp
POP edi ;[DI]=numerator=TOS
RET
;-------------------------------------------------------------------------------
pub eFPTAN
MOV esi,[CURstk]
CALL $FPTAN
PUSH esi
PUSHST
MOV edi,[CURstk]
POP esi
CALL MOVRQQ
RET
;---------------------------------------------------
; !
; 8087 emulator partial tangent !
; !
;---------------------------------------------------
; When 0<=x={TOS=[SI]}<=pi/4 then $FPTAN performs {TOS=[DI]} <--
; numerator tangent ({TOS=[SI]}), system created {temp=[SI]} <--
; denominator tangent ({TOS=[SI]). Every register except DI is
; destroyed.
pub $FPTAN
MOV ebx,offset TANRAT ;[BX]=rational function
CALL FRAT2X ;[DI]=numerator=TOS,
RET ; [SI]=denominator=temp
;-------------------------------------------------------------------------------
pub eFPATAN
MOV edi,[CURstk]
MOV esi,edi
MOV AX,Flag[esi]
SUB edi,Reg87Len
pub CALLFPATAN
CALL $FPATAN
MOV esi,[CURstk]
POPST
RET
;---------------------------------------------------
; !
; 8087 emulator arctangent !
; !
;---------------------------------------------------
; When 0<y={[DI]=NOS}<=x={[SI]=TOS}<infinity then $FPATAN performs
; {NOS=[DI]} <-- arctangent({NOS=[DI]}/{TOS=[SI]}), TOS is left
; unaltered. All registers except DI are destroyed.
pub $FPATAN
MOV [RESULT],edi ;result=[DI]
CALL DIDRQQ ;NOS=[DI] <-- [DI]/[SI]=x
MOV AL,0 ;flag reset
MOV esi,offset TWOMRT3 ;[SI]=2-3^.5
CALL COMPcsSIDI ;if 2-3^.5 >= x
JNB short ATNREDUCED ; then bypass arg reduction
MOV esi,edi ;[SI]=x=NOS
MOV edi,offset TEMP1 ;[DI]=temp
CALL MOVRQQ ;[DI]=x=temp
PUSH esi ;save NOS
MOV esi,offset RT3 ;[SI]=3^.5
CALL MoveCodeSItoDataSI
MOV [RESULT],edi ;result=[DI]
CALL MUDRQQ ;[DI]=3^.5*x=temp
MOV esi,offset cFLD1 ;[SI]=1
CALL MoveCodeSItoDataSI
CALL SUDRQQ ;[DI]=3^.5*x-1
POP esi ;get NOS
PUSH edi ;save ptr to 3^.5*x-1
MOV edi,esi ;DI gets NOS
MOV esi,offset RT3 ;[SI]=3^.5
CALL MoveCodeSItoDataSI
MOV [RESULT],edi ;result=[DI]
CALL ADDRQQ ;[DI]=x+3^.5=NOS
POP esi ;[SI]=3^.5*x-1
CALL DRDRQQ ;[DI]=(3^.5*x-1)/(x+3^.5)=NOS
MOV AL,1 ;flag set
pub ATNREDUCED
PUSH eax ;save flag
MOV esi,edi ;[SI]=reduced x=NOS
MOV ebx,offset ATNRAT ;[BX]=rational function
CALL FRAT2X ;[DI]=numerator=NOS,
; [SI]=denominator=temp
MOV [RESULT],edi ;result=[DI]
CALL DIDRQQ ;[DI]=arctan(reduced x)=NOS
POP eax ;get flag
OR AL,AL ;if flag=0
JZ short ATNCOMPLETE ; bypass adjust
MOV esi,offset PIBY6 ;[SI]=pi/6
CALL MoveCodeSItoDataSI
CALL ADDRQQ ;[DI]=arctan(x)=NOS
pub ATNCOMPLETE
RET
;-------------------------------------------------------------------------------
pub eF2XM1
MOV esi,[CURstk]
CALL $F2XM1
RET
;---------------------------------------------------
; !
; 8087 emulator exponential !
; !
;---------------------------------------------------
; When 0<=x={TOS=[SI]}<=.5 then $F2XM1 performs {TOS=[SI]} <--
; 2^{TOS=[SI]}-1. All registers except SI are destroyed.
pub $F2XM1
MOV ebx,offset EXPRAT ;[BX]=rational function
CALL FRAT2X ;[DI]=numerator=TOS
PUSH edi ;save numerator=TOS
XCHG esi,edi ;[SI]=numerator, [DI]=denominator
MOV [RESULT],edi ;result=[DI]
CALL SUDRQQ ;[DI]=denominator-numerator
MOV esi,edi ;[SI]=denominator-numerator
POP edi ;[DI]=numerator=TOS
MOV [RESULT],edi ;result=[DI]
CALL DIDRQQ ;[DI]=(2^x-1)/2
INC word ptr [edi+Expon] ;[DI]=2^x-1
MOV esi,edi ;[SI]=2^x-1
RET
;-------------------------------------------------------------------------------
pub eFYL2X
MOV edi,[CURstk]
MOV esi,edi
MOV AX,Flag[esi]
SUB edi,Reg87Len
pub CALLFYL2X
CALL $FYL2X
MOV esi,[CURstk]
POPST
RET
;---------------------------------------------------
; !
; 8087 emulator multiple of logarithm !
; !
;---------------------------------------------------
; When -infinity<y={NOS=[DI]}<infinity and 0<x={TOS=[SI]}<infinity
; then $FYL2X performs {NOS=[DI]} <-- {NOS=[DI]}*log2({TOS=[SI]}).
; TOS is left unaltered, all registers except DI are destroyed.
pub $FYL2X
PUSH esi ;save ptr to x=TOS
MOV esi,edi ;[SI]=y=NOS
MOV edi,offset TEMP2 ;[DI]=temp2
CALL MOVRQQ ;[DI]=y=temp2
MOV edi,esi ;[DI]=y=NOS
POP esi ;[SI]=x=TOS
PUSH edi ;save ptr to y=NOS
MOV edi,offset TEMP3 ;[DI]=temp3
CALL MOVRQQ ;[DI]=x=temp3
MOV BX,[edi+Expon] ;BX=exponent of x
MOV word ptr [edi+Expon],0 ;set exponent of x to 0
MOV esi,offset RT2 ;[SI]=2^.5
CALL COMPcsSIDI ;if reduced x < 2^.5
JA short LOGREDUCED ; then bypass normalization
DEC word ptr [edi+Expon] ;otherwise make x < 2^.5
INC BX ;adjust exponent
pub LOGREDUCED
PUSH ebx ;save exponent of x
MOV esi,offset cFLD1 ;[SI]=1
CALL MoveCodeSItoDataSI
MOV [RESULT],edi ;result=[DI]
CALL SUDRQQ ;[DI]=(reduced x)-1=temp3
MOV esi,edi ;[SI]=(reduced x)-1=temp3
POP ebx ;get exponent of x
POP edi ;[DI]=y=NOS
PUSH ebx ;save exponent of x
CALL $FYL2XP1 ;[DI]=y*log2(reduced x)=NOS
POP ebx ;get exponent of x
XOR AX,AX ;zero AX
OR BX,BX ;if exponent is zero
JZ short LOGRETURN ; then done
MOV DX,AX ;make sign +
JNS short EXPPOSITIVE ;if + then bypass adjust
MOV DL,Sign ;make sign -
NEG BX ;negate exponent
pub EXPPOSITIVE
MOV CX,16 ;initialize bit count
pub LOGLOOP
DEC CX ;decrement shift count
SHL BX,1 ;and shift exponent of x left
JNC LOGLOOP ;until carry detected
PUSH edi ;save ptr to y*log2(reduced x)=NOS
RCR BX,1 ;normalize exponent of x
MOV edi,offset TEMP3 ;[DI]=temp3
STOS word ptr es:[edi]
STOS word ptr es:[edi]
STOS word ptr es:[edi]
MOV AX,BX
STOS word ptr es:[edi]
MOV AX,CX
STOS word ptr es:[edi]
MOV AX,DX
STOS word ptr es:[edi] ;store exponent of x in temp3
MOV edi,offset TEMP2 ;[DI]=y=temp2
MOV esi,offset TEMP3 ;[SI]=exponent of x=temp3
MOV [RESULT],edi ;result=[DI]
CALL MUDRQQ ;[DI]=y*exponent of x=temp2
MOV esi,edi ;[SI]=y*exponent of x=temp2
POP edi ;[DI]=y*log2(reduced x)=NOS
MOV [RESULT],edi ;result=[DI]
CALL ADDRQQ ;[DI]=y*log2(x)=NOS
pub LOGRETURN
RET
;-------------------------------------------------------------------------------
pub eFYL2XP1
MOV edi,[CURstk]
MOV esi,edi
MOV AX,Flag[esi]
SUB edi,Reg87Len
pub CALLFYL2XP1
CALL $FYL2XP1
MOV esi,[CURstk]
POPST
RET
;---------------------------------------------------
; !
; 8087 emulator add 1 multiple of logarithm !
; !
;---------------------------------------------------
; When -infinity<y={[DI]=NOS}<infinity and
; 2^-.5-1<=x={[SI]=TOS}<2^.5-1 then $FYL2XP1 performs {NOS=[DI]}
; <-- {NOS=[DI]}*log2({TOS=[SI]}+1). TOS is left unaltered, all
; registers except DI are destroyed.
pub $FYL2XP1
PUSH edi ;save ptr to y
MOV edi,offset TEMP1 ;[DI]=temp
CALL MOVRQQ ;[DI]=x=temp
PUSH esi ;save ptr to x
MOV esi,offset TWO ;[SI]=2
CALL MoveCodeSItoDataSI
MOV [RESULT],edi ;result=[DI]
CALL ADDRQQ ;[DI]=x+2=temp
POP esi ;[SI]=x=TOS
CALL DRDRQQ ;[DI]=x/(x+2)=temp
INC word ptr [edi+Expon] ;[DI]=2x/(x+2)=temp
MOV esi,edi ;[SI]=2x/(x+2)=temp
MOV ebx,offset LOGRAT ;[BX]=rational function
CALL FRAT2X ;[DI]=numerator=temp,
; [SI]=denominator=temp
MOV [RESULT],edi ;result=[DI]
CALL DIDRQQ ;[DI]=log2(x+1)=temp
MOV esi,edi ;[SI]=log2(x+1)=temp
POP edi ;get ptr to y=NOS
MOV [RESULT],edi ;result=[DI]
CALL MUDRQQ ;[DI]=y*log2(x+1)=NOS
RET
ProfEnd FTRAN