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