fpe86.inc

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

INC
1,454
字号
        mov     ax,ss                   ; put SS in DS
        mov     ds,ax                   ; ...
        mov     bp,sp                   ; get access to registers
        jmp     short _comint7          ; goto common code
;
;       come here for DPMI hosts (e.g. Windows 3.1)
;
        public  __DPMI_int7
__DPMI_int7:
        pusha                           ; save registers
        push    ds                      ; ...
        push    es                      ; ...
        lea     bx,my87                 ; ...
        mov     bp,sp                   ; get access to registers
        mov     ds,DPMI_SS[bp]          ; set ds = user's SS
else
        mov     ax,ss                   ; put SS in DS
        mov     ds,ax                   ; ...
        mov     bp,sp                   ; get access to registers
endif
_comint7:cld                            ; make sure forward direction
        mov     S_MY87[bp],bx           ; save offset of save area
        get_st0                         ; get offset of stack top in DI
p_extended:                             ; nothing to do
;
;       peek at next instruction to see if it is also an emulator interrupt
;
exit:   mov     bp,sp                   ; get access to saved registers
        mov     cx,S_DS[bp]             ; get default data segment
        mov     ax,ds                   ; segment register for [bp] reference
        getretaddr                      ; get return address

luup:   mov     dl,es:[si]              ; get possible prefix in al
        sub     dl,26H                  ; if its es:
        js      short endlup            ; if signed, then not a prefix byte
        je      short is_es             ; - continue with next byte
        cmp     dl,09BH-26H             ; check for "fwait" opcode
        je      inc_si                  ; - yes, just skip over it
        sub     dl,08H                  ; if its cs:
        je      short is_cs             ; - record cs in cx and continue
        sub     dl,08H                  ; if its ss:
        je      short is_ss             ; - record ss in cx and continue
        sub     dl,08H                  ; if its ds:
        je      short is_ds             ; - record ds in cx and continue
        sub     dl,26H                  ; if its fs:
        je      short is_fs             ; - record fs in cx and continue
        dec     dl                      ; if its gs:
        je      short is_gs             ; - record gs in cx and continue
        dec     dl                      ; if its operand length
        je      short inc_si            ; - continue with next byte
        dec     dl                      ; if its address length
        jne     short endlup            ; - its not handled!!!!
inc_si: inc     si                      ; just bump past prefix
        jmp     luup                    ;
is_cs:  mov     cx,S_CS[bp]
        mov     ax,cx                   ; segment for [bp]
        inc     si                      ; bump past prefix
        jmp     luup                    ;
is_ds:  mov     cx,S_DS[bp]
        mov     ax,cx                   ; segment for [bp]
        inc     si                      ; bump past prefix
        jmp     luup                    ;
