fdmth086.asm

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

ASM
1,056
字号
;*****************************************************************************
;*
;*                            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*8 math library
;
;   __FDM,__FDD
;                   floating point routines
;                   13 June, 1984 @Watcom
;
;   All routines have the same calling conventions.
;   Op_1 and Op_2 are double prec reals, pointed to by DI and SI resp.
;   The binary operations are perfomed as Op_1 (*) Op_2.
;
;   In all cases, BP and DI are returned unaltered.
;
;
;                               have to always point at DGROUP.
;                               **** This routine does CODE modification ****
;                               is a power of 2.
;                               aligning fractions before the add
;                               No need to push second operand in f8split
;                               since ss:[si] can already be used to access it
;                               Moved f8split into each subroutine.
;                               to get rid of code modification
;                               we might be running with SS != DGROUP
;
include mdef.inc
include struct.inc

.8087
        modstart        fdmth086

        xref            __8087  ; indicate that NDP instructions are present

        xref    F8OverFlow              ; FSTATUS
        xref    F8UnderFlow             ; FSTATUS
        xref    F8DivZero               ; FSTATUS
        xref    __fdiv_m64r

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
        extrn  __chipbug : byte
fdadd   dw      _chkadd
fdsub   dw      _chksub
fdmul   dw      _chkmul
fddiv   dw      _chkdiv
        enddata

        xdefp   __FDA
        xdefp   __EDA
        xdefp   __FDS
        xdefp   __EDS
        xdefp   __FDM
        xdefp   __EDM
        xdefp   __FDD
        xdefp   __EDD

        defp    __EDD
        push    es:6[si]
        push    es:4[si]
        push    es:2[si]
        push    es:[si]
        mov     si,sp           ; point to second operand
        docall  __FDD
        add     sp,8
        ret
        endproc __EDD

        defp    __EDM
        push    es:6[si]
        push    es:4[si]
        push    es:2[si]
        push    es:[si]
        mov     si,sp           ; point to second operand
        docall  __FDM
        add     sp,8
        ret
        endproc __EDM

        defp    __EDS
        push    es:6[si]
        push    es:4[si]
        push    es:2[si]
        push    es:[si]
        mov     si,sp           ; point to second operand
        docall  __FDS
        add     sp,8
        ret
        endproc __EDS

        defp    __EDA
        push    es:6[si]
        push    es:4[si]
        push    es:2[si]
        push    es:[si]
        mov     si,sp           ; point to second operand
        docall  __FDA
        add     sp,8
        ret
        endproc __EDA


;
; __FDS
;

        defpe   __FDS
        go_to   fdsub

__FDS87:
        fld     qword ptr ss:[SI] ; load operand 2
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    AX              ; push operand 1
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        fsubr   qword ptr -8[BP]; subtract operand 2 from operand 1
_ret87: fstp    qword ptr -8[BP]; store result
        fwait                   ; wait
        pop     DX              ; load result into AX:BX:CX:DX
        pop     CX              ; . . .
        pop     BX              ; . . .
        pop     AX              ; . . .
        cmp     AX,8000h        ; is it negative zero?          17-mar-91
        _if     e               ; if it is then
          sub   AX,AX           ; - turn it into positive zero
          mov   BX,AX           ; - ... zero other words as well
          mov   CX,AX           ; - ...
          mov   DX,AX           ; - ...
        _endif                  ; endif
        pop     BP              ; restore BP
        ret                     ; return

__FDSemu:
        push    BP              ; save BP
        mov     BP,8000h        ; indicate that we are doing subtraction
        jmp     begin
        endproc __FDS


;
; __FDA
;


        defpe   __FDA
        go_to   fdadd

__FDA87:
        fld     qword ptr ss:[SI] ; load operand 2
        push    BP              ; save BP
        mov     BP,SP           ; get access to stack
        push    AX              ; push operand 1
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        fadd    qword ptr -8[BP]; add operand 1
        jmp     _ret87          ; return result from 8087

RetOp_2:
        sub     bx,bx           ; return op2
        _shl    cx,1            ; get sign bit into position
        mov     bp,cx           ; move it to correct reg
        xor     bp,ss:6[si]     ; see if sign must be reversed
        and     bp,8000h        ; clear out rest of reg
                                ; one of the args was found to be zero
addzero:or      BX,BX           ; check the first argument
        _if     ne              ; if the first arg is not zero
          mov   SI,DI           ; - return first argument
          sub   bp,bp           ; - don't reverse sign
        _endif                  ; endif
        mov     ax,ss:6[si]     ; get high word
        or      ax,ax           ; see if number is zero
        _if     ne              ; if not then
          xor   ax,bp           ; - reverse sign if required
        _endif                  ; endif
        mov     BX,ss:4[SI]     ; get next sig word
        mov     CX,ss:2[SI]     ; . . .
        mov     DX,ss:[SI]      ; . . .
        add     SP,8            ; clean up stack
        pop     DI              ; restore DI
        pop     BP              ; return to caller
        ret

__FDAemu:
        push    BP
        sub     BP,BP           ; indicate that we are doing addition
