chipr16.asm

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

ASM
883
字号
        fnstenv [bp]
        and     [bp].STATUS_WORD, 0bcffh
        or      [bp].STATUS_WORD, ax
        fldenv  [bp]
        add     sp, ENV_SIZE
rem_exit:
        pop     bp
        pop     cx
        pop     bx
        pop     ax
        CHECKSW                         ; debug only: save status
        ret
fprem_common    ENDP


comment ~**************************************************************
;
; float _frem_chk (float numer, float denom)
;
        public  _frem_chk
_frem_chk       PROC    FAR
        push    dx
        push    bp
        sub     sp, STACK_SIZE
        mov     bp, sp
        fld     dword ptr [STACK_SIZE+8+bp]
        fstp    tbyte ptr [NUMER+bp]
        fld     dword ptr [STACK_SIZE+12+bp]
        fstp    tbyte ptr [DENOM+bp]
        mov     dx, 0                   ; dx = 1 if denormal extended divisor
        call    fprem_common

        fstp    dword ptr [__fprem_result]
        mov     dx,ds
        mov     ax, offset __fprem_result

        fstp    st                      ; clean FP stack
        add     sp, STACK_SIZE
        pop     bp
        pop     dx
        ret
_frem_chk       ENDP
; end _frem_chk

;
; double _drem_chk (double numer, double denom)
;
        public  _drem_chk
_drem_chk       PROC    FAR
        push    dx
        push    bp
        sub     sp, STACK_SIZE
        mov     bp, sp
        fld     qword ptr [STACK_SIZE+8+bp]
        fstp    tbyte ptr [NUMER+bp]
        fld     qword ptr [STACK_SIZE+16+bp]
        fstp    tbyte ptr [DENOM+bp]
        mov     dx, 0                   ; dx = 1 if denormal extended divisor
        call    fprem_common
        fstp    qword ptr [__fprem_result]
        mov     dx,ds
        mov     ax, offset __fprem_result
        fstp    st                      ; clean FP stack
        add     sp, STACK_SIZE
        pop     bp
        pop     dx
        ret

_drem_chk       ENDP
; end drem_chk

;
; long double _lrem_chk(long double number,long double denom)
;
        public  _lrem_chk
_lrem_chk       PROC    NEAR
        push    bp
        mov     bp, sp
        fld     tbyte ptr [16+bp]       ; assumes long double push
                                        ; is 10 bytes, 18 = 8 + long double push                                        ; size.
        fld     tbyte ptr [6+bp]
        call    _fprem_chk
        fxch
        fstp    st
        pop     bp
        ret
_lrem_chk       ENDP
***********************************************************************~

;
; FPREM: ST = remainder(ST, ST(1))
;
; Compiler version of the FPREM must preserve the arguments in the floating
; point stack.

        public  __fprem_chk
        defpe   __fprem_chk
        push    dx
        push    bp
        sub     sp, STACK_SIZE
        mov     bp, sp
        fstp    tbyte ptr [NUMER+bp]
        fstp    tbyte ptr [DENOM+bp]
        xor     dx, dx
; prem_main_routine begin
        mov     ax,[DENOM+8+bp]         ; exponent
        test    ax,07fffh               ; check for denormal
        jz      denormal
        call    fprem_common
        add     sp, STACK_SIZE
        pop     bp
        pop     dx
        ret

denormal:
        fld     tbyte ptr [DENOM+bp]    ; load the denominator
        fld     tbyte ptr [NUMER+bp]    ; load the numerator
        mov     eax, dword ptr[DENOM+bp]        ; test for whole mantissa == 0
        or      eax, dword ptr[DENOM+4+bp]      ; test for whole mantissa == 0
        jz      remainder_hardware_ok_l ; denominator is zero
        fxch
        fstp    tbyte ptr[bp + DENOM_SAVE]      ; save org denominator
        fld     tbyte ptr[bp + DENOM]
        fxch
        or      dx, 02h
