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 + -
显示快捷键?