is_ss:  mov     cx,ds                   ; (DS contains user's SS)
        mov     ax,cx                   ; segment for [bp]
        inc     si                      ; bump past prefix
        jmp     luup                    ;
is_es:  mov     cx,S_ES[bp]             ;
        mov     ax,cx                   ; segment for [bp]
        inc     si                      ; bump past prefix
        jmp     luup                    ;
is_fs:;;;  mov     cx,fs                   ;
        inc     si                      ; bump past prefix
        jmp     luup                    ;
is_gs:;;;  mov     cx,gs                   ;
        inc     si                      ; bump past prefix
        jmp     luup                    ;
endlup:                                 ; segment of memory operand in cx
        mov     dx,es:[si]              ; load up opcode + modrm
        inc     si                      ; point es:si at rest of instruction
        inc     si                      ; ...
        mov     bl,dl                   ; get opcode
        and     dl,07H                  ; get opcode (0-7) into dl
        and     bl,0F8h                 ; isolate top bits
        cmp     bl,0D8h                 ; if it is an 8087 opcode
        je      emulate                 ; then execute it
        jmp     exit99                  ; otherwise exit
__int7  endp

else    ; not __PROTMODE__
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       interrupt int34()               ; int 34h to int 3Bh all come here
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public  __int34
__int34 proc    near
        sti                             ; interrupts back on
        save_regs                       ; save registers (same order as pusha)
        mov     bp,sp                   ; get access to registers
        mov     cx,ds                   ; save data segment in CX
        cld                             ; make sure forward direction
        call    __GETDS                 ; point ds at "8087" save area
        lea     bx,my87                 ; ...
        mov     S_MY87[bp],bx           ; save offset of save area
        get_st0                         ; get offset of stack top in DI
        mov     ax,ss                   ; segment register for [bp] reference
        getretaddr                      ; get return address
        mov     dx,es:-1[si]            ; load up opcode + modrm
        inc     si                      ; point ds:si at rest of instruction
        and     dl,0FH                  ; get opcode (0-7) into dl
        sub     dl,4                    ; ... (was 34-3B)
        jmp     emulate                 ; go emulate instruction
__int34 endp


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;       interrupt int3c()               ; segment override present
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

public  __int3c
__int3c proc    near
        sti                             ; interrupts back on
        save_regs                       ; save registers (same order as pusha)
        mov     bp,sp                   ; get access to registers
        cld                             ; make sure forward direction
        call    __GETDS                 ; point ds at "8087" save area
        lea     bx,my87                 ; ...
        mov     S_MY87[bp],bx           ; save offset of save area
        get_st0                         ; get offset of stack top in DI
        getretaddr                      ; get return address
        mov     dh,es:[si]              ; load up opcode, seg override
        inc     si                      ; point ds:si at rest of instruction
next_int3c:
        mov     dl,dh                   ; get opcode + segment override
        mov     dh,es:[si]              ; get modrm byte
        inc     si                      ; ...
        mov     bl,dl                   ; get segment override
        _guess                          ; guess: load cx with segment register
          mov   cx,S_DS[bp]             ; - assume DS
          and   bl,0C0h                 ; - isolate segment override bits
          _quif e                       ; - quit if 00 (DS)
          mov   cx,S_CS[bp]             ; - assume CS (10)
          shl   bl,1                    ; - shift out top bit
          _quif e                       ; - quit if 10 (CS)
          mov   cx,ss                   ; - assume SS (01)
          _quif nc                      ; - quit if 01 (SS)
          mov   cx,S_ES[bp]             ; - it has to be ES (11)
        _endguess                       ; endguess
        mov     ax,cx                   ; segment register for [bp] reference
        and     dl,0FH                  ; get opcode (0-7) into al
        sub     dl,8                    ; ... was D8-DF
        jmp     short emulate           ; do the emulation
__int3c endp
endif

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;      AT THIS POINT ...
;;      DL      = OPCODE 0-7
;;      DH      = MODRM byte
;;      ES:SI   = pointer to rest of instruction (or next instruction)
;;      CX      = has the segment for a data reference (if any)
;;      AX      = segment register to be used for [bp] reference
;;      DI      = offset into 8087 register stack to stack top
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mem_inst:
        mov     bl,dh                   ; get mmxxxrrr bits in bl
        shr     bl,1                    ; ... 0mmxxxrr
        shr     bl,1                    ; ... 00mmxxxr
        shr     bl,1                    ; ... 000mmxxx
        and     bl,018H                 ; isolate them 000mm000
        mov     bh,dh                   ; get r/m bits in bh mmxxxrrr
        and     bh,7                    ; isolate them       00000rrr
        or      bl,bh                   ; glue them          000mmrrr
        mov     bh,0                    ; zero top byte
        shl     bx,1                    ; make it an index
        call    word ptr cs:modrm[bx]   ; do effective address calcn
        mov     S_IP[bp],si             ; zap return address
        mov     es,cx                   ; get segment for memory operand
        mov     si,ax                   ; get offset for memory operand
        mov     bl,dh                   ; get r/m bits again
        and     bl,038H                 ; isolate opcode portion
        or      bl,dl                   ; or in other part of opcode
        shl     bx,1                    ; make it an index
        mov     bp,S_MY87[bp]           ; point BP to save area
        push    word ptr cs:memop[bx]   ; emulate the instruction
        and     bl,0Eh                  ; get index for load routine
        jmp     word ptr cs:loadrtn[bx] ; load memory operand into temp

ifndef __PROTMODE__
next_instruction:
        mov     dx,es:1[si]             ; get next interrupt #, plus next byte
        add     si,3                    ; skip past these bytes
        sub     dl,34h                  ; make sure it is int 34h to 3ch
        cmp     dl,3ch-34h              ; ...
        je      next_int3c              ; if int 3ch, go handle it
        ja      exit99                  ; exit if not an emulator interrupt
        mov     ax,ss                   ; segment register for [bp] reference
        mov     cx,S_DS[bp]             ; get segment register for memory opnd
endif
;
;       fall into emulate for this instruction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;      AT THIS POINT ...
;;      DL      = OPCODE 0-7
;;      DH      = MODRM byte
;;      ES:SI   = pointer to rest of instruction (or next instruction)
;;      CX      = has the segment for a data reference (if any)
;;      AX      = segment register to be used for [bp] reference
;;      DI      = offset into 8087 register stack to stack top
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

emulate proc    near
        cmp     dh,0C0H                 ; if its a memory reference
        jb      mem_inst                ; then go execute it
        mov     S_IP[bp],si             ; zap return address
        mov     bp,S_MY87[bp]           ; point bp at "8087"
        mov     bl,dh                   ; get r/m bits again
        and     bx,038H                 ; isolate opcode portion
        or      bl,dl                   ; or in other part of opcode
        shl     bx,1                    ; make it an index
        jmp     word ptr cs:stkop1[bx]  ; jmp to prepare/emulation routine


_i_:    push    word ptr cs:stkop[bx]   ; push address of emulation routine
        mov     bl,dh                   ; get "i" from ST(i)
        and     bl,7                    ; ...
        mov     si,bx                   ; save "i" in si
        add     si,cs:tentab[di].t_regnum; calc. reg num of st(i)
        and     si,7                    ; modulo 8
        mov     cx,si                   ; save a copy
        add     si,si                   ; i times 2
        add     si,si                   ; times 4
        add     si,cx                   ; times 5
        add     si,si                   ; times 10
        _lea    ax,st                   ; point AX to st(0)
        _lea    dx,st(i)                ; point DX to st(i)
        mov     bx,ax                   ; result goes to st(0)
        ret                             ; return to emulation routine

_r_:    push    word ptr cs:stkop[bx]   ; push address of emulation routine
        mov     bl,dh                   ; get "i" from ST(i)
        and     bl,7                    ; ...
        mov     si,bx                   ; save "i" in si
        add     si,cs:tentab[di].t_regnum; calc. reg num of st(i)
        and     si,7                    ; modulo 8
        mov     cx,si                   ; save a copy
        add     si,si                   ; i times 2
        add     si,si                   ; times 4
        add     si,cx                   ; times 5
        add     si,si                   ; times 10
        _lea    ax,st(i)                ; point AX to st(i)
        _lea    dx,st                   ; point DX to st(0)
        mov     bx,ax                   ; result goes to st(i)
        ret                             ; return to emulation routine

exit99:
ifdef QNX32
        add     sp,8
comment ~
        db      066h                    ; restore registers
        pop     gs
        db      066h
        pop     fs
~
        db      066h
        pop     es
        db      066h
        pop     ds
        db      066h
        popa
        db      066h
        iret
else
        pop     es                      ; restore registers
        pop     ds                      ; ...
        pop     di                      ; ...
        pop     si                      ; ...
        pop     bp                      ; ...
        pop     bx                      ; ...(sp)
        pop     bx                      ; ...
        pop     dx                      ; ...
        pop     cx                      ; ...
        pop     ax                      ; ...
 ifdef __PROTMODE__
  ifndef __QNX__
        retf                            ; return from interrupt
  else
        iret                            ; return from interrupt
  endif
 else
        iret                            ; return from interrupt
 endif
endif           ; QNX32

ifndef __PROTMODE__
p_extended:                             ; nothing to do
;
;       peek at next instruction to see if it is also an emulator interrupt
;
exit:   mov     bp,sp                   ; get access to saved registers
        getretaddr                      ; get cs:ip of next instruction
        cmp     byte ptr es:[si],0CDh   ; check for 'int' instruction
        jne     exit99
        jmp     next_instruction        ; if it is, then go for it
endif

saveflg_popstk_exit:
        saveflg
popstk_exit:
        popstk
        jmp     exit

saveflg_exit:
        saveflg
        jmp     exit


p_single:                               ; round result to single precision
        lea     bx,[bp+di].fpstack      ; point to stack top
        mov     dx,0FF00h               ; get mask of bits to keep
        mov     ax,4[bx]                ; get top part
        test    ax,80H                  ; if have to round
        _if     ne                      ; then
          test    al,7FH                ; - if half way between
          _if     e                     ; - then
            _guess                      ; - - guess
              cmp     word ptr [bx],0   ; - - - quif rest is not zero
              _quif   ne                ; - - - ...
              cmp     word ptr 2[bx],0  ; - - - quif rest is not zero
              _quif   ne                ; - - - ...
              shl     DX,1              ; - - - adjust mask
            _endguess                   ; - - enduess
          _endif                        ; - endif
          add     word ptr 4[bx],0100h  ; - round up
          adc     word ptr 6[bx],0      ; - ...
          _if     c                     ; - if exponent needs adjusting
            mov   word ptr 6[bx],8000h  ; - - set fraction
            inc   word ptr 8[bx]        ; - - increment exponent
            ;  check for overflow       ; - -
          _endif                        ; - endif
        _endif                          ; endif
        and     4[bx],dx                ; mask off bottom bits
        mov     word ptr 2[bx],0        ; zero the bottom part
        mov     word ptr [bx],0         ; zero the bottom part
        jmp     exit                    ; exit

p_double:                               ; round result to double precision
        lea     bx,[bp+di].fpstack      ; point to stack top
        mov     dx,0F800h               ; get mask of bits to keep
        mov     ax,[bx]                 ; get bottom part
        test    ax,0400H                ; if rounding bit on
        _if     ne                      ; then
          test  ax,03FFH                ; - if half way between
          _if   e                       ; - then
            shl   dx,1                  ; - - adjust mask
          _endif                        ; - endif
          add   word ptr  [bx],0800h    ; - round up
          adc   word ptr 2[bx],0        ; - ...
          adc   word ptr 4[bx],0        ; - ...
          adc   word ptr 6[bx],0        ; - ...
          _if   c                       ; - if exponent needs adjusting
            mov   word ptr 6[bx],8000h  ; - - set fraction
            inc   word ptr 8[bx]        ; - - increment exponent
            ;  check for overflow       ; - -
          _endif                        ; - endif
        _endif                          ; endif

⌨️ 快捷键说明

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