;
; For this we need pc=80.  Also, mask exceptions so we don't take any
; denormal operand exceptions.  It is guaranteed that the descaling
; later on will take underflow, which is what the hardware would have done
; on a normal fprem.
;
        fnstcw  [PREV_CW+bp]            ; save caller's control word
        mov     ax, [PREV_CW+bp]
        or      ax, 0033fh              ; mask exceptions, pc=80
        mov     [PATCH_CW+bp], ax
        fldcw   [PATCH_CW+bp]           ; mask exceptions & pc=80

; The denominator is a denormal.  For most numerators, scale both numerator
; and denominator to get rid of denormals.  Then execute the common code
; with the flag set to indicate that the result must be de-scaled.
; For large numerators this won't work because the scaling would cause
; overflow.  In this case we know the numerator is large, the denominator
; is small (denormal), so the exponent difference is also large.  This means
; the rem_large code will be used and this code depends on the difference
; in exponents modulo 64.  Adding 64 to the denominators exponent
; doesn't change the modulo 64 difference.  So we can scale the denominator
; by 64, making it not denormal, and this won't effect the result.
;
; To start with, figure out if numerator is large

        mov     ax, [bp + NUMER + 8]    ; load numerator exponent
        and     ax, 7fffh               ; isolate numerator exponent
        cmp     ax, 7fbeh               ; compare Nexp to Maxexp-64
        ja      big_numer_rem_de        ; jif big numerator

; So the numerator is not large scale both numerator and denominator

        or      dx, 1                   ; dx = 1, if denormal extended divisor
        fmul    qword ptr one_shl_64    ; make numerator not denormal
        fstp    tbyte ptr[bp + NUMER]
        fmul    qword ptr one_shl_64    ; make denominator not denormal
        fstp    tbyte ptr[bp + DENOM]
        jmp     scaling_done

; The numerator is large.  Scale only the denominator, which will not
; change the result which we know will be partial.  Set the scale flag
; to false.
big_numer_rem_de:
        ; We must do this with pc=80 to avoid rounding to single/double.
        ; In this case we do not mask exceptions so that we will take
        ; denormal operand, as would the hardware.
        fnstcw  [PREV_CW+bp]            ; save caller's control word
        mov     ax, [PREV_CW+bp]
        or      ax, 00300h              ; pc=80
        mov     [PATCH_CW+bp], ax
        fldcw   [PATCH_CW+bp]           ; pc=80

        fstp    st                      ; Toss numerator
        fmul    qword ptr one_shl_64    ; make denominator not denormal
        fstp    tbyte ptr[bp + DENOM]

; Restore the control word which was fiddled to scale at 80-bit precision.
; Then call the common code.
scaling_done:
        fldcw   [bp + PREV_CW]          ; restore callers control word
        call    fprem_common
        add     sp, STACK_SIZE
        pop     bp
        pop     dx
        ret

remainder_hardware_ok_l:
        fprem                           ; and finally do a remainder

        CHECKSW

        add     sp, STACK_SIZE
        pop     bp
        pop     dx
        ret
__fprem_chk      ENDP
; end _fprem_chk

;
;       FPREM1 CODE BEGINS
;


fprem1_common   PROC    NEAR

        push    ax
        push    bx
        push    cx
        push    bp
        mov     bp, sp
        mov     ax, [MAIN_DENOM+6+bp]   ; high 16 bits of mantissa
        xor     ax, ONESMASK            ; invert bits that have to be one
        test    ax, ONESMASK            ; check bits that have to be one
        jnz     remainder1_hardware_ok
        shr     ax, 11
        and     ax, 0fh
        mov     bx, ax
        cmp     byte ptr fprem_risc_table[bx], 0     ; check for (1,4,7,a,d)
        jz      remainder1_hardware_ok

