fsmth086.asm

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

ASM
652
字号
        mov     SI,DX           ; move X1 to less volatile register

        _shl    BX,1            ; move sign of X
        _rcl    AL,1            ; into AL
        stc                     ; rotate implied high bit into X
        rcr     BL,1            ; . . .
        _shl    CX,1            ; use sign of Y
        adc     AL,0            ; to calculate sign of result in AL
        stc                     ; rotate implied high bit into Y
        rcr     CL,1            ; . . .

        xchg    AL,CH           ; put sign in CH and get exponent of Y
        sub     AL,7Fh          ; remove bias from exponents
        sub     BH,7Fh          ; . . .
        add     BH,AL           ; add exponents
        _if     o               ; if over or underflow
          js    mul_oflow       ; - report overflow if signed
          jmp   mul_uflow       ; - handle underflow
        _endif                  ; endif
        cmp     BH,81h          ; check for underflow
        jle     mul_uflow       ; quit if underflow
        add     BH,7fh+2        ; bias exponent
        xchg    BH,CL           ; put exponent of result in CL and move Y2
                                ; into BH. Note that BL holds X2
        mov     AX,DI           ; get X1

        mul     SI              ; C1 := high_word( X1 * Y1 ) and
        xchg    DX,DI           ; get X1
        mov     AX,BX           ; get Y2
        xchg    AH,AL           ; put factor into lower register
        sub     AH,AH           ; . . .

        mul     DX              ; C2 := high_word( X1 * Y2 ) and
        xchg    DX,SI           ; get Y1
        add     DI,AX           ; (C2_C1) += low_word( X1 * Y2 )
        adc     SI,0            ; . . .
        mov     AX,BX           ; get X2
        sub     AH,AH           ; . . .
        mul     DX              ; (C2_C1) += low_word( X2 * Y1 )
        add     DI,AX           ; . . .
        adc     SI,DX           ; C2 += high_word( X2 * Y1 )
        mov     AX,BX           ; get X2
        mul     AH              ; C2 += byte_product( Y2 * X2 )
        add     SI,AX           ; . . .

        _loop                   ; loop
          _shl  DI,1            ;   shift result left
          _rcl  SI,1            ;   . . .
          dec   CL              ;   and dec exponent for every shift
        _until  be              ; until( carry flag or zero flag is set )
        jz      mul_oflow       ; ...

        mov     AX,SI           ; move result to more flexible registers
        mov     BX,DI           ; . . .
        mov     BL,BH           ; shift exponent into result
        mov     BH,AL           ; . . .
        mov     AL,AH           ; . . .
        mov     AH,CL           ; . . .
        add     BX,1            ; round up fraction
        adc     AX,0            ; and increment exponent if necessary
        jz      mul_oflow       ; report overflow if required
        shr     CH,1            ; shift sign into result
        rcr     AX,1            ; . . .
        rcr     BX,1            ; . . .
        mov     DX,AX           ; get result into DX:AX
        mov     AX,BX           ; . . .
        pop     DI              ; restore DI
        pop     SI              ; restore SI
        ret                     ; return

mul_uflow:                      ; underflow
        pop     DI              ; restore DI
        pop     SI              ; restore SI
        jmp     F4UnderFlow     ; . . .

mul_oflow:                      ; overflow
        shr     CH,1            ; get sign of infinity
        rcr     AX,1            ; into proper register
        pop     DI              ; restore DI
        pop     SI              ; restore SI
        jmp     F4OverFlow      ; report overflow
        endproc __FSM

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

        defpe   __FSD
        go_to   fsdiv

__FSDbad_div:
        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              ; . . .
        call    __fdiv_m32      ; divide operand 1 by operand 2
        sub     sp,4            ; rtn pops parm, _ret87 wants it
        jmp     _ret87          ; goto common epilogue

__FSD87:
        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              ; . . .
        fdiv    dword ptr -8[BP]; divide operand 1 by operand 2
        jmp     _ret87          ; goto common epilogue

