fsmth386.asm

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

ASM
454
字号
        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    EAX,EAX         ; - see if first arg is zero
          _quif e               ; - quit if op1 is 0
          or    EDX,EDX         ; - quit if op2 is 0
          _quif e               ; - . . .
          jmp   fsmul           ; - perform multiplication
        _endguess               ; endguess
        sub     EAX,EAX         ; set answer to 0
        ret                     ; return

__FSM87:
        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
        fmul    dword ptr -8[EBP]; mulitply operand 1 by operand 2
        jmp     _ret87          ; goto common epilogue

__FSMemu:
        push    ECX             ; save ECX
        _shl    EAX,1           ; get sign of op1
        _rcl    ECX,1           ; save it
        _shl    EDX,1           ; get sign of op2
        adc     ECX,0           ; calc sign of result
        ror     ECX,1           ; move to the top
        rol     EAX,8           ; move exponent of op1 into AL
        rol     EDX,8           ; move exponent of op2 into DL
        sub     AL,7Fh          ; remove bias from exponents
        sub     DL,7Fh          ; . . .
        add     DL,AL           ; add exponents
        _if     o               ; if over or underflow
          js    short mul_oflow ; - report overflow if signed
          jmp   short mul_uflow ; - handle underflow
        _endif                  ; endif
        cmp     DL,81h          ; check for underflow
        jle     short mul_uflow ; quit if underflow
        add     DL,7fh+1        ; bias exponent
        mov     CL,DL           ; save exponent
        mov     AL,0            ; zero rest of fraction
        mov     DL,0            ; ...
        stc                     ; turn on implied 1 bit in fraction
        rcr     EAX,1           ; ...
        stc                     ; turn on implied 1 bit in fraction
        rcr     EDX,1           ; ...
        mul     EDX             ; calc fraction
        or      EDX,EDX         ; check top bit
        _if     ns              ; if not set
          _shl  EDX,1           ; - move left 1
          dec   CL              ; - decrement exponent
        _endif                  ; endif
        sar     EDX,8           ; place fraction in correct location
        adc     EDX,0           ; round up
        adc     CL,0            ; increment exponent if necessary
        jz      short mul_oflow ; report overflow if required
        shl     EDX,9           ; get rid of implied 1 bit
        mov     DL,CL           ; get exponent
        ror     EDX,8           ; rotate into position except for sign
        _shl    ECX,1           ; get sign
        rcr     EDX,1           ; place sign in result
        mov     EAX,EDX         ; place in correct register
        pop     ECX             ; restore ECX
        ret                     ; return

mul_uflow:                      ; underflow
        pop     ECX             ; restore ECX
        jmp     F4UnderFlow     ; . . .

mul_oflow:                      ; overflow
        mov     EAX,ECX         ; get sign
        pop     ECX             ; restore ECX
        jmp     F4OverFlow      ; report overflow
        endproc __FSM

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

        defpe   __FSD
        jmp     fsdiv

__FSDbad_div:
        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
        call    __fdiv_m32      ; divide operand 1 by operand 2
        push    EDX             ; __fdiv_m32 popped operand 2, _ret87 wants it
        jmp     _ret87          ; goto common epilogue

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