begin:  push    DI              ; save DI

;       copy of the f8split routine

        push    AX              ; push operand 1 onto stack
        push    BX              ; . . .
        push    CX              ; . . .
        push    DX              ; . . .
        mov     DI,SP           ; get address of operand 1
        _guess                  ; guess
          mov   BX,AX           ; - get most sig word of op1
          mov   AX,ss:6[SI]     ; - get most sig word of op2
          mov   DL,AL           ; - save mantissa-holding part
          mov   DH,BL           ; - save mantissa-holding part
          mov   cl,bh           ; - save sign
          and   BX,7FF0h        ; - isolate exponent
          je    addzero         ; - quif zero
          mov   ch,ah           ; - save sign
          and   AX,7FF0h        ; - isolate exponent
          je    addzero         ; - quif zero
          and   cx,8080h        ; - only want sign bits
          xor   dx,1010h        ; - set implied one bit of mant.
          xor   DL,AL           ; - . . .
          xor   DH,BL           ; - . . .
        _endguess               ; endguess

;       end of f8split

        xor     CX,BP           ; change sign of op_2 if this is sub
        sar     CH,1            ; prepare sign byte
        add     CH,CL           ; it is op_2's sign we indicate
        mov     BP,AX           ; save exponent
        sub     AX,BX           ; get shift count
        _if     l               ; - if op_2 < op_1
          mov   BP,BX           ; - - move op_1's exponent into BP
          neg   AX              ; - - negate the shift count
          xchg  SI,DI           ; - - exchange operands
          xchg  DH,DL           ; - - . . .
          _shl  CH,1            ; - - make op_1's sign count
          rcr   CL,1
          xchg  CL,CH           ; - - . . .
        _endif                  ; - endif
        cmp     AX,0400h        ; AX has shift count << 4
        jae     retOp_2         ; if shift count >= 64, return operand 2
        shr     AX,1            ; move shift count into bottom bits
        shr     AX,1
        shr     AX,1
        shr     AX,1
        mov     AH,AL           ; AH := shift count
        mov     AL,DH           ; AL := high byte of smaller real
        mov     DH,CH           ; DH := sign byte
        mov     BX,ss:4[DI]     ; . . .
        mov     CX,ss:2[DI]     ; . . .
        mov     DI,ss:[DI]      ; . . .
        or      AH,AH           ; test AH (shift count)
        _if     ne              ; if shift count <> 0
          xchg  DX,DI           ; - get DI into byte registers for shift
          _loop                 ; - loop (shift by a byte at a time)
            cmp   AH,8          ; - - quit if less than a byte to do
            _quif l             ; - - . . .
            sub   AH,8          ; - - subtract 8 from shift count
            _if   e             ; - - if exact # of bytes
              mov   AH,DL       ; - - - get high bit for guard bit
            _endif              ; - - endif
            mov   DL,DH         ; - - shift right 1 byte
            mov   DH,CL         ; - - . . .
            mov   CL,CH         ; - - . . .
            mov   CH,BL         ; - - . . .
            mov   BL,BH         ; - - . . .
            mov   BH,AL         ; - - . . .
            mov   AL,0          ; - - . . .
          _until  e             ; - until done
          _if   ne              ; - if still more to shift
            _loop               ; - - loop
              shr   AL,1        ; - - - shift over fractions
              rcr   BX,1        ; - - - . . .
              rcr   CX,1        ; - - - . . .
              rcr   DX,1        ; - - - . . .
              dec   AH          ; - - - dec shift count
            _until  e           ; - - until shift count = 0
            rcr   AH,1          ; - - save guard bit
          _endif                ; - endif
          and   AH,80h          ; - isolate guard bit
          xchg  DX,DI           ; - exchange regs again
        _endif                  ; endif
        _shl    DH,1            ; get bit 7 of sign word. 1 if signs are
                                ; different, 0 if they are the same
        _if     nc              ; if signs are the same
          add   DI,ss:[SI]      ; - add the mantissas
          adc   CX,ss:2[SI]     ; - . . .
          adc   BX,ss:4[SI]     ; - . . .
          adc   AL,DL           ; - . . .
          test  AL,20h          ; - check for carry
          je    add_norm        ; - if we haven't carried, normalize now
          push  DX              ; - put sign onto stack
          mov   DX,DI           ; - get low word into correct reg
          jmp   fin_up          ; - common finish up routine
        _endif                  ; endif
        sub     DI,ss:[SI]
        sbb     CX,ss:2[SI]     ; . . .
        sbb     BX,ss:4[SI]     ; . . .
        sbb     AL,DL           ; . . .
        cmc                     ; complement carry
        rcr     SI,1            ; save complemented carry in SI
        and     SI,8000h        ; isolate the bit
        add     DX,SI           ; and use it to calculate sign of result
        _shl    SI,1            ; restore the complement of the carry
        _if     c               ; if no borrow, see if result is zero
          cmp   AL,0            ; - - quif answer is not zero
          jne   add_norm        ; - - . . .
          or    SI,BX

⌨️ 快捷键说明

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