fsmth086.asm

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

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


;
;     real*4 math library
;
;  04-apr-86    G. Coschi       special over/underflow check in mul,div
;                               have to always point at DGROUP.
;                               we might be running with SS != DGROUP
;
;     inputs: DX,AX - operand 1 (high word, low word resp. ) (op1)
;             CX,BX - operand 2                              (op2)
;
;     operations are performed as op1 (*) op2 where (*) is the selected
;     operation
;
;     output: DX,AX - result    (high word, low word resp. )
;
;     __FSA, __FSS - 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
;     __FSM        - written  16-may-84
;                  - by       Athos Kasapi
;     __FSD        - written  may-84 by "
;
;
;
include mdef.inc
include struct.inc

.8087
        modstart        fsmth086

        xref            __8087  ; indicate that NDP instructions are present

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

go_to   macro frtn
if _MODEL and _DS_PEGGED
        jmp     frtn
else
 if _MODEL and (_BIG_DATA or _HUGE_DATA)
        push    ax
        push    bp
        push    ds
        mov     ax,DGROUP               ; get access to DGROUP
        mov     bp,sp
        mov     ds,ax                   ; . . .
        mov     ax,frtn
        xchg    ax,4[bp]
        pop     ds
        pop     bp
        retn
 else
        jmp     frtn
 endif
endif
endm

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

        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
        jcxz    ret_op1         ; if op2 is 0 then return operand 1
        xor     CH,80h          ; flip the sign of op2 and add

        defpe   __FSA
        jcxz    ret_op1         ; if op2 is 0 then return operand 1
        or      DX,DX           ; if op1 is 0
        _if     e               ; then
          mov   DX,CX           ; - return operand 2
          mov   AX,BX           ; - . . .
ret_op1:  ret                   ; - return
        _endif                  ; endif
        go_to   fsadd

__FSA87:
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    DX              ; push operand 1
        push    AX              ; . . .
        fld     dword ptr -4[BP]; load operand 1
        push    CX              ; push operand 2
        push    BX              ; . . .
        fadd    dword ptr -8[BP]; add operand 2 to operand 1
_ret87:
        fstp    dword ptr -4[BP]; store result
        add     sp,4            ; clean up stack
        fwait                   ; wait
        pop     AX              ; load result into DX:AX
        pop     DX              ; . . .
        cmp     DX,8000h        ; check for negative zero
        _if     e               ; if it is then
          sub     AX,AX         ; - make it positive
          mov     DX,AX         ; - ...
        _endif                  ; endif
        pop     BP              ; restore BP
        ret                     ; return

__FSAemu:
        push    DI              ; save DI
        xchg    AX,BX           ; flip registers around
        xchg    AX,DX           ; . . .
;
;       now have:
;               AX:BX
;           +-  CX:DX
;<> Scheme for calculating sign of result:
;<>   The sign word is built and kept in DL
;<>   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

        mov     DI,DX           ; put low order word of op2 in DI
        sub     DX,DX           ; clear DX
        _shl    AX,1            ; get exponent of op1 into AH
        _rcl    DL,1            ;
        mov     DH,DL           ;
        _shl    DL,1            ;
        _shl    DL,1            ;
        add     DL,DH           ;
        stc                     ; put implied 1 bit into top bit of
        rcr     AL,1            ; ... fraction
        _shl    CX,1            ; get exponent of op2 into CH
        adc     DL,0            ;
        stc                     ; put implied 1 bit into top bit
        rcr     CL,1            ; ... of fraction
        mov     DH,AH           ; assume op1 > op2
        sub     AH,CH           ; calculate difference in exponents
        _if     ne              ; if different
          _if   b               ; - if op1 < op2
            mov   DH,CH         ; - - get larger exponent for result
            neg   AH            ; - - negate the shift count
            xchg  AL,CL         ; - - flip operands
            xchg  BX,DI         ; - - . . .
            xor   DL,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
          mov   CH,AH           ; - get shift count
          mov   AH,0            ; - zero guard byte
          _loop                 ; - loop (align fractions)
            shr   CL,1          ; - - shift over fraction
            rcr   DI,1          ; - - . . .
            dec   CH            ; - - decrement shift count
          _until e              ; - until fractions aligned
          rcr   AH,1            ; - only need last bit in guard byte

