	page	,132
	title	87disp - common transcendental dispatch routine
;*** 
;87disp.asm - common transcendental dispatch routine (80x87/emulator version)
;
;   Copyright (c) 1984-88, Microsoft Corporation
;
;Purpose:
;   Common transcendental dispatch routine (80x87/emulator version)
;
;Revision History:
;   07-07-84  GFW initial version
;   11-20-85  GFW mask overflow/underflow/precision exceptions;
;		  fixed affine/projective infinity confusion
;   09-12-86  BCM added _Flanguage to distinguish languages
;   10-21-86  BCM use _cpower rather than _Flanguage to
;		  distinguish C and FORTRAN exponentiation semantics
;   06-11-87  GFW faster dispatch code - all in-line
;   10-26-87  BCM minor changes for new cmacros.inc
;   04-25-88  WAJ _cpower is now on stack for MTHREAD
;   08-24-88  WAJ 386 version
;   02-01-92  GDP ported to NT
;
;*******************************************************************************

.xlist
	include cruntime.inc
	include mrt386.inc
	include elem87.inc
.list

	.data

globalT _indefinite,  0FFFFC000000000000000R
globalT _piby2,       03FFFC90FDAA22168C235R
staticQ One,	      03FF0000000000000R


ifndef	MTHREAD 	; by default assume C pow() semantics
globalB _cpower, 1	; if zero, assume FORTRAN (or other) exponentiation
endif	;MTHREAD	;    semantics



labelB	XAMtoTagTab
			    ; C2 C1 C0 C3   Meaning	   Meaning  Tag   0
	db	2 * ISIZE   ;  0  0  0	0  +Unnormal  =>   NAN	     10   0
	db	1 * ISIZE   ;  0  0  0	1  +Zero      =>   Zero      01   0
	db	2 * ISIZE   ;  0  0  1	0  +NAN       =>   NAN	     10   0
	db	2 * ISIZE   ;  0  0  1	1   Empty     =>   NAN	     10   0
	db	2 * ISIZE   ;  0  1  0	0  -Unnormal  =>   NAN	     10   0
	db	1 * ISIZE   ;  0  1  0	1  -Zero      =>   Zero      01   0
	db	2 * ISIZE   ;  0  1  1	0  -NAN       =>   NAN	     10   0
	db	2 * ISIZE   ;  0  1  1	1   Empty     =>   NAN	     10   0
	db	0 * ISIZE   ;  1  0  0	0  +Normal    =>   Valid     00   0
	db	1 * ISIZE   ;  1  0  0	1  +Denormal  =>   Zero      01   0
	db	3 * ISIZE   ;  1  0  1	0  +Infinity  =>   Infinity  11   0
	db	2 * ISIZE   ;  1  0  1	1   Empty     =>   NAN	     10   0
	db	0 * ISIZE   ;  1  1  0	0  -Normal    =>   Valid     00   0
	db	1 * ISIZE   ;  1  1  0	1  -Denormal  =>   Zero      01   0
	db	3 * ISIZE   ;  1  1  1	0  -Infinity  =>   Infinity  11   0
	db	2 * ISIZE   ;  1  1  1	1   Empty     =>   NAN	     10   0


	CODESEG

xamTOS	macro
	cmp	[rdx].fnumber, OP_SQRT	; check for sqrt
	JSNE	cwdefault
	mov	bx, word ptr (DSF.savCntrl)
	or	bh, 2			; set precision control to 53 bits
	and	bh, 0feh
	mov	bl, 03fh		; mask exceptions
	jmp	setcw
lab cwdefault
	mov	bx, 133fh		; default cw
lab setcw
	mov	DSF.setCntrl, bx	; set new control word
	fldcw	DSF.setCntrl		; load new control word
	mov	rbx, dataoffset XAMtoTagTab	; Prepare for XLAT
	fxam
	mov	DSF.Function, rdx	; save function jmp table address
	fstsw	DSF.StatusWord
	mov	DSF.ErrorType, 0	; clear error code
	endm

comdisp macro
	CBI
	and	rcx, 0404h		; clear all but signs from CX
	mov	rbx, rdx
	add	rbx, rax
	add	rbx, size funtab	; skip over name, error vals, etc.
	jmp	[rbx]			; jmp to function
	endm

; Will dispatch  to  the  special  case routines for the single argument
; transcendental functions.  It assumes on  entry  that  the  8087 stack
; has the  argument  on  the  top  of its stack and that DX has been set
; to the address of the dispatch table (which should be in  Tag  order).
; This routine	will  FXAM  the top of the 8087 stack, generate Tag info
; from the condition code, and jump to the corresponding dispatch  table
; entry.  In the process of creating the offset for the XLAT instruction
; bit 2 of CL will be loaded with  the sign of the argument.  DI may not
; be used in any computations.

_trandisp1  proc    near

	xamTOS				; setup control word and check TOS

	fwait
	mov	cl, CondCode
	shl	cl, 1
	sar	cl, 1
	rol	cl, 1
	mov	al, cl
	and	al, 0fh
	xlat

	comdisp

