c.asm

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

ASM
589
字号
SW_PE           =       0020H
;include fstatus.inc
FPE_OK                  equ     0
FPE_INVALID             equ     81h
FPE_DENORMAL            equ     82h
FPE_ZERODIVIDE          equ     83h
FPE_OVERFLOW            equ     84h
FPE_UNDERFLOW           equ     85h
FPE_INEXACT             equ     86h
FPE_UNEMULATED          equ     87h
FPE_SQRTNEG             equ     88h
FPE_STACKOVERFLOW       equ     8ah
FPE_STACKUNDERFLOW      equ     8bh
FPE_EXPLICITGEN         equ     8ch
FPE_IOVERFLOW           equ     8dh
;include 386sqrt.inc
;
;
        xdefp   __sqrt
;
;       __sqrt( long double *EAX );
;

        defp    __sqrt
        push    EDI             ; save EDI
        push    ESI             ; save ESI
        push    EDX             ; save EDX
        push    ECX             ; save ECX
        push    EBX             ; save EBX
        mov     CX,8[EAX]       ; get exponent
        mov     EDX,4[EAX]      ; get operand
        mov     EBX,[EAX]       ; ...
        _guess                  ; guess: special number
          or    EBX,EBX         ; - quit if not zero
          _quif ne              ; - ...
          or    EDX,EDX         ; - if fraction all zero
          _if   e               ; - then
            _shl  CX,1          ; - - get rid of sign bit
            je    sqrt9         ; - - answer is 0 if exponent is 0
indefinite: mov   word ptr 8[EAX],0FFFFh ; - - set result to indefinite
            mov   dword ptr 4[EAX],0    ; - - ...
            mov   dword ptr [EAX],0     ; - - ...
sq_NaN:     or    byte ptr 7[EAX],0C0h  ; - - set result to NaN
            jmp   sqrt9         ; - - return
          _endif                ; - endif
          cmp   CX,7FFFh        ; - if +ve infinity
          je    sqrt9           ; - answer is +ve infinity if arg is +vf inf.
        _endguess               ; endguess
        _guess                  ; guess: NaN
          mov   EDX,ECX         ; - get exponent
          and   DH,07Fh         ; - get rid of sign bit
          cmp   DX,07FFFh       ; - check for NaN
          je    sq_NaN          ; - result is a NaN
          _shl  CX,1            ; - get rid of sign bit
          jc    sq_NaN          ; - sqrt(-ve) = -ve
          shr   CX,1            ; - restore sign
          _quif e               ; - quit if number is denormal
          mov   EDX,4[EAX]      ; - get top part of fraction
          _shl  EDX,1           ; - top bit should be on
          jnc   indefinite      ; - number is an unnormal
        _endguess               ; endguess
        mov     EDX,4[EAX]      ; get operand
        sub     EDI,EDI         ; zero guard bits
        push    EAX             ; save address of operand
        sub     CX,3FFFh        ; remove bias
        sar     CX,1            ; divide by 2
        _if     nc              ; if exponent is even
          shr   EDX,1           ; - divide argument by 2
          rcr   EBX,1           ; - ...
          rcr   EDI,1           ; - save guard bit
        _endif                  ; endif
        add     CX,3FFFh        ; add bias back in
        mov     8[EAX],CX       ; store exponent
        mov     ECX,EDX         ; save operand
        mov     EAX,EBX         ; ...
        mov     ESI,EDX         ; get high order word
        stc                     ; calculate initial estimate
        rcr     ESI,1           ; ...
        inc     EDX             ; check for EDX=FFFFFFFFh
        _if     ne              ; if not -1, then
          dec   EDX             ; - restore EDX
          _loop                 ; - loop
            div   ESI           ; - - calculate newer estimate
            dec   ESI           ; - - want estimate to be within one
            cmp   ESI,EAX       ; - -
            _quif na            ; - - quit if estimate good enough
            inc   ESI           ; - -
            add   ESI,EAX       ; - - calculate new estimate as (old+new)/2
            rcr   ESI,1         ; - - ...
            mov   EDX,ECX       ; - - restore operand
            mov   EAX,EBX       ; - - ...
          _endloop              ; - endloop
          inc   ESI             ; - restore divisor
          mov   ECX,EAX         ; - save word of quotient
          mov   EAX,EDI         ; - get guard bit
          div   ESI             ; - calculate next word of quotient
