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