__FSDemu:
        _shl    CX,1            ; shift sign of divisor into carry
        _if     e               ; if divisor is zero
          jmp   F4DivZero       ; - handle divide by zero
        _endif                  ; endif
        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,DX           ; save DX in DI
                                ; CX:DI is the divisor;  AX:BX is the dividend
        _rcl    DL,1            ; save sign in DL
        or      AX,AX           ; check dividend for zero
        _if     e               ; if so then
          sub   DX,DX           ; - make sure both parts are 0
          pop   DI              ; - restore DI
          pop   SI              ; - restore SI
          ret                   ; - return
        _endif                  ; endif
        stc                     ; rotate implied '1'bit back into divisor
        rcr     CL,1            ; . . .
        _shl    AX,1            ; shift sign of divisor into carry
        adc     DL,0            ; now calculate save sign of result in DL
        stc                     ; rotate implied '1' bit into dividend
        rcr     AL,1            ; . . .
        sub     CH,7Fh          ; calculate exponent of result
        sub     AH,7Fh          ; . . .
        sub     AH,CH           ; . . .
        _if     o               ; if over or underflow
          _if   s               ; - if overflow
            shr dl,1            ; - - get sign of infinity
            rcr ax,1            ; - - . . .
            jmp div_oflow       ; - - handle overflow
          _endif                ; - else
          jmp   div_uflow       ; - - handle underflow
        _endif                  ; endif
        cmp     AH,81h          ; check for underflow
        jle     div_uflow       ; . . .
        add     AH,7Fh          ; restore bias to exponent
        mov     DH,AH           ; save calculated exponent
        mov     CH,25
        mov     AH,CL