;
;       ESI:0   estimate is too small
;       ECX:EAX estimate is too large
;       calculate new estimate as (ESI:0+ECX:EAX)/2
;
          add   ESI,ECX         ; - ...
        _else                   ; else (high word was -1)
          cmp   EAX,ESI         ; - if low word not -1
          je    short sqrt8     ; - then
          xchg  EAX,EDX         ; - flip around
          mov   EAX,EDI         ; - get guard bit
          div   ESI             ; - calculate value for last 32 bits
        _endif                  ; endif
        sub     EDX,EDX         ; zero EDX
        stc                     ; divide by 2
        rcr     ESI,1           ; ...
        rcr     EAX,1           ; ...
        adc     EAX,EDX         ; round up (EDX=0)
sqrt8:  adc     EDX,ESI         ; ...

        pop     ESI             ; restore address of operand
        mov     [ESI],EAX       ; store result
        mov     4[ESI],EDX      ; ...
sqrt9:  pop     EBX             ; restore EBX
        pop     ECX             ; restore ECX
        pop     EDX             ; restore EDX
        pop     ESI             ; restore ESI
        pop     EDI             ; restore EDI
        ret                     ; return to caller
        endproc __sqrt
;include 386fdld.inc
; ====          ==              ======
        xdefp   __FDLD

;       convert double to long double
; input:
;       EDX:EAX double
;       EBX     pointer to long double to be filled in

__FDLD  proc    near
        push    ECX                     ; save ECX
        mov     ECX,EDX                 ; get exponent and sign
        shld    EDX,EAX,11              ; shift fraction left 11 bits
        shl     EAX,11                  ; ...
        _guess                          ; guess: a normal number
          sar   ECX,32-12               ; - shift exponent to bottom
          and   CX,07FFh                ; - isolate exponent
          _quif e                       ; - quit if denormal number
          _guess                        ; - guess: normal number
            cmp   CX,07FFh              ; - - quit if infinity or NaN
            _quif e                     ; - - ...
            add   CX,3FFFh-03FFh        ; - - change bias to temp real format
          _admit                        ; - guess: NaN
            mov   CX,7FFFh              ; - - set exponent for infinity or NaN
            test  EDX,7FFFFFFFh         ; - - check for infinity
            _if   e                     ; - - if top part is 0
              or    EAX,EAX             ; - - - check low word
            _endif                      ; - - endif
            _quif e                     ; - - quit if infinity
            push  EAX                   ; - - save EAX
            mov   AL,SW_IE              ; - - indicate "Invalid" exception
            mov   AH,FPE_INVALID        ; - - ...
            call  __Exception_HNDLR     ; - - ...
            pop   EAX                   ; - - restore EAX
            or    EDX,40000000h         ; - - indicate NaN
          _endguess                     ; - endguess
          or    EDX,80000000h           ; - turn on implied 1 bit
        _admit                          ; guess: zero
          or    EDX,EDX                 ; - quit if non-zero
          _quif ne                      ; - ...
          or    EAX,EAX                 ; - ...
          _quif ne                      ; - ...
          sub   ECX,ECX                 ; - set exponent and sign to 0
        _admit                          ; admit: denormal number
          mov   CX,3C01h                ; - set exponent
          or    EDX,EDX                 ; - if high word is zero
          _if   e                       ; - then
            xchg  EAX,EDX               ; - - shift number left 32 bits
            sub   CX,32                 ; - - adjust exponent
          _endif                        ; - endif
          _loop                         ; - loop (normalize number)
            or    EDX,EDX               ; - - quit if top bit is on
            _quif s                     ; - - ...
            _shl  EAX,1                 ; - - shift number left 1 bit
            _rcl  EDX,1                 ; - - ...
            dec   CX                    ; - - decrement exponent
          _endloop                      ; - endloop
        _endguess                       ; endguess
        mov     [EBX],EAX               ; store number
        mov     4[EBX],EDX              ; ...
        _shl    ECX,1                   ; get sign
        rcr     CX,1                    ; place in top bit
        mov     8[EBX],CX               ; ...
        pop     ECX                     ; restore ECX
        ret                             ; return
__FDLD  endp
;include 386ldfd.inc
;
; =========     ==              ======
;                               call exception_hndlr on overflow
        xdefp   __LDFD

