386fpemu.inc

来自「开放源码的编译器open watcom 1.6.0版的源代码」· INC 代码 · 共 1,702 行 · 第 1/5 页

INC
1,702
字号
ifdef __WIN387__
        _guess                          ; - guess: have to map in address
          cmp   cx,S_DS[ebp]            ; - - is it client's ds(/es/ss)?
          _quif e                       ; - - yes, use pre-calculated base
          cmp   cx,S_CS[ebp]            ; - - is it client's cs?
          _quif e                       ; - - yes, use pre-calculated base
          push  eax                     ; - - save eax
          movzx ecx,cx                  ; - - selector to map

          VxDcall3 _SelectorMapFlat, WINVMHandle, ecx, 0

          add   ebx,eax                 ; - - add base of selector to relative
                                        ;     offset from start of selector
          pop   eax                     ; - - restore eax
        _admit                          ; - admit: can use WINBase
          add   ebx,WINBase             ; - - shift address correctly!
        _endguess                       ; - endguess
        sub     esi,WINBase             ; - set to EIP within client's cs
        mov     S_EIP[ebp],esi          ; - save it
else
        mov     S_EIP[ebp],esi          ; - zap return address
endif
        mov     esi,ebx                 ; - get address

        mov     bl,ah                   ; - get r/m bits again
        and     ebx,038H                ; - isolate opcode portion     0RRR000
        or      bl,al                   ; - or in other part of opcode 0RRRooo

        getsavearea

        get_st0                         ; get st*10 into edi
      ifdef SEGMENTED
        jmp     dword ptr cs:memop[ebx*4];- emulate the instruction
      else
        jmp     dword ptr    memop[ebx*4];- emulate the instruction
      endif

luup:   mov     al,[esi]                ; get possible prefix in al
        cmp     al,9Bh                  ; check for "fwait"
        ja      endlup                  ; ... go check for possible prefix
prefix_byte: je short inc_esi           ; skip over "fwait" opcode
        cmp     al,26h                  ; check for "es:"
        je      short is_es             ; - continue with next byte
        cmp     al,2Eh                  ; if its cs:
        je      short is_cs             ; - record cs in dx and continue
        cmp     al,36H                  ; if its ss:
        je      short is_ss             ; - record ss in dx and continue
        cmp     al,3EH                  ; if its ds:
        je      short is_ds             ; - record ds in dx and continue
        cmp     al,64H                  ; if its fs:
        je      short is_fs             ; - record fs in dx and continue
        cmp     al,65H                  ; if its gs:
        je      short is_gs             ; - record gs in dx and continue
        cmp     al,66H                  ; if its operand length
        je      short inc_esi           ; - continue with next byte
        cmp     al,67H                  ; if its address length
        jne     endlup                  ; - its not handled!!!!
inc_esi:inc     esi                     ; just bump past prefix
        jmp     short luup              ;
is_cs:  mov     cx,S_CS[ebp]
        mov     edx,ecx                 ;
        inc     esi                     ; bump past prefix
        jmp     short luup              ;
is_ds:  mov     cx,S_DS[ebp]
        mov     edx,ecx                 ;
        inc     esi                     ; bump past prefix
        jmp     short luup              ;
is_ss:  mov     cx,S_SS[ebp]            ;
        mov     edx,ecx                 ;
        inc     esi                     ; bump past prefix
        jmp     short luup              ;
is_es:  mov     cx,S_ES[ebp]            ;
        mov     edx,ecx                 ;
        inc     esi                     ; bump past prefix
        jmp     short luup              ;
is_fs:
        ifdef __WIN387__
          mov   cx,S_FS[ebp]
        else
          mov   cx,fs                   ;
        endif
        mov     edx,ecx                 ;
        inc     esi                     ; bump past prefix
        jmp     short luup              ;
is_gs:
        ifdef __WIN387__
          mov   cx,S_GS[ebp]
        else
          mov   cx,gs                   ;
        endif
        mov     edx,ecx                 ;
        inc     esi                     ; bump past prefix
        jmp     short luup              ;


calc_st0:
calc_sti:

stkins:                                 ; else

        ifdef __WIN387__
          sub   esi,WINBase             ; - set to addr in client
          mov   S_EIP[ebp],esi          ; - save it
        else
          mov   S_EIP[ebp],esi          ; - zap return address
        endif

        getsavearea

;       al has bottom 3 bits of opcode
;       ah has modrm bytes

        mov     dl,ah                   ; - get modrm byte           mmRRRrrr
        and     edx,038H                ; - isolate opcode portion   00RRR000
        or      dl,al                   ; - + other part of opcode   00RRRooo

      ifdef SEGMENTED
        mov     edi,dword ptr ds:[ebp].stktop;- di gets index of top of stack
      else
        mov     edi,dword ptr    [ebp].stktop;- di gets index of top of stack
      endif
