trig387.asm

来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 532 行 · 第 1/2 页

ASM
532
字号
;*****************************************************************************
;*
;*                            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!
;*
;*****************************************************************************


;
;   interface to floating point library for trig functions
;
.387
include mdef.inc
include struct.inc
include math387.inc

        extern_chipbug
        xref            __8087  ; indicate that NDP instructions are present

        modstart        trig387

        ;datasegment
        ;enddata

        xdefp   "C",sin         ; calc sin(fac1)
        xdefp   "C",cos         ; calc cos(fac1)
        xdefp   "C",tan         ; calc tan(fac1)

ifndef __386__
if _MODEL and _BIG_CODE
argx    equ     6
else
argx    equ     4
endif
status  equ     -4
endif                           ; __386__

;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<>                                                                     <>
;<>     SIN and COS functions for 8087                                  <>
;<>                                                                     <>
;<>                                                                     <>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
;<>                                                                     <>
;<>     sin8087 - compute sin of st(0)                                  <>
;<>                                                                     <>
;<>     let st(0) be theta. must reduce theta into range 0 to pi/4      <>
;<>     and determine which octant theta is in. if theta is in an odd   <>
;<>     octant then define beta to be - (alpha - pi/4), and use beta.   <>
;<>     fptan instruction computes Y and X which can be used to         <>
;<>     compute either sin or cos.                                      <>
;<>     we use the octant number to determine which answer is required. <>
;<>                                                                     <>
;<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>

ifdef __386__
    datasegment
endif
TwoPi   db      035h,0c2h,068h,021h,0a2h,0dah,00fh,0c9h,001h,040h
ifndef __FPI87__
piby2   db      035h,0c2h,068h,021h,0a2h,0dah,00fh,0c9h,0ffh,03fh
piby4   db      035h,0c2h,068h,021h,0a2h,0dah,00fh,0c9h,0feh,03fh
;;;piby2   dt      1.57079632679489661923
;;;piby4   dt      0.78539816339744830961

ifdef __386__
octtab  dd      oct0            ; sin(alpha)
        dd      oct1            ; cos(beta)
        dd      oct2            ; cos(alpha)
        dd      oct3            ; sin(beta)
        dd      oct4            ; - sin(alpha)
        dd      oct5            ; - cos(beta)
        dd      oct6            ; - cos(alpha)
        dd      oct7            ; - sin(beta)
else
octtab  dw      oct0            ; sin(alpha)
        dw      oct1            ; cos(beta)
        dw      oct2            ; cos(alpha)
        dw      oct3            ; sin(beta)
        dw      oct4            ; - sin(alpha)
        dw      oct5            ; - cos(beta)
        dw      oct6            ; - cos(alpha)
        dw      oct7            ; - sin(beta)
endif                           ; __386__
endif                           ; __FPI87__
ifdef __386__
    enddata
endif


        public  IF@COS
        public  IF@DCOS
        defp    IF@DCOS
        defp    IF@COS
ifndef __FPI87__
        chk387
        mov     AL,2            ; cos(x) = sin(x+pi/2)
        jne     Sin8087         ;   which is 2 octants over
endif                           ; __FPI87__
        _loop                   ; loop
          fcos                  ; - calculate cos
          call  chk_C2          ; - see if argument was in range
        _until  c               ; until done
        ret                     ; return
        endproc IF@COS
        endproc IF@DCOS


        public  IF@SIN
        public  IF@DSIN
        defp    IF@DSIN
        defp    IF@SIN
ifdef __FPI87__
        _loop                   ; loop
          fsin                  ; - calculate sin
          call  chk_C2          ; - see if argument was in range
        _until  c               ; until done
        ret                     ; return
else
        chk387                  ; check for 387
        mov     AL,0            ; no octant adjustment required
        _if     e               ; if 387
          _loop                 ; - loop
            fsin                ; - - calculate sin
            call  chk_C2        ; - - see if argument was in range
          _until  c             ; - until done
          ret                   ; - return
        _endif                  ; endif