; The count is set to 25.  We do not know if the first digit of our quotient
; mantissa will be a one or zero.  We do know that if the first calculated
; digit was not a 1, the second one will be, since we will have by then
; shifted the dividend left and made it large enough for the divisor to
; subtract out of  To always calculate 24 SIGNIFICANT digits (ie with a leading
; one) in the mantissa we must, then, calculate 25, in case the leading digit
; was a zero.

        _loop                   ; loop
          _guess                ; - The purpose of this guess is to set the
            cmp AH,AL           ; - Carry bit by the time we reach endguess
            jl  try
            jg  didnt_go
            cmp DI,BX           ; - . . .
            je  try             ; - . . .
          _endguess             ; - . . .
          _if   c               ; - if
                                ; - - the carry is set (ie the divisor will
                                ; - - definitely subract from the dividend
                                ; - - without a borrow
try:        sub BX,DI           ; - - subtract the divisor from dividend
            sbb AL,AH           ; - - . . .
            stc                 ; - - set cary, to indicate that the divisor
                                ; - - was subtracted from the dividend
          _endif                ; - endif
didnt_go: _rcl  SI,1            ; - rotate a 1 into quotient if carry set
          _rcl  CL,1            ; - . . .
          dec   CH              ; - count --
          jle   done            ; - if( count = 0 ) goto done
resume:
          _shl  BX,1            ; - shift divisor left
          _rcl  AL,1            ; - . . .
          jc    try

; If the carry is set here, we didnt subtract the divisor from the dividend
; (recall that the divisor has a 1 in the msb -- if we subtracted it from
; the dividend without a borrow, the dividend would not have a one in
; its msb to be shifted into the carry tested for in the condition above.
; If we are rotating a carry out of the dividend, the dividend
; is now big enough that we can be sure of subtracting out the divisor
; without a borrow, as we have shifted it left one digit.

          jno   didnt_go

; If the overflow is not set and the carry is not set, we know there is
; now a '0' in the msb of the dividend and since there is a '1' in the
; msb of the divisor, we know that it wont subtract from the dividend
; without a borrow, so we dont even check --- just jump to a place where
; we can shift a 0 into the quotient for the current digit

        _endloop
done:

; The following conditional ensures that not only do we have 24 significant
; normalized digits in our quotient registers, but we also have the next
; (would have followed the lsb) bit in the carry.  If we do not have a
; carry at this point, we only have 24 sig digits.  We can use the carry
; to hold an extra significant digit, which we go back for in the conditional

        _if     nc
          dec   DH

; the exponent is decremented because in going back for an extra digit, we
; shift the quotient left one bit, and hence multiply it by two.

          jnz   resume          ; on not overflow, goto resume
          jmp   div_uflow       ; handle underflow
        _endif

; we know that the carry is set here --- ie we have shifted
; a significant bit of the quotient into the carry in order
; to make room for an extra significant bit in the lsb position
; of the word. We now put the msb in the carry back into the msb
; of the word, and use the lsb shifted into the carry in doing this to
; round off the quotient. We do this by rotating right the carry into the
; quotient and saving the least sig bit in the carry. This is added back on to
; round off the number. we do not alter the exponent when we right, because
; we shifted left 25 times instead of 24, so the quotent needed right shifting

        rcr     CL,1
        rcr     SI,1
        adc     SI,0            ; add back lsb to round off quotient
        adc     CL,0            ; . . .
        _guess                  ; guess have to inc exponent
          _quif nc              ; - quit if no carry
          inc   dh              ; - increment exponent
          _quif nz              ; - quit if no overflow
          shr   dl,1            ; - get sign of infinity
          rcr   ax,1            ; - . . .
          jmp   div_oflow       ; - handle overflow
        _endguess               ; endguess

        ror     DX,1            ; rotate sign bit into high bit
        or      DX,007Fh        ; prepare sign-exponent word
        mov     CH,0FFh         ; prepare high word of mantissa word
        and     CX,DX           ; mask the sign and exponent into quotient
        mov     DX,CX           ; move high order word of quotent to DX
        mov     AX,SI           ; move low  ...    ...        ...    AX
        pop     DI              ; restore DI
        pop     SI              ; restore SI
        ret                     ; return to caller

div_uflow:                      ; handle underflow
        pop     DI              ; restore DI
        pop     SI              ; restore SI
        jmp     F4UnderFlow     ; handle underflow


div_oflow:                      ; handle overflow
        pop     DI              ; restore DI
        pop     SI              ; restore SI
        jmp     F4OverFlow      ; handle overflow
        endproc __FSD


_chkadd: call   _chk8087
        go_to   fsadd

_chkmul: call   _chk8087
        go_to   fsmul

_chkdiv: call   _chk8087
        go_to   fsdiv

_chk8087 proc   near
        push    ax                      ; save AX
if (_MODEL and _DS_PEGGED) eq 0
if _MODEL and (_BIG_DATA or _HUGE_DATA)
        push    ds                      ; save DS
        mov     ax,DGROUP               ; get access to DGROUP
        mov     ds,ax                   ; . . .
endif
endif
        cmp     byte ptr __real87,0     ; if 8087 present
        _if     ne                      ; then
          mov   ax,offset __FSA87       ; - get addr of add rtn
          mov   fsadd,ax                ; - ...
          mov   ax,offset __FSM87       ; - get addr of mul rtn
          mov   fsmul,ax                ; - ...
          test  byte ptr __chipbug,1    ; - if we have a bad divider
          _if   ne                      ; - then
            mov ax,offset __FSDbad_div  ; - - get addr of div rtn
          _else                         ; - else
            mov ax,offset __FSD87       ; - - get addr of div rtn
          _endif
          mov   fsdiv,ax                ; - ...
        _else                           ; else
          mov   ax,offset __FSAemu      ; - get addr of add rtn
          mov   fsadd,ax                ; - ...
          mov   ax,offset __FSMemu      ; - get addr of mul rtn
          mov   fsmul,ax                ; - ...
          mov   ax,offset __FSDemu      ; - get addr of div rtn
          mov   fsdiv,ax                ; - ...
        _endif                          ; endif
if (_MODEL and _DS_PEGGED) eq 0
if _MODEL and (_BIG_DATA or _HUGE_DATA)
        pop     ds                      ; restore ds
endif
endif
        pop     ax                      ; restore AX
        ret                             ; return
        endproc _chk8087

        endmod
        end

⌨️ 快捷键说明

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