;;    ifdef SEGMENTED
;;      mov     edi,dword ptr ds:[ebp].status;- di gets index of top of stack
;;    else
;;      mov     edi,dword ptr    [ebp].status;- di gets index of top of stack
;;    endif
;;      and     edi,SW_ST               ; - ...
;;      shr     edi,SW_ST_SHIFT         ; - ...
        mov     bl,ah                   ; - get the "i" from ST(I)   mmRRRrrr
        and     ebx,7                   ; - ...
;;      mov     esi,ebx                 ; - ...
;;      add     esi,edi                 ; - add to top of stack
        movzx   esi,TENTBL[edi].t_regnum; - get top of stack reg #
        add     esi,ebx                 ; - plus "i"
        and     esi,7                   ; - - modulo 7
;;      lea     edi,[edi+edi*4]         ; - multiply ST index by 10
;;      add     edi,edi                 ; - ...
        lea     esi,[esi+esi*4]         ; - multiply ST(i) index by 10
        add     esi,esi                 ; - ...
      ifdef SEGMENTED
        jmp    dword ptr cs:stkop[edx*4]; - execute the instruction
      else
        jmp    dword ptr    stkop[edx*4]; - execute the instruction
      endif

exit99:
;
; save updated stack top
;
        ifdef __WIN387__
          pop   EBP                     ; restore EBP
        endif
        ret                             ; return from emulation

p_single:                               ; round result to single precision
        lea     EBX,[edi+ebp].fpstack   ; point to stack top
        mov     EDX,0FFFFFF00h          ; get mask of bits to keep
        mov     EAX,4[EBX]              ; get top part
        shl     EAX,25                  ; get rounding bit
        _if     c                       ; if have to round
          _if   e                       ; - if half way between
            cmp   dword ptr [EBX],0     ; - - if bottom part is also 0
            _if   e                     ; - - then (half way)
              _shl  EDX,1               ; - - - adjust mask
            _endif                      ; - - endif
          _endif                        ; - endif
          add   dword ptr 4[EBX],0100h  ; - round up
          _if   c                       ; - if exponent needs adjusting
            mov   dword ptr 4[EBX],80000000h; - - set fraction
            inc   word ptr 8[EBX]       ; - - increment exponent
            ;  check for overflow
          _endif                        ; - endif
        _endif                          ; endif
        and     4[EBX],EDX              ; mask off bottom bits
        mov     dword ptr [EBX],0       ; zero the bottom part
        jmp     exit                    ; exit

p_double:                               ; round result to double precision
        lea     EBX,[edi+ebp].fpstack   ; point to stack top
        mov     EDX,0FFFFF800h          ; get mask of bits to keep
        mov     EAX,[EBX]               ; get bottom part
        shl     EAX,22                  ; get rounding bit
        _if     c                       ; if have to round
          _if   e                       ; - if half way between
            _shl  EDX,1                 ; - - adjust mask
          _endif                        ; - endif
          add   dword ptr [EBX],0800h   ; - round up
          adc   dword ptr 4[EBX],0      ; - ...
          _if   c                       ; - if exponent needs adjusting
            mov   dword ptr 4[EBX],80000000h; - - set fraction
            inc   word ptr 8[EBX]       ; - - increment exponent
            ;  check for overflow
          _endif                        ; - endif
        _endif                          ; endif
        and     [EBX],EDX               ; mask off bottom bits
        jmp     exit                    ; exit

saveflg_popstk_exit:
        saveflg
popstk_exit:
        popstk
        jmp     exit

saveflg_exit:
        saveflg
        jmp     exit


        xdefp   F8DivZero

F8DivZero proc  near
        mov     AL,SW_ZE                ; indicate zero divide
        mov     AH,FPE_ZERODIVIDE       ; ...
        call    __Exception_HNDLR       ; process exception
        ret                             ; return
F8DivZero endp

        xdefp   F8InvalidOp
F8InvalidOp proc near
        mov     AL,SW_IE                ; indicate invalid operation
        mov     AH,FPE_INVALID          ; ...
        call    __Exception_HNDLR       ; process exception
        ret                             ; return
F8InvalidOp endp

        xdefp   F8OverFlow
F8OverFlow proc near
        mov     AL,SW_OE                ; get OVERFLOW mask
        mov     AH,FPE_OVERFLOW         ; set OVERFLOW exception code
        call    __Exception_HNDLR       ; process exception
        ret                             ; return
F8OverFlow endp

        xdefp   __Exception_HNDLR