Sin8087:
ifdef __386__
        push    EBX             ; save EBX
        sub     EBX,EBX         ; zero whole register
        mov     BL,AL           ; save octant adjustment
        fld     tbyte ptr piby4 ; load pi/4
        fxch    st(1)           ; exchange
        ftst                    ; get sign of argument
        fstsw   AX              ; . . .
        sahf                    ; get flags
        _if     b               ; if number is negative
          fchs                  ; - make argument positive
          cmp   BL,0            ; - if computing SIN function
          _if   e               ; - then
            mov   BL,4          ; - - set octant adjustment
          _endif                ; - endif
        _endif                  ; endif
        _loop                   ; loop (reduce argument to mod pi/4)
          fprem                 ; - calculate partial remainder
          fstsw AX              ; - store status word
          test  AX,0400h        ; - check C2
        _until  e               ; until C2 is clear
        mov     AL,0            ; set octant # to 0
        test    AH,02h          ; if C1 is on
        _if     ne              ; then
          or    AL,1            ; - set low order bit of octant
;         compute beta = - ( alpha - pi/4 ); and use beta as the angle

          fsub  st(0),st(1)     ; - subtract pi/4 from the angle
          fchs                  ; - and change the sign
        _endif                  ; endif
        test    AH,40h          ; if C3 is on
        _if     ne              ; then
          or    AL,2            ; - set next bit in octant number
        _endif                  ; endif
        test    AH,01h          ; if C0 is on
        _if     ne              ; then
          add   AL,04h          ; - set next bit in octant #
        _endif                  ; endif

;       AL now has the octant number

        fstp    st(1)           ; copy angle up over pi/4
        fptan                   ; st(0) := X,  st(1) := Y
        fld     st(0)           ; duplicate X
        fmul    st(0),st(0)     ; calculate X*X
        fld     st(2)           ; duplicate Y
        fmul    st(0),st(0)     ; calculate Y*Y
        faddp   st(1),st(0)     ; calculate X*X + Y*Y
        fsqrt                   ; R = sqrt(X*X + Y*Y)
        add     BL,AL           ; add in octant adjustment
        and     BL,7            ; reduce to mod 8
        lea     EBX,octtab[EBX*4] ; point to table entry
        mov     EAX,cs:[EBX]    ; get address of routine from table
        pop     EBX             ; restore EBX
        jmp     EAX             ; jump to appropriate routine
else
        push    BP              ; save BP
        mov     BP,SP           ; get access to locals
        push    BX              ; save BX
        mov     BX,AX           ; save octant adjustment
        push    AX              ; allocate status word
        fld     tbyte ptr piby4 ; load pi/4
        fxch    st(1)           ; exchange
        ftst                    ; get sign of argument
        fstsw   status[BP]      ; . . .
        fwait                   ; . . .
        mov     AX,status[BP]   ; . . .
        sahf                    ; get flags
        _if     b               ; if number is negative
          fchs                  ; - make argument positive
          cmp   BL,0            ; - if computing SIN function
          _if   e               ; - then
            mov   BL,4          ; - - set octant adjustment
          _endif                ; - endif
        _endif                  ; endif
        _loop                   ; loop (reduce argument to mod pi/4)
          fprem                 ; - calculate partial remainder
          fstsw status[BP]      ; - store status word
          fwait                 ; - wait for store to complete
          mov   AX,status[BP]   ; - get status
          test  AX,0400h        ; - check C2
        _until  e               ; until C2 is clear
        mov     AL,0            ; set octant # to 0
        test    AH,02h          ; if C1 is on
        _if     ne              ; then
          or    AL,1            ; - set low order bit of octant
;         compute beta = - ( alpha - pi/4 ); and use beta as the angle

          fsub  st(0),st(1)     ; - subtract pi/4 from the angle
          fchs                  ; - and change the sign
        _endif                  ; endif
        test    AH,40h          ; if C3 is on
        _if     ne              ; then
          or    AL,2            ; - set next bit in octant number
        _endif                  ; endif
        test    AH,01h          ; if C0 is on
        _if     ne              ; then
          add   AL,04h          ; - set next bit in octant #
        _endif                  ; endif

;       AL now has the octant number

        fstp    st(1)           ; copy angle up over pi/4
        fptan                   ; st(0) := X,  st(1) := Y
        fld     st(0)           ; duplicate X
        fmul    st(0),st(0)     ; calculate X*X
        fld     st(2)           ; duplicate Y
        fmul    st(0),st(0)     ; calculate Y*Y
        faddp   st(1),st(0)     ; calculate X*X + Y*Y
        fsqrt                   ; R = sqrt(X*X + Y*Y)
        add     BL,AL           ; add in octant adjustment
        and     BL,7            ; reduce to mod 8

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?