;       convert long double to double
; input:
;       EAX - pointer to long double
; output:
;       EDX:EAX - double
;
__LDFD  proc    near
        push    ECX                     ; save ECX
        push    EBX                     ; save EBX
        push    ESI                     ; save ESI
        mov     CX,8[EAX]               ; get exponent and sign
        mov     EDX,4[EAX]              ; get fraction
        mov     EAX,[EAX]               ; ...
        mov     ESI,0FFFFF800h          ; get mask of bits to keep
        mov     EBX,EAX                 ; get bottom part
        shl     EBX,22                  ; get rounding bit
        _if     c                       ; if have to round
          _if   e                       ; - if half way between
            _shl  ESI,1                 ; - - adjust mask
          _endif                        ; - endif
          add   EAX,0800h               ; - round up
          adc   EDX,0                   ; - ...
          _if   c                       ; - if exponent needs adjusting
            mov   EDX,80000000h         ; - - set fraction
            inc   CX                    ; - - increment exponent
            ;  check for overflow
          _endif                        ; - endif
        _endif                          ; endif
        and     EAX,ESI                 ; mask off bottom bits
        mov     EBX,ECX                 ; save exponent and sign
        and     CX,7FFFh                ; if number not 0
        add     CX,03FFh-3FFFh          ; change bias to double format
        _guess                          ; guess: number not too large or -ve
          cmp   CX,07FFh                ; - quit if too large or -ve
          _quif ae                      ; - ...
          _guess                        ; - guess: DENORMAL
            or    CX,CX                 ; - - quit if normal
            _quif ne                    ; - - ...
            shrd  EAX,EDX,12            ; - - drop 12 bits off the bottom
            _shl  EDX,1                 ; - - get rid of implied 1 bit
            shr   EDX,12                ; - - shift right 12
          _admit                        ; - admit: NORMAL
            shrd  EAX,EDX,11            ; - - drop 11 bits off the bottom
            _shl  EDX,1                 ; - - get rid of implied 1 bit
            shrd  EDX,ECX,11            ; - - copy exponent into high part
          _endguess                     ; - endguess
          _shl  BX,1                    ; - get sign
          rcr   EDX,1                   ; - shift into result
        _admit                          ; guess: underflow or denormal
          cmp   CX,0C400h               ; - quit if overflow
          _quif b                       ; - ...
          cmp   CX,-52                  ; - if in the denormal range
          _if   ge                      ; - then
            sub   CX,12                 ; - - adjust exponent for 12 more shifts
            neg   CX                    ; - - negate shift count
            cmp   CL,32                 ; - - if at least 32 bits
            _if   ae                    ; - - then
              sub   CL,32               ; - - - adjust shift count
              mov   ESI,EAX             ; - - - shift right 32
              mov   EAX,EDX             ; - - - ...
              sub   EDX,EDX             ; - - - ...
            _endif                      ; - - endif
            shrd  ESI,EAX,CL            ; - - get the bits from the bottom
            shrd  EAX,EDX,CL            ; - - shift right
            shr   EDX,CL                ; - - ...
            add   ESI,ESI               ; - - round up
            adc   EAX,0                 ; - - ...
            adc   EDX,0                 ; - - ...
          _else                         ; - else
            sub   EAX,EAX               ; - - set result to 0
            sub   EDX,EDX               ; - - ...
          _endif                        ; - endif
        _admit                          ; admit: OVERFLOW
          shrd  EAX,EDX,11              ; - drop 11 bits off the bottom
          _shl  EDX,1                   ; - get rid of implied 1 bit
          shr   EDX,11                  ; - copy exponent into high part
          _shl  BX,1                    ; - get sign
          rcr   EDX,1                   ; - shift into result
          or    EDX,7FF00000h           ; - set exponent
          cmp   CX,43FFh                ; - quit if infinity or NaN
          _quif e                       ; - ...
          push  EAX                     ; - save EAX
          mov   AL,SW_OE                ; - get OVERFLOW mask
          mov   AH,FPE_OVERFLOW         ; - set OVERFLOW exception code
          call  __Exception_HNDLR       ; - set OVERFLOW exception
          pop   EAX                     ; - restore EAX
        _endguess                       ; endguess
        pop     ESI                     ; restore ESI
        pop     EBX                     ; restore EBX
        pop     ECX                     ; restore ECX
        ret                             ; return
__LDFD  endp

        endmod
        end

⌨️ 快捷键说明

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