fpe87.asm
来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 556 行 · 第 1/2 页
ASM
556 行
;*****************************************************************************
;*
;* Open Watcom Project
;*
;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;* ========================================================================
;*
;* This file contains Original Code and/or Modifications of Original
;* Code as defined in and that are subject to the Sybase Open Watcom
;* Public License version 1.0 (the 'License'). You may not use this file
;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;* provided with the Original Code and Modifications, and is also
;* available at www.sybase.com/developer/opensource.
;*
;* The Original Code and all software distributed under the License are
;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;* NON-INFRINGEMENT. Please see the License for the specific language
;* governing rights and limitations under the License.
;*
;* ========================================================================
;*
;* Description: 80x87 interrupt handler.
;*
;*****************************************************************************
.8087
.286
include struct.inc
include mdef.inc
include stword.inc
include env87.inc
include fstatus.inc
_emu_init_start segment word public 'EMU'
_emu_init_start ends
_emu_init_end segment word public 'EMU'
_emu_init_end ends
DGROUP group _emu_init_start,_emu_init_end
modstart fpe87
datasegment
extrn __8087 : byte
ifdef __MT__
extrn __threadid : dword
extrn "C",__ThreadData: word
else
extrn "C",_STACKLOW : word
endif
extrn "C",__FPE_handler: dword
ifndef __OS2__
extrn "C",__FPE_int : byte ; defined in \clib\math\c\fpeint.c
endif
TInf db 00h,00h,00h,00h,00h,00h,00h,80h,0ffh,7fh
F8Inf db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,0efh,7fh
F4Inf db 0ffh,0ffh,7fh,7fh
enddata
bss_segment
STACK_SIZE equ 512
db (STACK_SIZE) dup(?)
FPEStk label byte
SaveSS dw 1 dup(?)
SaveSP dw 1 dup(?)
endbss
ifndef __OS2__
Save87 dw 0
dw 0
endif
ifndef __OS2__
xdefp "C",__Init_FPE_handler
xdefp "C",__Fini_FPE_handler
endif
ifndef __OS2__
defp __Init_FPE_handler
_guess ; guess initialization required
cmp word ptr CS:Save87+2,0 ; - quit if already initialized
_quif ne ; - ...
cmp byte ptr __8087,0 ; - quit if no 80x87 present
_quif e ; - ...
push BP ; - save registers
push AX ; - save registers
push BX ; - ...
push DX ; - ...
push DS ; - ...
push ES ; - ...
mov AH,35h ; - get old interrupt handler
mov AL,__FPE_int ; - for INT 2 (INT 10 on NEC)
int 21h ; - ...
mov CS:Save87,BX ; - save old interrupt handler
mov CS:Save87+2,ES ; - ...
mov AH,25h ; - set new interrupt handler
mov AL,__FPE_int ; - for INT 2 (INT 10 on NEC)
push CS ; - set DS:DX to address of new handler
pop DS ; - ...
mov DX,offset __FPEHandler ; - ...
int 21h ; - ...
pop ES ; - restore registers
pop DS ; - ...
pop DX ; - ...
pop BX ; - ...
pop AX ; - ...
pop BP ; - ...
_endguess ; endguess
ret
endproc __Init_FPE_handler
defp __Fini_FPE_handler
_guess ; guess handler was initialized
cmp word ptr CS:Save87+2,0 ; - quit if not initialized
_quif e ; - ...
push AX ; - save registers
push DX ; - ...
push DS ; - ...
push BP ; - save BP
sub SP,2 ; - allocate space for control word
mov BP,SP ; - point to space for control word
fstcw word ptr [BP] ; - get control word
fwait ; - ...
mov byte ptr [BP],7Fh ; - disable exception interrupts
fldcw word ptr [BP] ; - ...
fwait ; - ...
add SP,2 ; - remove temporary
mov AH,25h ; - restore old interrupt handler
mov AL,__FPE_int ; - for INT 2 (INT 10 on NEC)
mov DS,CS:Save87+2 ; - get address of old handler
mov DX,CS:Save87 ; - ...
int 21h ; - ...
pop BP ; - restore BP
pop DS ; - restore registers
pop DX ; - ...
pop AX ; - ...
_endguess ; endguess
ret
endproc __Fini_FPE_handler
endif
; Interrupt handler for 80x87 exceptions.
xdefp __FPEHandler
__FPEHandler proc far
push BP ; allocate room on stack for 80x87
sub SP,ENV_SIZE ; ... environment information
mov BP,offset DGROUP:_emu_init_end ; see if we have an emulator
cmp BP,offset DGROUP:_emu_init_start ; ...
mov BP,SP ; point to buffer for 80x87 environment
_if ne ; if we have an emulator
fstenv [BP] ; - get 80x87 environment
_else ; else
fnstenv [BP] ; - get 80x87 environment
_endif ; endif
fwait ; wait for 80x87
ifndef __OS2__
test word ptr ENV_SW[BP],ST_EF_ES
; check if 80x87 interrupted
_if e ; if interrupt not caused by 80x87
add SP,ENV_SIZE ; - restore stack
pop BP ; - ...
push CS:Save87+2 ; - invoke old interrupt handler
push CS:Save87 ; - ...
ret ; - ...
_endif ; endif
endif
push AX ; save regs
push BX ; ...
push CX ; ...
push DX ; ...
push SI ; ...
push DI ; ...
push DS ; ...
push ES ; ...
;fclex ; clear exceptions
fdisi ; disable interrupts
ifndef __OS2__
sti ; enable CPU interrupts
endif
mov AX,seg DGROUP ; get data segment
mov DS,AX ; ...
mov DX,ENV_CW[BP] ; get control word
not DX ; flip bits to get mask
mov DH,0FFh ; want to keep high bits
ifdef __OS2__
mov CX,ENV_SIZE+2[BP] ; get status word that OS/2 pushed
mov ES,ENV_IP+2[BP] ; get instruction pointer
mov DI,ENV_IP+0[BP] ; ...
_loop ; loop (skip over prefix bytes)
mov BX,ES:[DI] ; - get opcode
and BL,0F8h ; - see if 8087 opcode
cmp BL,0D8h ; - quit if it is
_quif e ; - ...
inc DI ; - point to next byte
_endloop ; endloop
mov BX,ES:[DI] ; get opcode
else
mov CX,ENV_SW[BP] ; get status word from fstenv
mov BX,ENV_IP+2[BP] ; get op code
and BH,7 ; ...
or BH,0D8h ; ...
endif
and DX,CX ; get status word
mov ES,ENV_OP+2[BP] ; get pointer to operand
mov DI,ENV_OP[BP] ; ...
mov CX,FPE_OK ; assume unrecognizeable error
_guess ; guess precision exception
test DL,ST_EF_PR ; - check for precision exception
_quif e ; - quit if not precision exception
mov CX,FPE_INEXACT ; - indicate precision exception
_admit ; guess invalid operation
test DL,ST_EF_IO ; - check for invalid operation
_quif e ; - quit if not invalid operation
call InvalidOp ; - process invalid operation
_admit ; guess denormal operand
test DL,ST_EF_DO ; - check for denormal operand
_quif e ; - quit if not denormal operand
mov CX,FPE_DENORMAL ; - indicate underflow
_admit ; guess overflow
test DL,ST_EF_OF ; - check for overflow
_quif e ; - quit if not overflow
call KOOverFlow ; - process overflow exception
mov CX,FPE_OVERFLOW ; - set floating point error code
_admit ; guess underflow
test DL,ST_EF_UF ; - check for underflow
_quif e ; - quit if not underflow
mov CX,FPE_UNDERFLOW ; - indicate underflow
_admit ; guess divide by 0
test DL,ST_EF_ZD ; - check for divide by zero
_quif e ; - quit if not divide by zero
mov CX,FPE_ZERODIVIDE ; - indicate divide by zero
_admit ; guess stack under/overflow
test DL,ST_EF_SF ; - check for stack under/overflow
_quif e ; - quit if not stack under/overflow
test DX,ST_C1 ; - check if underflow
_if e ; - if underflow
mov CX,FPE_STACKUNDERFLOW ; - - indicate stack underflow
_else ; - else
mov CX,FPE_STACKOVERFLOW ; - - indicate stack overflow
_endif ; - endif
_endguess ; endguess
_guess ok ; guess exception to be handled
test CX,CX ; - check if exception allowed
_quif e ; - quit if exception not allowed
mov AX,offset DGROUP:FPEStk - STACK_SIZE; - get new stack bottom
mov BX,DS ; - get new value for SS:SP
mov DX,offset DGROUP:FPEStk ; - ...
mov SI,SS ; - get current SS:SP
mov DI,SP ; - ...
cmp BX,SI ; - if might be using the FPEStk
_if e ; - then
cmp DI,DX ; - - check stack pointer
_if be ; - - if <= stack top
cmp DI,AX ; - - - check with stack bottom
_quif ae , ok ; - - - quit if FPEStk in use
_endif ; - - endif
_endif ; - endif
mov SaveSS,SS ; - save current stack pointer
mov SaveSP,SP ; - ...
mov SS,SI ; - get new stack pointer
mov SP,DX ; - ...
ifdef __MT__
les si,__threadid ; - get thread id
mov si,es:[si] ; - ...
shl si,1 ; - turn into index
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?