;      SCCSID = @(#)emsincos.asm	       13.5 90/03/27
	page	,132
	subttl	emsincos - fsin, fcos and fsincos
;***
;emulator.asm -  80387 emulator
;
;	 IBM/Microsoft Confidential
;
;	 Copyright (c) IBM Corporation 1987, 1989
;	 Copyright (c) Microsoft Corporation 1987, 1989
;
;	 All Rights Reserved
;
;Purpose:
;	Code for fsin, fcos and fsincos
;
;Revision History:
;	See emulator.hst
;
;*******************************************************************************

lab eFsincosStackOver
	or	SEL[CURerr], StackFlag or Invalid
	test	SEL[CWmask], Invalid
	JSZ	eFsincosStackOverRet

	mov	SEL[rsi.lMan0], 0			; st(0) = Ind
	mov	SEL[rsi.lMan1], 0c0000000h
	mov	SEL[rsi.wExp], 7fffh - IexpBias
	mov	SEL[rsi.bTag], bTAG_NAN
	mov	SEL[rsi.bFlags], bSign

	mov	SEL[rdi.lMan0], 0			; st(-1) = Ind
	mov	SEL[rdi.lMan1], 0c0000000h
	mov	SEL[rdi.wExp], 7fffh - IexpBias
	mov	SEL[rdi.bTag], bTAG_NAN
	mov	SEL[rdi.bFlags], bSign

	mov	SEL[CURstk], rdi		; push stack
lab eFsincosStackOverRet
	ret


lab eFSINCOS
	mov	esi, SEL[CURStk]    ; esi = st(0)
	mov	edi, esi
	PrevStackElem	 edi	    ; edi = st(-1)

	cmp	SEL[edi.bTag], bTAG_EMPTY
	JSNE	eFsincosStackOver

	cmp	SEL[esi.bTag], bTAG_NAN
	JSNE	eFsincosNotSNaN

	test	SEL[esi.bMan7], 40h
	JSNZ	eFsincosNotSNaN

	test	SEL[CWmask], Invalid
	JSNZ	eFsincosNotSNaN

	or	SEL[CURerr], Invalid
	ret

lab eFsincosNotSNaN
ifdef NT386
        push    eax
        mov     eax, dword ptr SEL[rsi]
        mov     dword ptr SEL[rdi], eax
        mov     eax, dword ptr SEL[rsi+4]
        mov     dword ptr SEL[rdi+4], eax
        mov     eax, dword ptr SEL[rsi+8]
        mov     dword ptr SEL[rdi+8], eax
        add     rsi, Reg87Len
        add     rdi, Reg87Len
        pop     eax
else
        push	ds		    ; Copy current stack into st(-1)
	pop	es
	movsd
	movsd
	movsd
endif

	call	eFSIN
	PUSHST
	call	eFCOS

	ret


lab eFcosSpecial
	mov	esp, ebp
	pop	ebp

	mov	SEL[RESULT], esi

	mov	al, SEL[esi.bTag]
	cmp	al, bTAG_ZERO
	JSNE	eFcosInf

lab eFcosRetOne
	mov	SEL[esi.lMan0], 0
	mov	SEL[esi.lMan1], 080000000h
	mov	SEL[esi.wExp], 3fffh - IexpBias
	mov	SEL[esi.bFlags], 0
	mov	SEL[esi.bTag], bTAG_VALID
	ret

lab eFcosInf
	cmp	al, bTAG_INF
	JE	RetIndInv

lab eFcosNaN
	jmp	OneArgOpNaNRet


cProc  eFCOS,<PLM,PUBLIC>,<>

	localT	temp
	localB	SignFlag

cBegin
	mov	esi, SEL[CURstk]

	cmp	SEL[esi.bTag], bTAG_VALID
	jne	eFcosSpecial

	or	SEL[CURerr], Precision

	and	SEL[esi].bFlags, not bSign ; st(0) = fabs( st(0) );

	call	SinCosReduce		; Set ah to condition code.

	add	SEL[esi].wExp, IExpBias

	push	SEL[esi].wExp
	push	SEL[esi].lMan1
	push	SEL[esi].lMan0
	lea	ecx, [temp]
	push	ecx

	mov	bl, ah			; if octant 2, 3, 4, or 5 then final
	and	bl, bOCT2 or bOCT4	; result must be negative
	mov	[SignFlag], bl

	test	ah, bOCT1 or bOCT2	; if octant is 1, 2, 5, 6 then must
	jpo	CosCallSin		; do sin()

	call	__FASTLDCOS
	jmp	short CosCopyRes

CosCallSin:
	call	__FASTLDSIN

CosCopyRes:
	mov	eax, dword ptr [temp]
	mov	SEL[esi].lMan0, eax
	mov	eax, dword ptr [temp+4]
	mov	SEL[esi].lMan1, eax

	mov	ax,  word ptr [temp+8]
	sub	ax, IExpBias
	mov	SEL[esi].wExp, ax

	cmp	[SignFlag], 0
	jpe	CosDone

	or	SEL[esi].bFlags, bSign	; Make result negative.
CosDone:

cEnd





lab eFsinSpecial
	mov	esp, ebp
	pop	ebp

	mov	al, SEL[esi.bTag]
	cmp	al, bTAG_ZERO
	JSNE	eFsinInf

lab eFsinZero
	ret

lab eFsinInf
	cmp	al, bTAG_INF
	JE	RetIndInv

lab eFsinNaN
	jmp	OneArgOpNaNRet


cProc  eFSIN,<PLM,PUBLIC>,<>

	localT	temp
	localB	SignFlag

cBegin
	mov	esi, SEL[CURstk]

	cmp	SEL[esi.bTag], bTAG_VALID
	jne	eFsinSpecial

	or	SEL[CURerr], Precision

	mov	al, SEL[esi].bFlags
	and	SEL[esi].bFlags, not bSign

	shl	al, 1		    ; shift sign into carry.
	sbb	cl, cl		    ; set cl to -1 if argument is negative.

	push	ecx
	call	SinCosReduce	    ; Set ah to condition code.
	pop	ecx

	cmp	SEL[esi].bTag, bTAG_ZERO
	je	SinDone

	add	SEL[esi].wExp, IExpBias

	push	SEL[esi].wExp
	push	SEL[esi].lMan1
	push	SEL[esi].lMan0
	lea	ebx, [temp]
	push	ebx

	mov	bl, ah			; if octant 4, 5, 6 or 7 then final
	and	bl, bOCT4		; result must be negative

	neg	cl			; set cl to odd parity if arg was < 0.0
	xor	bl, cl			; set bl to odd parity if result must be negative

	mov	[SignFlag], bl

	test	ah, bOCT1 or bOCT2	; if octant is 1, 2, 5, 6 then must
	jpo	SinCallCos		; do cos()

	call	__FASTLDSIN
	jmp	short SinCopyResult

SinCallCos:
	call	__FASTLDCOS

SinCopyResult:
	mov	eax, dword ptr [temp]
	mov	SEL[esi].lMan0, eax
	mov	eax, dword ptr [temp+4]
	mov	SEL[esi].lMan1, eax

	mov	ax, word ptr [temp+8]
	sub	ax, IExpBias
	mov	SEL[esi].wExp, ax

	cmp	[SignFlag], 0
	jpe	SinDone

	or	SEL[esi].bFlags, bSign	; Make result negative.
SinDone:

cEnd



lab SinCosReduce
	mov	SEL[TEMP1.bFlags], 0		; TEMP1 = pi/4
	mov	SEL[TEMP1.bTag], bTAG_VALID
	mov	SEL[TEMP1.wExp], 3ffeh-IExpBias
	mov	SEL[TEMP1.wMan3], 0c90fh
	mov	SEL[TEMP1.wMan2], 0daa2h
	mov	SEL[TEMP1.wMan1],	2168h
	mov	SEL[TEMP1.wMan0], 0c235h

ifdef NT386
        mov     edi, TEMP1
else
	mov	edi, edataOFFSET TEMP1
endif

	push	esi
	call	InternFPREM		    ; rsi = st(0), rdi = st(0)
	pop	esi

	mov	ah, SEL[SWcc]

	test	ah, bOCT1		; check for even octant
	jz	EvenOct 		;   yes

	add	SEL[esi.wExp], IExpBias	; convert to true long double

	push	ds
	push	esi
	push	cs
	push	ecodeOFFSET PIBY4
	push	ds
	push	esi
	push	-1
	call	__FASTLDADD		; st(0) = pi/4 - st(0)
	mov	ah, SEL[SWcc]

	sub	SEL[esi.wExp], IExpBias	; convert to squirly emulator long double

EvenOct:
	retn



labelW	PIBY4
    dw	    0c235h, 02168h, 0daa2h, 0c90fh, 3ffeh

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; NOTE tedm:   NT masm can't handle floating-point constants  ;
;              because strtod and _strtold C-runtimes aren't  ;
;              there.  So the constants below must be pre-    ;
;              assembled and defined as a byte stream.        ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ifdef NOTDEF

staticT  FourByPI, +0.1273239544735162686151e+01

staticT  SinP0, +0.7853981633974483096141845e+00
staticT  SinP1, -0.8074551218828078152025820e-01
staticT  SinP2, +0.2490394570192716275251900e-02
staticT  SinP3, -0.3657620418214640005290000e-04
staticT  SinP4, +0.3133616889173253480000000e-06
staticT  SinP5, -0.1757247417617080600000000e-08
staticT  SinP6, +0.6948152035052200000000000e-11
staticT  SinP7, -0.2022531292930000000000000e-13

staticT  CosP0, +0.99999999999999999996415e+00
staticT  CosP1, -0.30842513753404245242414e+00
staticT  CosP2, +0.15854344243815410897540e-01
staticT  CosP3, -0.32599188692668755044000e-03
staticT  CosP4, +0.35908604458858195300000e-05
staticT  CosP5, -0.24611363826370050000000e-07
staticT  CosP6, +0.11500497024263000000000e-09
staticT  CosP7, -0.38577620372000000000000e-12

else

staticB  FourByPI, <02Ah,015h,044h,04Eh,06Eh,083h,0F9h,0A2h,0FFh,03Fh>

staticB  SinP0   , <035h,0C2h,068h,021h,0A2h,0DAh,00Fh,0C9h,0FEh,03Fh>
staticB  SinP1   , <0DAh,095h,0F2h,02Dh,031h,0E7h,05Dh,0A5h,0FBh,0BFh>
staticB  SinP2   , <0E9h,0C6h,056h,0ADh,03Bh,0E3h,035h,0A3h,0F6h,03Fh>
staticB  SinP3   , <0D5h,0E7h,05Dh,015h,073h,066h,069h,099h,0F0h,0BFh>
staticB  SinP4   , <0BCh,032h,069h,0E1h,042h,01Ah,03Ch,0A8h,0E9h,03Fh>
staticB  SinP5   , <021h,077h,004h,05Fh,0A1h,0A5h,083h,0F1h,0E1h,0BFh>
staticB  SinP6   , <0FCh,01Ah,0D1h,006h,0CCh,063h,077h,0F4h,0D9h,03Fh>
staticB  SinP7   , <04Ah,003h,086h,040h,07Ch,065h,02Ch,0B6h,0D1h,0BFh>

staticB  CosP0   , <0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FEh,03Fh>
staticB  CosP1   , <02Fh,0F2h,02Eh,0F2h,04Dh,0E6h,0E9h,09Dh,0FDh,0BFh>
staticB  CosP2   , <02Fh,04Eh,0D5h,0DAh,040h,0F8h,0E0h,081h,0F9h,03Fh>
staticB  CosP3   , <09Dh,0DEh,06Ah,0E4h,0F1h,0E3h,0E9h,0AAh,0F3h,0BFh>
staticB  CosP4   , <031h,01Eh,0F9h,081h,041h,083h,0FAh,0F0h,0ECh,03Fh>
staticB  CosP5   , <076h,0B1h,000h,0A4h,01Eh,0F6h,068h,0D3h,0E5h,0BFh>
staticB  CosP6   , <0D8h,005h,06Fh,08Ah,0EAh,00Ah,0E6h,0FCh,0DDh,03Fh>
staticB  CosP7   , <003h,0D5h,00Ah,0ACh,0CCh,035h,02Ch,0D9h,0D5h,0BFh>

endif

cProc __FASTLDSIN,<PLM,PUBLIC>,<isi,idi>

	parmT	x
	parmI	RetOff

	localT	x2
	localT	poly
	localI	count

cBegin

	lea	isi, [x]		    ; x = x * (4/PI)
	push	ss
	push	isi

	push	ss
	push	isi

	mov	iax, codeOFFSET FourByPI
	push	cs
	push	iax

	call	__FASTLDMULT


	lea	idi, [x2]		    ; x2 = x * x
	push	ss
	push	idi

	push	ss
	push	isi

	push	ss
	push	isi

	call	__FASTLDMULT

if 0
	push	ss
	pop	es
	lea	idi, [poly]
	mov	isi, codeOFFSET SinP7
	movsw
	movsw
	movsw
	movsw
	movsw
endif
	mov	eax, dword ptr [SinP7]	    ; poly = SinP7
	mov	dword ptr [poly], eax
	mov	eax, dword ptr [SinP7+4]
	mov	dword ptr [poly+4], eax
	mov	ax, word ptr [SinP7+8]
	mov	word ptr [poly+8], ax

	lea	isi, [poly]
	mov	idi, codeOFFSET SinP6

	mov	[count], 7

SinPolyLoop:
	push	ss
	push	isi		    ; poly = poly * x2

	push	ss
	push	isi

	lea	iax, [x2]
	push	ss
	push	iax

	call	__FASTLDMULT


	push	ss
	push	isi		    ; poly = poly + SinP[n]

	push	ss
	push	isi

	push	cs
	push	idi

	xor	iax, iax
	push	iax
	call	__FASTLDADD

	sub	idi, 10

	dec	[count]
	jnz	SinPolyLoop

	push	ss
	push	[RetOff]		; return x * poly

	lea	iax, [x]
	push	ss
	push	iax

	push	ss
	push	isi

	call	__FASTLDMULT

	mov	iax, [RetOff]
	mov	idx, ss
cEnd




cProc  __FASTLDCOS,<PLM,PUBLIC>,<isi,idi>

	parmT	x
	parmI	RetOff

	localT	x2
	localI	count

cBegin

	lea	isi, [x]		    ; x = x * (4/PI)
	push	ss
	push	isi

	push	ss
	push	isi

	mov	iax, codeOFFSET FourByPI
	push	cs
	push	iax

	call	__FASTLDMULT


	lea	idi, [x2]		    ; x2 = x * x
	push	ss
	push	idi

	push	ss
	push	isi

	push	ss
	push	isi

	call	__FASTLDMULT

if 0
	push	ss			    ; (return) = CosP7
	pop	es
	mov	idi, [RetOff]
	mov	isi, codeOFFSET CosP7
	movsw
	movsw
	movsw
	movsw
	movsw
endif
	mov	isi, [RetOff]
	mov	eax, dword ptr [CosP7]
	mov	dword ptr ss:[isi], eax
	mov	eax, dword ptr [CosP7+4]
	mov	dword ptr ss:[isi+4], eax
	mov	ax, word ptr [CosP7+8]
	mov	word ptr ss:[isi+8], ax

	mov	idi, codeOFFSET CosP6

	mov	[count], 7

CosPolyLoop:
	push	ss
	push	isi		    ; (return) = (return) * x2

	push	ss
	push	isi

	lea	iax, [x2]
	push	ss
	push	iax

	call	__FASTLDMULT


	push	ss
	push	isi		    ; (return) = (return) + SinP[n]

	push	ss
	push	isi

	push	cs
	push	idi

	xor	iax, iax
	push	iax

	call	__FASTLDADD


	sub	idi, 10

	dec	[count]
	jnz	CosPolyLoop

	mov	iax, isi
	mov	idx, ss
cEnd