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