;<> bit 7 of the guard byte holds an extra significant bit from mantissa
;<> of the operand we shifted left to allign with the greater operand
;<> it is added or subtracted from with operands by shifting the bit into
;<> the carry bit just before the operation

        _endif                  ; endif
        shr     DL,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   BX,DI           ; - add the fractions
          adc   AL,CL           ; - . . .
          _if   c               ; - if carry
            rcr   AL,1          ; - - shift fraction right 1 bit
            rcr   BX,1          ; - - . . .
            rcr   AH,1          ; - - save extra sig bit in guard bit
            inc   DH            ; - - increment exponent
            _if   z             ; - - if we overflowed
              ror dl,1          ; - - - set sign of infinity
              rcr ah,1          ; - - - . . .
              jmp add_oflow     ; - - - handle overflow
            _endif              ; - - endif
          _endif                ; - endif
        _else                   ; else (signs are different)
          shr   DL,1            ; - skip junk bit
          rol   AH,1            ; - get guard bit
          ror   AH,1            ; - and put it back
          sbb   BX,DI           ; - subtract the fractions
          sbb   AL,CL           ; - . . .
          _guess                ; - guess
            _quif nc            ; - - quit if no borrow
            inc   DL            ; - - sign := sign of op_2
            not   AL            ; - - negate the fraction (considering
                                ; - - the guard bit an extension of the
            not   BX            ; - - fraction)
            neg   AH            ; - - . . .
            sbb   BX,-1         ; - - . . .
            sbb   AL,-1         ; - - . . .
          _admit                ; - admit
            cmp   AL,0          ; - - quit if answer is not 0
            _quif ne            ; - - . . .
            or    BX,BX         ; - - . . .
            _quif ne            ; - - . . .
            sub   AX,AX         ; - - set result to 0
            sub   DX,DX         ; - - . . .
            pop   DI            ; - - restore DI
            ret                 ; - - return (answer is 0)
          _endguess             ; - endguess
        _endif                  ; endif

        ; normalize the fraction
        _shl    AH,1            ; get guard bit
        adc     BX,0            ; round up fraction if required
        adc     AL,0            ; . . .
        _guess  underflow       ; guess
          _quif nc              ; - quit if round up didn't overflow frac
          inc   DH              ; - adjust exponent
        _admit                  ; admit
          _loop                 ; - loop (shift until high bit appears)
            _rcl  BX,1          ; - - shift fraction left
            _rcl  AL,1          ; - - . . .
            _quif c,underflow   ; - - quit if carry has appeared
            dec   DH            ; - - decrement exponent
          _until  e             ; - until underflow
          jmp   add_uflow       ; - handle underflow
        _endguess               ; endguess
        mov     AH,DH           ; get exponent
        ror     DL,1            ; get sign bit
        rcr     AX,1            ; shift it into result
        rcr     BX,1            ; . . .
        mov     DX,AX           ; get result in DX:AX
        mov     AX,BX           ; . . .
        pop     DI              ; restore DI
        ret                     ; return

add_uflow:                      ; handle underflow
        pop     DI              ; restore DI
        jmp     F4UnderFlow     ; goto underflow routine

add_oflow:                      ; handle overflow
        pop     DI              ; restore DI
        jmp     F4OverFlow      ; handle overflow
        endproc __FSA
        endproc __FSS

;=====================================================================

        defpe   __FSM

;<> multiplies X by Y and places result in C.
;<> X2 and X1 represent the high and low words of X. Similarly for Y and C
;<> Special care is taken to use only six registers, so the code is a bit
;<> obscure

        _guess                  ; guess: answer not 0
          or    DX,DX           ; - see if first arg is zero
          _quif e               ; - quit if op1 is 0
          or    CX,CX           ; - quit if op2 is 0
          _quif e               ; - . . .
          go_to fsmul           ; - invoke support rtn
        _endguess               ; endguess
        sub     AX,AX           ; set answer to 0
        sub     DX,DX           ; . . .
        ret                     ; return

__FSM87:
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    DX              ; push operand 1
        push    AX              ; . . .
        fld     dword ptr -4[BP]; load operand 1
        push    CX              ; push operand 2
        push    BX              ; . . .
        fmul    dword ptr -8[BP]; mulitply operand 1 by operand 2
        jmp     _ret87          ; goto common epilogue

__FSMemu:
        push    SI              ; save SI
        push    DI              ; save DI
        xchg    AX,BX           ; flip registers around
        xchg    AX,DX           ; . . .
;
;       now have:
;               AX:BX
;            *  CX:DX
;
        mov     DI,BX           ; move arguments to better registers
        mov     BX,AX           ; . . .

⌨️ 快捷键说明

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