fsmth386.asm

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

ASM
454
字号
;*****************************************************************************
;*
;*                            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:  REAL*4 math library.
;*
;*****************************************************************************


;
;       inputs: EAX - operand 1 (high word, low word resp. ) (op1)
;               EDX - operand 2                              (op2)
;
;       operations are performed as op1 (*) op2 where (*) is the selected
;       operation
;
;       output: EAX - result
;
;       F4Add, F4Sub - written  28-apr-84
;                    - modified by A.Kasapi 15-may-84
;                    - to:      Calculate sign of result
;                    -          Guard bit in addition for extra accuracy
;                               Add documentation
;       F4Mul        - written  16-may-84
;                    - by       Athos Kasapi
;       F4DIV        - written  may-84 by "
;
include mdef.inc
include struct.inc

.287
        modstart        fsmth386

        xref            __8087  ; indicate that NDP instructions are present

        xref    __fdiv_m32

        datasegment
        extrn   __real87 : byte         ; cstart
        extrn   __chipbug : byte
fsadd   dd      _chkadd
fsmul   dd      _chkmul
fsdiv   dd      _chkdiv
        enddata


        xref    F4DivZero       ; Fstatus
        xref    F4OverFlow      ; Fstatus
        xref    F4UnderFlow     ; Fstatus

        xdefp   __FSA           ; add real*4 to real*4
        xdefp   __FSS           ; subtract real*4 from real*4
        xdefp   __FSM           ; 4-byte real multiply
        xdefp   __FSD           ; 4-byte real divide


        defpe   __FSS
        or      EDX,EDX         ; if op2 is 0
        je      short ret_op1   ; then return operand 1
        xor     EDX,80000000h   ; flip the sign of op2 and add

        defpe   __FSA
        or      EDX,EDX         ; if op2 is 0
        je      short ret_op1   ; then return operand 1
        or      EAX,EAX         ; if op1 is 0
        _if     e               ; then
          mov   EAX,EDX         ; - return operand 2
ret_op1:  ret                   ; - return
        _endif                  ; endif
        jmp     fsadd

__FSA87:
        push    EBP             ; save EBP
        mov     EBP,ESP         ; get access to stack
        push    EAX             ; push operand 1
        fld     dword ptr -4[EBP]; load operand 1
        push    EDX             ; push operand 2
        fadd    dword ptr -8[EBP]; add operand 2 to operand 1
_ret87:
        fstp    dword ptr -4[EBP]; store result
        add     ESP,4           ; clean up stack
        fwait                   ; wait
        pop     EAX             ; load result into EAX
        cmp     EAX,80000000H   ; is result -0.0
        _if     e               ; if it is then
        xor     EAX,EAX         ; - make it positive
        _endif                  ; endif
        pop     EBP             ; restore EBP
        ret                     ; return

__FSAemu:
        push    ECX             ; save ECX
        push    EBX             ; save EBX
;<> Scheme for calculating sign of result:
;<>   The sign word is built and kept in CL
;<>   Bits 0 and 1 hold the sum of the sign bits
;<>       shifted out of op_1 and op_2
;<>   Bit 2 holds the sign of the larger operand. It is assumed to be
;<>       op_1 until op_2 is found larger

        sub     ECX,ECX         ; clear ECX
        _shl    EAX,1           ; get sign of op1
        _rcl    CL,1            ;
        mov     CH,CL           ;
        _shl    CL,1            ;
        _shl    CL,1            ;
        add     CL,CH           ;
        rol     EAX,8           ; get exponent of op1 into AL
        _shl    EDX,1           ; get sign of op2
        adc     CL,0            ; place in CL
        rol     EDX,8           ; get exponent of op2 in DL
        mov     BL,AL           ; get exponent of op1
        mov     BH,DL           ; get exponent of op2

        mov     AL,0            ; zero rest of fraction
        stc                     ; put implied 1 bit into top bit of
        rcr     EAX,1           ; ... fraction
        mov     DL,0            ; zero rest of fraction
        stc                     ; put implied 1 bit into top bit
        rcr     EDX,1           ; ... of fraction

        mov     CH,BL           ; assume op1 > op2
        sub     BL,BH           ; calculate difference in exponents
        _if     ne              ; if different
          _if   b               ; - if op1 < op2
            mov   CH,BH         ; - - get larger exponent for result
            neg   BL            ; - - negate the shift count
            xchg  EAX,EDX       ; - - flip operands
            xor   CL,4

;<> op_2 is larger, so its sign now occupies bit 2 of sign word.  This
;<> information is only correct if the signs of op-1 and op-2 are different.
;<> Since we look past bit 1 for sign only if the signs are different, bit2
;<> will supply the correct information when it is needed. We get the sign of
;<> op_2 by flipping the sign of op_1, already in bit 2

          _endif                ; - endif
          xchg  CL,BL           ; - get shift count
          cmp   CL,32           ; - if count >= 32
          _if   ge              ; - then
            sub   EDX,EDX       ; - - answer is 0
          _else                 ; - else
            shr   EDX,CL        ; - - align fraction
          _endif                ; - endif
          xchg  CL,BL           ; - put back
        _endif                  ; endif
        shr     CL,1            ; get bit 0 of sign word - value is 0 if
                                ; both operands have same sign, 1 if not
        _if     nc              ; if signs are the same
          add   EAX,EDX         ; - add the fractions
          _if   c               ; - if carry
            rcr   EAX,1         ; - - shift fraction right 1 bit
            inc   CH            ; - - increment exponent
            _if   z             ; - - if we overflowed
              ror CL,1          ; - - - set sign of infinity
              rcr EAX,1         ; - - - . . .
              jmp short add_oflow;- - - handle overflow
            _endif              ; - - endif
          _endif                ; - endif
        _else                   ; else (signs are different)
          shr   CL,1            ; - skip junk bit
          sub   EAX,EDX         ; - subtract the fractions
          _guess                ; - guess
            _quif nc            ; - - quit if no borrow
            inc   CL            ; - - sign := sign of op_2
            neg   EAX           ; - - negate the fraction
          _admit                ; - admit
            or    EAX,EAX       ; - - quit if answer is not 0
            _quif ne            ; - - . . .
            pop   EBX           ; - - restore EBX
            pop   ECX           ; - - restore ECX
            ret                 ; - - return (answer is 0)
          _endguess             ; - endguess
        _endif                  ; endif

        ; normalize the fraction
        add     EAX,00000080h   ; round up fraction if required
        mov     AL,0            ; zero bottom 8 bits    10-jul-89
        _guess  underflow       ; guess
          _quif nc              ; - quit if round up didn't overflow frac
          inc   CH              ; - adjust exponent
        _admit                  ; admit
          _loop                 ; - loop (shift until high bit appears)
            _shl  EAX,1         ; - - shift fraction left
            _quif c,underflow   ; - - quit if carry has appeared
            dec   CH            ; - - decrement exponent
          _until  e             ; - until underflow
          jmp   short add_uflow ; - handle underflow
        _endguess               ; endguess
        mov     AL,CH           ; get exponent
        ror     EAX,8           ; rotate into position
        ror     CL,1            ; get sign bit
        rcr     EAX,1           ; shift it into result
        pop     EBX             ; restore EBX
        pop     ECX             ; restore ECX
        ret                     ; return

add_uflow:                      ; handle underflow
        pop     EBX             ; restore EBX
        pop     ECX             ; restore ECX
        jmp     F4UnderFlow     ; goto underflow routine

add_oflow:                      ; handle overflow
        pop     EBX             ; restore EBX
        pop     ECX             ; restore ECX

⌨️ 快捷键说明

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