;
;  input:
;       AL - exception mask
;       AH - exception code
;
__Exception_HNDLR proc  near
      ifdef SEGMENTED
        or      byte ptr ds:[ebp].status,AL   ; indicate exception occurred
        test    byte ptr ds:[ebp].control,AL  ; if exception unmasked
      else
        or      byte ptr    [ebp].status,AL   ; indicate exception occurred
        test    byte ptr    [ebp].control,AL  ; if exception unmasked
      endif
ifndef __WIN387__
        _if     e                       ; then
          push  ESI                     ; - save registers
          push  EDI                     ; - ...
          push  ECX                     ; - ...
          push  ES                      ; - ...
          push  DS                      ; - ...
          sub   ESP,NDP_SIZE            ; - allocate space for copy of 387
          mov   CX,SS                   ; - set ES=SS
          mov   ES,CX                   ; - ...
          mov   ESI,EBP                 ; - point to current copy
          mov   EDI,ESP                 ; - point to temporary save area
          mov   ECX,108/4               ; - number of dwords to copy
          cld                           ; - make sure forward direction
          rep   movsd                   ; - copy it
          movzx EAX,AH                  ; - get exception code  21-jul-90
if _OS eq _QNX
          call  __FPEhandler            ; - jump to SIGFPE handler rtn
else
          call  __FPE_exception_        ; - jump to SIGFPE handler rtn
endif
          mov   CX,DS                   ; - set ES=DS
          mov   ES,CX                   ; - ...
          mov   CX,SS                   ; - set DS=SS
          mov   DS,CX                   ; - ...
          mov   EDI,EBP                 ; - point to current copy
          mov   ESI,ESP                 ; - point to temporary save area
          mov   ECX,108/4               ; - number of dwords to copy
          cld                           ; - make sure forward direction
          rep   movsd                   ; - copy it
          add   ESP,NDP_SIZE            ; - deallocate space
          pop   DS                      ; - restore registers
          pop   ES                      ; - ...
          pop   ECX                     ; - ...
          pop   EDI                     ; - ...
          pop   ESI                     ; - ...
        _endif                          ; endif
endif
        ret                             ; return
__Exception_HNDLR endp

;===========================MOD/RM calculations=================================
; NB: 16 bit addressing modes are NYI

DOMODRM macro   disp,reg1
        IFIDN   <disp>,<D0>                     ; if D0
        xor     EBX,EBX                         ; - start ea at 0
        ELSE                                    ; else
        IFIDN   <disp>,<D8>                     ; - if D8
        movsx   EBX,byte ptr [ESI]              ; - - start it off at D8
        inc     ESI                             ; - - bump past displacement
        ELSE                                    ; - else
        .ERRDIF <disp>,<D32>                    ; - - it must be D32
        mov     EBX,dword ptr [ESI]             ; - - pick up D32
        add     ESI,4
        ENDIF                                   ; - endif
        ENDIF                                   ; endif
        IFNB    <reg1>                          ; if there's a register
        add     EBX,&reg1[ebp]                  ; - add the register in too
        IFIDN   <reg1>,<S_EBP>                  ; - if register is EBP
        mov     ecx,edx                         ; - - get segment for [EBP]
        ENDIF                                   ; - endif
        IFIDN   <reg1>,<S_ESP>                  ; - if register is ESP
        mov     ecx,edx                         ; - - get segment for [EBP]
        ENDIF                                   ; - endif
        ENDIF                                   ; endif
        ret                                     ; return to caller
        endm                                    ; nice macro eh?

m00000: DOMODRM D0,S_EAX                        ; mod r/m byte actions
m00001: DOMODRM D0,S_ECX
m00010: DOMODRM D0,S_EDX
m00011: DOMODRM D0,S_EBX
s00100: DOMODRM D0,S_ESP
m00101: DOMODRM D32
m00110: DOMODRM D0,S_ESI
m00111: DOMODRM D0,S_EDI
m01000: DOMODRM D8,S_EAX
m01001: DOMODRM D8,S_ECX
m01010: DOMODRM D8,S_EDX
m01011: DOMODRM D8,S_EBX
s01100: DOMODRM D8,S_ESP
m01101: DOMODRM D8,S_EBP
m01110: DOMODRM D8,S_ESI
m01111: DOMODRM D8,S_EDI
m10000: DOMODRM D32,S_EAX
m10001: DOMODRM D32,S_ECX
m10010: DOMODRM D32,S_EDX
m10011: DOMODRM D32,S_EBX
s10100: DOMODRM D32,S_ESP
m10101: DOMODRM D32,S_EBP
m10110: DOMODRM D32,S_ESI
m10111: DOMODRM D32,S_EDI

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?