;*****************************************************************************
;*
;*                            Open Watcom Project
;*
;*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;*  ========================================================================
;*
;*    This file contains Original Code and/or Modifications of Original
;*    Code as defined in and that are subject to the Sybase Open Watcom
;*    Public License version 1.0 (the 'License'). You may not use this file
;*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;*    provided with the Original Code and Modifications, and is also
;*    available at www.sybase.com/developer/opensource.
;*
;*    The Original Code and all software distributed under the License are
;*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;*    NON-INFRINGEMENT. Please see the License for the specific language
;*    governing rights and limitations under the License.
;*
;*  ========================================================================
;*
;* Description:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
;*               DESCRIBE IT HERE!
;*
;*****************************************************************************


; static char sccs_id[] = "@(#)fptan32.asm      1.4  12/20/94  16:51:51";
;
; This code is being published by Intel to users of the Pentium(tm)
; processor.  Recipients are authorized to copy, modify, compile, use and
; distribute the code.
;
; Intel makes no warranty of any kind with regard to this code, including
; but not limited to, implied warranties or merchantability and fitness for
; a particular purpose. Intel assumes no responsibility for any errors that
; may appear in this code.
;
; No patent licenses are granted, express or implied.
;
;
;  The following code is a PRELIMINARY IMPLEMENTATION of a
;  software patch for the floating point divide instructions.
;
;
include mdef.inc

.386
.387

PATCH_CW        EQU     00ch
PREV_CW         EQU     010h
COSINE          EQU     0               ; These two are overlaid because they
ANGLE           EQU     0               ; are not live at the same time.


STACK_SIZE      EQU     014h

ONESMASK        EQU     0e000000h


DATA32  SEGMENT DWORD USE32 PUBLIC 'DATA'

fdiv_risk_table DB      0, 1, 0, 0, 4, 0, 0, 7, 0, 0, 10, 0, 0, 13, 0, 0
fdiv_scale      DD      03f700000h              ; 0.9375
one_shl_63      DD      05f000000h

DATA32  ENDS

DGROUP GROUP DATA32

_TEXT  SEGMENT   DWORD USE32 PUBLIC 'CODE'


        assume cs:_TEXT, ds:DGROUP, es:DGROUP, ss:nothing
        public  __fptan_chk

;
;  PRELIMINARY VERSION for register-register divides.
;


        defpe   __fptan_chk

        push    eax
        sub     esp, STACK_SIZE
        fstp    tbyte ptr [esp+ANGLE]
        mov     eax, [esp+ANGLE+8]
        and     eax, 07fffh
        jz      use_hardware            ; denormals, ...
        cmp     eax, 07fffh
        je      use_hardware            ; NaNs, infinities, ...
        mov     eax, [esp+ANGLE+4]
        add     eax, eax
        jnc     use_hardware            ; unnormals (explicit 1 missing)
        fld     tbyte ptr [esp+ANGLE]

;
; Check for proper parameter range ( |<angle>| < 2^63)
;
        fabs
        fcomp   one_shl_63
        fstsw  ax
        sahf
        jae     use_hardware

        fld     tbyte ptr [esp+ANGLE]
        fsincos
        fstp    tbyte ptr [esp+COSINE]
        fld     tbyte ptr [esp+COSINE]  ; load the denominator (cos(x))
        mov     eax, [esp+COSINE+4]     ; get mantissa bits 32-64
        add     eax,eax                 ; shift the one's bit onto carry
        xor     eax, ONESMASK           ; invert the bits that must be ones
        test    eax, ONESMASK           ; and make sure they are all ones
        jz      scale_if_needed         ; if all are one scale numbers
        fdivp   st(1), st               ; use of hardware is OK.
        fld1                            ; push 1.0 onto FPU stack
        add     esp, STACK_SIZE
        pop     eax
        ret

scale_if_needed:
        shr     eax, 28                 ; keep first 4 bits after point
        cmp     fdiv_risk_table[eax], ah        ; check for (1,4,7,a,d)
        jnz     divide_scaled           ; are in potential problem area
        fdivp   st(1), st               ; use of hardware is OK.
        fld1                            ; push 1.0 onto FPU stack
        add     esp, STACK_SIZE
        pop     eax
        ret

divide_scaled:
        fwait                           ; catch preceding exceptions
        fstcw   [esp+PREV_CW]           ; save caller's control word
        mov     eax, [esp+PREV_CW]
        or      eax, 033fh              ; mask exceptions, pc=80
        mov     [esp+PATCH_CW], eax
        fldcw   [esp+PATCH_CW]          ; mask exceptions & pc=80
        fmul    fdiv_scale              ; scale denominator by 15/16
        fxch
        fmul    fdiv_scale              ; scale numerator by 15/16
        fxch

; This assures correctly rounded result if pc=64 as well

        fldcw   [esp+PREV_CW]           ; restore caller's control word
        fdivp   st(1), st               ; use of hardware is OK.
        fld1                            ; push 1.0 onto FPU stack
        add     esp, STACK_SIZE
        pop     eax
        ret

use_hardware:
        fld     tbyte ptr [esp+ANGLE]
        fptan
        add     esp, STACK_SIZE
        pop     eax
        ret
__fptan_chk       ENDP

_TEXT  ENDS
        end