__FSDemu:
        _shl    EDX,1           ; shift sign of divisor into carry
        _if     e               ; if divisor is zero
          jmp   F4DivZero       ; - handle divide by zero
        _endif                  ; endif
        push    ECX             ; save ECX
        _rcl    ECX,1           ; save sign in ECX
        _shl    EAX,1           ; shift sign of dividend into carry
        _if     e               ; if dividend is 0, then
          pop   ECX             ; - restore ECX
          ret                   ; - return
        _endif                  ; endif
        adc     ECX,0           ; now calculate save sign of result in ECX
        ror     ECX,1           ; rotate sign to top
        rol     EAX,8           ; get exponent into AL
        rol     EDX,8           ; get exponent into DL
        sub     AL,7Fh          ; calculate exponent of result
        sub     DL,7Fh          ; . . .
        sub     AL,DL           ; . . .
        _if     o               ; if over or underflow
          jns   short div_uflow ; - handle underflow
          _shl  ECX,1           ; - get sign of infinity
          rcr   EAX,1           ; - . . .
          jmp   short div_oflow ; - handle overflow
        _endif                  ; endif
        cmp     AL,81h          ; check for underflow
        jle     short div_uflow ; . . .
        add     AL,7Fh          ; restore bias to exponent
        mov     CH,AL           ; save calculated exponent
        mov     AL,0            ; zero bottom of fraction
        mov     DL,0            ; ...
        stc                     ; rotate implied '1'bit back into divisor
        rcr     EDX,1           ; . . .
        stc                     ; rotate implied '1' bit into dividend
        rcr     EAX,1           ; . . .
        push    ECX             ; save sign and exponent
        mov     ECX,EDX         ; save divisor
        mov     EDX,EAX         ; place dividend into EDX
        sub     EAX,EAX         ; set rest to 0
        shr     EDX,1           ; so we don't get a divide overflow trap
        div     ECX             ; do the divide
        pop     ECX             ; restore sign and exponent
        or      EAX,EAX         ; check top bit
        _if     ns              ; if not set
          _shl  EAX,1           ; - move left 1
          dec   CH              ; - decrement exponent
        _endif                  ; endif
        sar     EAX,8           ; place fraction in correct location
        adc     EAX,0           ; round up
        _guess                  ; guess have to inc exponent
          _quif nc              ; - quit if no carry
          inc   CH              ; - increment exponent
          _quif nz              ; - quit if no overflow
          mov   EAX,ECX         ; - get sign of infinity
          jmp   short div_oflow ; - handle overflow
        _endguess               ; endguess
        shl     EAX,9           ; get rid of implied 1 bit
        mov     AL,CH           ; get exponent
        ror     EAX,8           ; rotate into position except for sign
        _shl    ECX,1           ; get sign
        rcr     EAX,1           ; place sign in result
        pop     ECX             ; restore ECX
        ret                     ; return to caller

div_uflow:                      ; handle underflow
        pop     ECX             ; restore ECX
        jmp     F4UnderFlow     ; handle underflow


div_oflow:                      ; handle overflow
        pop     ECX             ; restore ECX
        jmp     F4OverFlow      ; handle overflow
        endproc __FSD


_chkadd: call   _chk8087
        jmp     fsadd

_chkmul: call   _chk8087
        jmp     fsmul

_chkdiv: call   _chk8087
        jmp     fsdiv


_chk8087 proc   near
        push    eax                     ; save AX
        cmp     byte ptr __real87,0     ; if real 80x87 NDP present
        _if     ne                      ; then
          mov   eax,offset __FSA87      ; - get addr of add rtn
          mov   fsadd,eax               ; - ...
          mov   eax,offset __FSM87      ; - get addr of mul rtn
          mov   fsmul,eax               ; - ...
          test  byte ptr __chipbug, 1   ; - if we've got a bad divider
          _if   ne                      ; - then
            mov eax,offset __FSDbad_div ; - - get addr of div rtn
          _else                         ; - else
            mov eax,offset __FSD87      ; - - get addr of div rtn
          _endif                        ; - endif
          mov   fsdiv,eax               ; - ...
        _else                           ; else
          mov   eax,offset __FSAemu     ; - get addr of add rtn
          mov   fsadd,eax               ; - ...
          mov   eax,offset __FSMemu     ; - get addr of mul rtn
          mov   fsmul,eax               ; - ...
          mov   eax,offset __FSDemu     ; - get addr of div rtn
          mov   fsdiv,eax               ; - ...
        _endif                          ; endif
        pop     eax                     ; restore AX
        ret                             ; return
        endproc _chk8087

        endmod
        end

⌨️ 快捷键说明

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