fpe87.asm
来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 556 行 · 第 1/2 页
ASM
556 行
shl si,1 ; - ...
add si,__ThreadData ; - get pointer to thread data
mov es,__ThreadData+2 ; - ...
les si,[si] ; - ...
xchg ax,es:[si] ; - set new stack low, and get old one
push ax ; - save current stack low
mov ax,cx ; - set floating point status
call __FPE_handler ; - call user's handler
pop es:[si] ; - restore stack low
else
push _STACKLOW ; - save current stack low
mov _STACKLOW,AX ; - set new stack low
mov AX,CX ; - set floating point status
call __FPE_handler ; - call user's handler
pop _STACKLOW ; - restore old stack low value
endif
mov SS,SaveSS ; - restore stack pointer
mov SP,SaveSP ; - ...
_endguess ; endguess
fclex ; clear exceptions that may have
; occurred as a result of handling the
; exception
and word ptr ENV_CW[BP],0FF72h
fldcw word ptr ENV_CW[BP] ; enable interrupts
pop ES ; restore registers
pop DS ; ...
pop DI ; ...
pop SI ; ...
pop DX ; ...
pop CX ; ...
pop BX ; ...
pop AX ; ...
fwait ; make sure 80x87 is ready
add SP,ENV_SIZE ; clean up stack
pop BP ; ...
ifdef __OS2__
add SP,2 ; OS/2 stored the FP status word on stack!
endif
iret ; return from interrupt handler
endproc __FPEHandler
; Process invalid operation.
InvalidOp proc near
mov CX,FPE_INVALID ; assume invalid operation
_guess ; guess: it's square root
cmp BX,0d9fah ; - ...
_quif ne ; - quit if it's not that instruction
mov CX,FPE_SQRTNEG ; - indicate divide by zero
_admit ; guess: 'fprem' instruction
cmp BX,0D9F8h ; - check for 'fprem' 10-may-90
_if ne ; - if not 'fprem'
cmp BX,0D9F5h ; - - check for 'fprem1'
_endif ; - endif
_quif ne ; - quit if not 'fprem' or 'fprem1'
_admit ; guess: integer overflow
mov DX,BX ; - save op code
and DX,0310h ; - check for fist/fistp instruction
cmp DX,0310h ; - ...
_quif ne ; - quit if its not that instruction
call KOIntOFlow ; - process integer overflow exception
_admit ; guess: it's floating point underflow
mov DX,BX ; - save op code
and DX,0110h ; - check if fst or fstp instruction
cmp DX,0110h ; - ...
_quif ne ; - quit if it's not that instruction
; Destination is short or long real and source register is an unnormal
; with exponent in range.
fstp ST(0) ; - pop old result
fldz ; - load zero
mov DX,BX ; - save op code
and DX,00C0h ; - check the MOD bits of instruction
cmp DX,00C0h ; - ...
_if ne ; - if result to be placed in memory
call Store ; - - store result in memory
_endif ; - endif
test BX,0008h ; - check if result to be popped
_if ne ; - if result to be popped
fstp ST(0) ; - - pop the result
_endif ; - endif
mov CX,FPE_UNDERFLOW ; - indicate underflow
_admit ; guess: it's divide
mov DX,BX ; - save op code
and DX,0130h ; - check for fdiv/fidiv instruction
cmp DX,0030h ; - ...
_quif ne ; - quit if it's not that instruction
mov DX,ENV_TW[BP] ; - get tag word
mov CL,AH ; - get stack pointer
and CL,38h ; - ...
shr CL,1 ; - ...
shr CL,1 ; - ...
ror DX,CL ; - make stack top low order bits
and DX,0005h ; - check if top two elements are 0
cmp DX,0005h ; - ...
_quif ne ; - quif if they are not 0
mov CX,FPE_ZERODIVIDE ; - indicate divide by zero
_endguess ; endguess
ret
endproc InvalidOp
; Process integer overflow exception.
KOIntOFlow proc near
push BX ; save BX
push DI ; save DI
push BP ; save base pointer
sub SP,10 ; allocate temporary
mov BP,SP ; point to temporary
fld ST(0) ; duplicate result
fstp tbyte ptr [BP] ; get value
fwait ; wait for store to complete
pop DX ; get value into registers
pop CX ; ...
pop BX ; ...
pop AX ; ...
pop DI ; ...
pop BP ; restore base pointer
mov SI,DI ; save sign
and DI,7fffh ; clear sign bit
sub DI,3ffeh ; remove bias
neg DI ; compute 64 - exponent
add DI,64 ; ...
_loop ; loop
or DI,DI ; - check for 0 shift count
_quif le ; - quit if shift count 0
shr AX,1 ; - shift mantissa into integer
rcr BX,1 ; - ...
rcr CX,1 ; - ...
rcr DX,1 ; - ...
dec DI ; - decrement shift count
_endloop ; endloop
_loop ; loop
or DI,DI ; - check for 0 shift count
_quif ge ; - quit if shift count 0
shl DX,1 ; - shift mantissa into integer
rcl CX,1 ; - ...
rcl BX,1 ; - ...
rcl AX,1 ; - ...
inc DI ; - decrement shift count
_endloop ; endloop
or SI,SI ; check sign
_if s ; if negative
not CX ; - negate integer
neg DX ; - ...
sbb CX,-1 ; - ...
_endif ; endif
pop DI ; restore DI
mov ES:[DI],DX ; store low order 16 bits
pop BX ; restore BX
test BX,0400h ; check if 32 or 16 bit integer
_if e ; if 32 bit integer
mov ES:2[DI],CX ; - store high order 16 bits
_endif ; endif
test BX,0008h ; check if result to be popped
_if ne ; if 32 bit integer
fstp ST(0) ; - pop the result
_endif ; endif
ret ; return
endproc KOIntOFlow
; Process overflow exception (note that only floating point overflows
; are handled - integer overflows are invalid operations).
KOOverFlow proc near
_guess ; guess: fscale instruction 10-may-90
cmp BX,0D9FDh ; - quit if not 'fscale' instruction
_quif ne ; - ...
_admit ; guess: fst/fstp instruction
mov DX,BX ; - save op code
and DX,0110h ; - check if fst or fstp instruction
cmp DX,0110h ; - ...
_quif ne ; - quit if not an fst/fstp instr.
call GetInf ; - load infinity
mov DX,BX ; - save op code
and DX,00C0h ; - check the MOD bits of instruction
cmp DX,00C0h ; - ...
_if ne ; - if result to be placed in memory
call Store ; - - store infinity
_endif ; - endif
test BX,0008h ; - check if result to be popped
_if ne ; - if result to be popped
fstp ST(0) ; - - pop result
_endif ; - endif
_admit ; admit arithmetic operation
mov DX,BX ; - save op code
and DX,00C0h ; - check if both operands on stack
cmp DX,00C0h ; - ...
_quif ne ; - quif both operands not on stack
;
; This code handles overflow on the following intructions:
; fxxx ST,ST(i)
; fxxx ST(i),ST where xxx is one of mul,div,sub or add
; fxxxp ST(i),ST
;
mov SI,offset DGROUP:TInf ; - load internal infinity
call Load ; - ...
_admit ; admit
;
; This admit block is to handle overflow on the following intructions:
; fxxx short real
; fxxx long real where xxx is one of mul,div,sub or add
;
call GetInf ; - load infinity
_endguess ; endguess
ret ; return
endproc KOOverFlow
; Replace the top element of the stack with the appropriate signed
; infinity.
GetInf proc near
ftst ; get sign of result
fstsw word ptr ENV_OP[BP]
fstp ST(0) ; pop argument off stack (does fwait)
test BX,0400h ; check if single or double
_if ne ; if double
fld qword ptr F8Inf ; - load single precision infinity
_else ; else
fld dword ptr F4Inf ; - load single precision infinity
_endif ; endif
test word ptr ENV_OP[BP],ST_C0
_if ne ; if argument is negative
fchs ; - return negative infinity
_endif ; endif
ret ; return
endproc GetInf
; Replace an element on the stack with internal zero or infinity.
Load proc near
test BX,0400h ; check if result is top element
_if e ; if result is not top element
sub DX,DX ; - indicate we are at the top
_else ; else
mov DX,BX ; - get st(i)
and DX,0007h ; - . . .
_endif ; endif
push DX ; save st(i)
_loop ; loop
dec DX ; - decrement counter
or DX,DX ; - are we at st(i)?
_quif e ; - quit if we are at st(i)
fincstp ; - increment stack pointer
_endloop ; endloop
ffree ST(0) ; free the stack element
fld tbyte ptr [SI] ; load internal zero
pop DX ; get st(i)
_loop ; loop
dec DX ; - decrement counter
or DX,DX ; - are we at st(i)?
_quif e ; - quit if we are at st(i)
fdecstp ; - decrement stack pointer
_endloop ; endloop
ret ; return
endproc Load
; Store the top element of the stack at ES:DI.
Store proc near
test BX,0400h
_if ne ; if double
fst qword ptr ES:[DI]; - store zero
_else ; else
fst dword ptr ES:[DI]; - store zero
_endif ; endif
ret ; return
endproc Store
endmod
end
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?