_trandisp1  endp


; Will dispatch to the special case routines  for  the	double	argument
; transcendental functions.   It  assumes on entry that the 8087 has arg1
; next to the top and arg2 on top of the 8087  stack  and  that  DX  has
; been set  to	the  address  of  the dispatch table (which should be in
; Tag-arg1,Tag-arg2  order).   This  routine  will  FXAM  the  top   two
; registers of	the  8087  stack,generate  Tag info from the condition
; codes, and jump to the corresponding	dispatch  table entry.	 In  the
; process of  creating	the  offsets  for  the	XLAT statements bit 2 of
; CH and bit 2 of CL will be loaded with  the  signs  of  the  arguments
; next to the  top and on top, respectively, of  the 8087 stack.  DI may
; not be used in any computations.

_trandisp2  proc    near

	xamTOS				; setup control word and check TOS

	fxch
	mov	cl, CondCode
	fxam
	fstsw	DSF.StatusWord
	fxch
	mov	ch, CondCode
	shl	ch, 1
	sar	ch, 1
	rol	ch, 1
	mov	al, ch
	and	al, 0fh
	xlat
	mov	ah, al
	shl	cl, 1
	sar	cl, 1
	rol	cl, 1
	mov	al, cl
	and	al, 0fh
	xlat
	shl	ah, 1
	shl	ah, 1
	or	al, ah

	comdisp

_trandisp2  endp



page
;----------------------------------------------------------
;
;	SPECIAL CASE RETURN FUNCTIONS
;
;----------------------------------------------------------
;
;	INPUTS - The signs of the last, second to last
;		 arguments are in CH, CL respectively.
;
;	OUTPUT - The result is the stack top.
;
;----------------------------------------------------------

labelNP _rttospopde, PUBLIC
	call	setDOMAIN

labelNP _rttospop, PUBLIC
	fxch				; remove ST(1)

labelNP _rtnospop, PUBLIC
	fstp	st(0)			; remove ST(0)

labelNP _rttosnpop, PUBLIC
	ret				; return TOS

labelNP _rtnospopde, PUBLIC
	call	setDOMAIN
	jmp	_rtnospop


;----------------------------------------------------------

labelNP _rtzeropop, PUBLIC
	fstp	st(0)			; remove ST(0)

labelNP _rtzeronpop, PUBLIC
	fstp	st(0)			; remove ST(0)
	fldz				; push 0.0 onto stack
	ret

;----------------------------------------------------------

labelNP _rtonepop, PUBLIC
	fstp	st(0)			; remove ST(0)

labelNP _rtonenpop, PUBLIC
	fstp	st(0)			; remove ST(0)
	fld1				; push 1.0 onto stack
	ret

;----------------------------------------------------------

isQNAN macro
	fstp	DSF.Fac 		; use ten byte storage
	fld	DSF.Fac
	test	byte ptr [DSF.Fac+7], 40h ; Test for QNaN or SNaN
	endm


labelNP _tosnan1, PUBLIC		; ST(0) is a NaN
	isQNAN
	JSZ	_tossnan1
	mov	DSF.Errortype, DOMAIN_QNAN
	ret
lab _tossnan1
	mov	DSF.Errortype, DOMAIN
	fadd	[One]			; Convert SNaN to QNaN
	ret

labelNP _nosnan2, PUBLIC		; ST(1) is a NaN
	fxch
labelNP _tosnan2, PUBLIC		; ST(0) is a NaN
	isQNAN
	JSZ	_tossnan2
	mov	DSF.Errortype, DOMAIN_QNAN
	jmp	_tosnan2ret
lab _tossnan2
	mov	DSF.Errortype, DOMAIN
lab _tosnan2ret
	fadd				; Propagate NaN and pop
	ret

labelNP _nan2, PUBLIC
	isQNAN
	JSZ	_snan2
	fxch
	isQNAN
	JSZ	_snan2
	mov	DSF.Errortype, DOMAIN_QNAN
	jmp	_nan2ret
lab _snan2
	mov	DSF.Errortype, DOMAIN
lab _nan2ret
	fadd				; Propagate NaN and pop
	ret




;----------------------------------------------------------

labelNP _rtindfpop, PUBLIC
	fstp	st(0)			; remove ST(0)

labelNP _rtindfnpop, PUBLIC
	fstp	st(0)			; remove ST(0)
	fld	[_indefinite]		; push real indefinite onto stack
	cmp	DSF.ErrorType, 0	; if error set
	JSG	retj			;   must be SING, don't set DOMAIN

labelNP _rttosnpopde, PUBLIC
lab setDOMAIN
	mov	DSF.ErrorType, DOMAIN
lab retj
	or	cl, cl			; test sign in cl
	ret


;----------------------------------------------------------

labelNP _rtchsifneg, PUBLIC
	or	cl, cl			; if arg is negative
	JSZ	chsifnegret		;    negate top of stack
	fchs
lab chsifnegret
	ret

end