; The denominator has the bit pattern. Weed out the funny cases like NaNs
; before applying the software version. Our caller guarantees that the
; denominator is not a denormal. Here we check for:
;       denominator     inf, NaN, unnormal
;       numerator       inf, NaN, unnormal, denormal

        mov     ax, [MAIN_DENOM+8+bp]   ; exponent
        and     ax, 7fffh               ; mask the exponent only
        cmp     ax, 7fffh               ; check for INF or NaN
        je      remainder1_hardware_ok
        mov     ax, [MAIN_NUMER+8+bp]   ; exponent
        and     ax, 07fffh              ; mask the exponent only
        jz      remainder1_hardware_ok  ; jif numerator denormal
        cmp     ax, 07fffh              ; check for INF or NaN
        je      remainder1_hardware_ok
        mov     ax, [bp + MAIN_NUMER + 6]       ; high mantissa bits - numerator
        add     ax, ax                  ; set carry if explicit bit set
        jnz     remainder1_hardware_ok  ; jmp if numerator is unnormal
        mov     ax, [bp + MAIN_DENOM + 6] ; high mantissa bits - denominator
        add     ax, ax          ; set carry if explicit bit set
        jnz     remainder1_hardware_ok  ; jmp if denominator is unnormal
rem1_patch:
        mov     ax, [MAIN_DENOM+8+bp]   ; sign and exponent of y (denominator)
        and     ax, 07fffh              ; clear sy
        add     ax, 63                  ; evaluate ey + 63
        mov     bx, [MAIN_NUMER+8+bp]   ; sign and exponent of x (numerator)
        and     bx, 07fffh              ; clear sx
        sub     bx, ax                  ; evaluate the exponent difference (ex - ey)
        ja      rem1_large              ; if ex > ey + 63, case of large arguments
rem1_patch_loop:
        mov     ax, [MAIN_DENOM+8+bp]   ; sign and exponent of y (denominator)
        and     ax, 07fffh              ; clear sy
        add     ax, 10                  ; evaluate ey + 10
        mov     bx, [MAIN_NUMER+8+bp]   ; sign and exponent of x (numerator)
        and     bx, 07fffh              ; clear sx
        sub     bx, ax                  ; evaluate the exponent difference (ex - ey)
        js      remainder1_hardware_ok  ; safe if ey + 10 > ex
        fld     tbyte ptr [MAIN_NUMER+bp]   ; load the numerator
        mov     ax, [MAIN_DENOM+8+bp]   ; sign and exponent of y (denominator)
        mov     bx, [MAIN_NUMER+8+bp]   ; sign and exponent of x (numerator)
        and     bx, 07fffh              ; clear sx
        mov     cx, bx
        sub     bx, ax
        and     bx, 07h
        or      bx, 04h
        sub     cx, bx
        mov     bx, ax
        and     bx, 08000h              ; keep sy
        or      cx, bx                  ; merge the sign of y
        mov     word ptr [MAIN_DENOM+8+bp], cx
        fld     tbyte ptr [MAIN_DENOM+bp]   ; load the shifted denominator
        mov     word ptr [MAIN_DENOM+8+bp], ax  ; restore the initial denominator
        fxch
        fprem                           ; this rem is safe
        fstp    tbyte ptr [MAIN_NUMER+bp]       ; update the numerator
        fstp    st(0)                   ; pop the stack
        jmp rem1_patch_loop
rem1_large:
        test    dx, 02h                 ; is denominator already saved
        jnz     already_saved1
        fld     tbyte ptr[bp + MAIN_DENOM]
        fstp    tbyte ptr[bp + MAIN_DENOM_SAVE] ; save denominator
already_saved1:
        ; Save user's precision control and institute 80.  The fp ops in
        ; rem1_large_loop must not round to user's precision (if it is less
        ; than 80) because the hardware would not have done so.  We are
        ; aping the hardware here, which is all extended.

        fnstcw  [bp+MAIN_PREV_CW]       ; save caller's control word
        mov     ax, word ptr[bp + MAIN_PREV_CW]

⌨️ 快捷键说明

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