|
|
page ,132 subttl emdos.asm - Initialization and Termination ;*** ;emdos.asm - Initialization and Termination ; ; Copyright (c) 1987-89, Microsoft Corporation ; ;Purpose: ; Initialization and Termination ; ; This Module contains Proprietary Information of Microsoft ; Corporation and should be treated as Confidential. ; ;Revision History: (Also see emulator.hst) ; ; 12-10-89 WAJ Added MTHREAD DS == 0 check. ; ;*******************************************************************************
comment !
DOS interfaces to emulator/8087 functions
Certain emulator/8087 functions are performed by calling __fpmath with an function code and arguments.
__fpmath general floating point math package interface used by the emulator/8087 and float calls interfaces. This is a far routine and must be far called.
entry:
bx = 0 initialize floating point math dx:ax = task data area (dx = segment , ax = size) extra size is used to increase floating point stack (can pass segmented address of __fptaskdata in dx:ax) si = environment segment returns: ax = 0 if successful and using software floating point 1 if successful and using 8087 negative if error
bx = 1 reset (FINIT)
bx = 2 terminate floating point math
bx = 3 set error signal address dx:ax = segment:offset of user error handler
bx = 4 load user control word (user should not use FLDCW instruction directly) ax = user control word value
bx = 5 store user control word returns: ax = user control word value
bx = 6 truncate TOS to integer TOS ax = user control word (only use round mode)
bx = 7 truncate TOS to 32-bit integer in DX:AX ax = user control word (only use round mode)
bx = 8 store user status word returns: ax = user status word value
bx = 9 clear exceptions
bx = 10 return number of stack elements in ax
bx = 11 returns 1 if using 80x87, 0 if not
bx = 12 if ax = 0, turn off extended stack. if ax = 1, turn on e.s.
QB3 version
bx = 0 init, ax = initCW, es = PSP bx = 1 reset bx = 2 term bx = 3 set vectors bx = 4 reset vectors
!
glb <functab>
functab label word
dw initialization ; 0 - initialize emulator/8087 dw reset ; 1 - reset emulator/8087 stack dw termination ; 2 - terminate emulator/8087
ifdef QB3
dw set_vectors ; 3 - set interrupt vectors dw rst_vectors ; 4 - reset interrupt vectors
SizeJmpTab equ 4
else ;not QB3 dw setsignal ; 3 - set error signal address
dw loadcontrolword ; 4 - load user control word dw storecontrolword ; 5 - store user control word dw truncateTOS ; 6 - truncate TOS to integer TOS dw truncateTOSto32int ; 7 - truncate TOS to integer in DX:AX dw storestatusword ; 8 - store user status word dw clearexceptions ; 9 - clear execeptions dw NumStack ; 10 - report number of elements in stack dw ReturnHave8087 ; 11 - report if using coprocessor dw SetExtendedStack ; 12 - turn on or off extended stack
SizeJmpTab equ 12
endif ;not QB3
endfunc label word
szfunctab= endfunc - functab
public __fpmath ; emulator entry point ; (if linked with user program)
__fpmath proc far
cmp bx, SizeJmpTab ja RetFPErr
shl bx,1 push ds ; save DS
ifdef QB3 push es push ax push cx push dx push si push di endif
ifdef MTHREAD or bx,bx ; check for initialization jz callfunc ; yes - skip set up of ds push ax ; preserve AX = __fpmath argument LOADthreadDS ; macro in emthread.asm ; loads thread's DS; trashes AX mov ax, ds or ax, ax ; check for DS of zero. pop ax jz FPMathRet callfunc:
else ;MTHREAD
ifdef standalone xor cx,cx mov ds,cx mov ds,ds:[TSKINT*4+2] ; point to task data area
elseifdef _COM_ mov ds, [__EmDataSeg]
else mov cx, edataBASE mov ds,cx endif ;standalone
endif ;MTHREAD
call functab[bx]
ifdef QB3 pop di pop si pop dx pop cx pop ax pop es endif
lab FPMathRet pop ds ; restore DS
pub emuret ret
RetFPErr: or ax, -1 mov dx, ax jmp emuret
__fpmath endp
ProfBegin DOS
subttl emdos.asm - Initialization and Termination page ;*********************************************************************; ; ; ; Initialization and Termination ; ; ; ;*********************************************************************;
wastetime macro push cx mov cx,20 ;; wait for a short time loop $ pop cx endm
ifndef only87 CHIPKEY db 'NO87=' CHIPKEYLEN equ $ - CHIPKEY crlf db 13,10 endif ;only87
ifdef standalone Installed db 0 ; installation flag
pub sizeerror mov ax,-1 ; return size error stc ret endif ;standalone
; initialization ; ; entry dx:ax = task data area (segment and size) for standalone ; si = DOS environment segment for NO87 lookup
pub initialization
ifdef QB3 mov [initCW],ax ; save initial BASIC control word endif
setstacklimits macro mov di,offset BEGstk ; di = base of register stack mov [BASstk],di ; initialize stack base mov cx,Reg87Len ; cx = register length xchg ax,dx ; ax = task data segment size sub ax,di ; ax = number bytes for stack cwd ; dx:ax = number of bytes div cx ; ax = number of entries mul cx ; ax = number of bytes add ax,di ; ax = top of stack sub ax,cx ; Leave room for one on overflow mov [LIMstk],ax ; set top of stack endm
ifdef standalone
; check task data area sizes for correctness
cmp ax,offset __fptaskdata ; compare against minimum size jb sizeerror ; too small mov ds,dx ; set up task data segment xchg dx,ax ; set up size mov ax,25h*256 + TSKINT ; set TASK DATA pointer vector int 21h
setstacklimits endif ;standalone
ifdef MTHREAD ALLOCthreadDS ; macro in emthread.asm mov dx,(offset __fptaskdata)-cvtbufsize ; set up size in dx ; cvt buf not part of stack setstacklimits endif ;MTHREAD
ifdef QP mov ax, edataOFFSET BEGstk ; initialize BASstk, CURstk, LIMstk mov [BASstk], ax ; QuickPascal has no data initialization mov [CURstk], ax
mov ax, edataOFFSET ENDstk sub ax, 2*Reg87Len mov [LIMstk], ax endif ;QP
ifndef frontend ifdef DOS5 push ss ; current stack segment selector push ds mov ax,offset SSalias push ax ; address of SSalias os2call DOSCREATECSALIAS ; get SS alias for exception handling endif ;DOS5
endif ;frontend
ifdef DOS3and5 push ds mov ax,offset protmode push ax os2call DOSGETMACHINEMODE ; get machine mode flag endif ;DOS3and5
ifdef MTHREAD mov ax,ds cmp ax,EMULATOR_DATA ; check for thread 1 je initcheckenv ; yes - go look for NO87=
; other threads should copy thread 1's Have8087 value ; and then go to initfinish
push ds mov ax,EMULATOR_DATA mov ds,ax mov al,[Have8087] pop ds mov [Have8087],al jmp initfinish endif ;MTHREAD pub initcheckenv
ifdef frontend mov [Have8087],0 ; indicate no 8087 else ifndef only87 push ds
; Examine the environment looking for the NO87= switch
or si,si ; check for no environment passed in je init1 ; don't look for NO87=
mov es,si ; ES = environment segment push cs pop ds xor di,di ; DI -> 1st byte of environment cld
pub envstart cmp byte ptr es:[di],0 ; 1st byte zero means end of env. je init1 ; continue with initialization
mov cx,CHIPKEYLEN ; Length of key 'NO87=' mov si,offset CHIPKEY ; key string address
repe cmpsb
je envwrtmsg
mov cx,7FFFh ; Scan rest of environment xor al,al ; for 0 repne scasb je envstart ; yes - check next entry jmp short init1 ; UNDONE - bad environment if here
pub envwrtmsg mov cx,7FFFh mov al,' ' ; skip leading blanks repe scasb dec di mov dl,es:[di] ; Get character of message or dl,dl ; Do we have a null? jz envmsgend ; If so we're done
pub envwrtlp xor ax,ax ;** vvv ; scan for a null byte mov cx,7FFFh mov bx,di ; save offset of string repne scasb dec di sub di,bx mov cx,di ; count of characters before null byte
; ; write out NO87= environment string to standard output ;
ifdef DOS5 mov di,bx ; restore offset of string push ax mov ax,sp ; allocate space for return count
mov bx,1 push bx ; file handle (standard output) push es push di ; address of buffer push cx ; number of bytes to write push ss push ax ; address for return count os2call DOSWRITE
; ; write out CR-LF pair to standard output ; mov ax,sp ; pointer to space for return count
mov bx,1 push bx ; file handle (standard output) push cs mov di,offset crlf push di ; address of CR-LF pair mov bx,2 push bx ; number of bytes to write: 2 push ss push ax ; address for return count os2call DOSWRITE pop bx ;** ^^^ ; deallocate space for return count else push es pop ds mov dx,bx ; ds:dx = string mov bx,1 ; bx = file handle (1) mov ah,40H int 21h ; call DOS - write string
push cs pop ds mov dx,offset crlf ; ds:dx = CR/LF mov cx,2 ; cx = 2 bytes mov ah,40H int 21h ; call DOS - write string endif
pub envmsgend pop ds ; restore user data area mov [Have8087],0 ; indicate emulation ifdef _NO87INSTALL jmp initinstallno87 ; go call __FPINSTALLNO87 else ;_NO87INSTALL jmp initvec ; initialize for emulation endif ;_NO87INSTALL
pub init1 pop ds ; restore user data area
endif ;only87
; check if 8087/80287 is present
ifdef DOS3and5 cmp [protmode],0 ; check for protect mode jne prot287chk ; yes - check for 287 endif ;DOS3and5
ifdef DOS3
; real mode 8087/80287 check
ifdef PCDOS PCBIOSEQ equ 11H ; PC BIO's Equipment determination call. COPROCESSORMASK equ 2H ; Mask for Coprocessor sense switch.
int PCBIOSEQ ; PC-DOS Bios Equipment and al,COPROCESSORMASK ; Coprocessor present? shr al,1 ; al = 0 if no 8087/80287 , 1 = if yes ifdef only87 jz installerror ; error if no 8087/80287 endif ;only87 else fninit ; Initialize the 8087. wastetime xor ax,ax ; Clean AX. mov [statwd],ax ; Clear temporary. fnstcw [statwd] ; have bits 033Fh set if 8087 wastetime and [statwd],0F3Fh ; (was 1F3Fh, but now allows for 80387-A1 step) cmp [statwd],033Fh jnz realno87 ; no 8087 or 287
; 80287 can fool you - also check for status word
fnstsw [statwd] ; save status word wastetime inc ax ; al = 1 (assume have an 80287) test [statwd],0B8BFh ; should be off if present
pub realno87 jz realhave87 ifdef only87 jmp short installerror ; error if no 8087/80287 else xor ax,ax ; al = 0 endif ;only87
pub realhave87 endif ;PCDOS
MOV [Have8087],al endif ;DOS3
ifdef DOS3and5 jmp short initinstall endif ;DOS3and5
ifdef DOS5
; protect mode 80287 check
pub prot287chk push ds
.286 push offset Have8087 ; directly change Have8087 push 3 ; 3rd byte is coprocessor flag push 0 ; reserved parameter
ifndef DOS5only .8086 endif
os2call DOSDEVCONFIG ifdef only87 cmp [Have8087],0 ; error if no 87 present je installerror endif ;only87 endif ;DOS5
endif ;frontend
; check if floating point emulator/8087 already installed (device driver)
pub initinstall
ifndef QB3
ifndef frontend ifndef only87 cmp [Have8087],0 ; check for 8087/80287 ifdef _NO87INSTALL jne initcontinue pub initinstallno87 extrn __FPINSTALLNO87:near call __FPINSTALLNO87 jmp initvec initcontinue: else ;_NO87INSTALL je initvec ; no - don't install hardware endif ;_NO87INSTALL endif ;only87
ifdef DOS3and5 cmp [protmode],0 ; check for protect mode jne initprotinstall ; yes - don't install hardware endif ;DOS3and5 ifdef DOS5only jmp initprotinstall endif
ifdef DOS3 ifdef standalone cmp [Installed],0 ; note - in code segment (not task) jnz initvec ; installed - skip installation endif ;standalone
extrn __FPINSTALL87:near call __FPINSTALL87 ; OEM installation jnc initvec
endif ;DOS3
pub installerror mov ax,-2 ; return installation error stc ret
ifdef DOS5 pub initprotinstall
.286 push 16 ; exception error push cs push offset protexception push ds push offset oldvec+4 ; address for old exception vector
ifndef DOS5only .8086 endif os2call DOSSETVEC endif ;DOS5 endif ;frontend
endif ;QB3
; set up interrupt vectors for emulator or fixup-on-the-fly
pub initvec
ifdef DOS3and5 cmp [protmode],0 jne initvecprot ; yes - protect mode setup endif ;DOS3and5
ifdef DOS3 ; real mode emulation and fixup on the fly vector setup
ifndef QB3 call set_vectors endif
endif ;DOS3 ifdef DOS3and5 jmp short initfinish endif
ifdef DOS5 pub initvecprot ifndef only87 cmp [Have8087],0 ; emulation? jne initfinish ; no - don't setup vector
.286 push 7 ; emulation push cs push offset protemulation push ds push offset oldvec ; address for old emulation vector
ifndef DOS5only .8086 endif os2call DOSSETVEC endif ;only87 endif ;DOS5
; finish initialization
pub initfinish
call reset ; reset (0), FINIT if 8087 present
ifdef QB3 mov ax,[initCW] else mov ax,InitControlWord ; setup initial control word endif call loadcontrolword
ifndef QB3 xor ax,ax mov word ptr [SignalAddress],ax ; clear SignalAddress mov word ptr [SignalAddress+2],ax endif
ifdef MTHREAD mov [ExtendStack],1 endif ;MTHREAD
ifndef only87 ifdef LOOK_AHEAD ifdef DOS3and5 mov ax, offset DOSLookAhead cmp [protmode], 0 je SetLookAheadRoutine
mov ax, offset ProtLookAhead SetLookAheadRoutine: mov [LookAheadRoutine], ax
endif ;DOS3and5 endif ;LOOK_AHEAD endif ;not only87
mov al,[Have8087] cbw ; ax = 0 or 1 depending on 8087 ret
ifdef MTHREAD lab LoadDS_EDI ; this is used from emds.asm push bx push cx push dx
mov bx, DGROUP mov ds, bx
call __FarGetTidTab mov ds, dx mov di, ax add di, __fpds
pop dx pop cx pop bx
ret endif ;MTHREAD
;------ termination ----------------------------------------------------
pub termination
ifdef DOS3and5 cmp [protmode],0 ; are we in protect mode? jne termprot ; yes endif ;DOS3and5
ifdef DOS3 ; real mode termination
ifndef QB3 call rst_vectors endif
ifndef frontend ifndef only87 cmp [Have8087],0 ; Non zero if 8087 chip exists ifdef _NO87INSTALL jne termcontinue extrn __FPTERMINATENO87:near call __FPTERMINATENO87 ret termcontinue: else ;_NO87INSTALL je termrealdone endif ;_NO87INSTALL endif ;only87
FNINIT ; Clean up 8087.
ifndef QB3 extrn __FPTERMINATE87:near call __FPTERMINATE87 ; OEM 8087 cleanup routine endif
endif ;frontend
pub termrealdone ret endif ;DOS3
ifdef DOS5 ; protect mode termination
pub termprot
; UNDONE - don't do any cleanup - should be handled by DOS
ifndef frontend ; UNDONE - should not be needed push [SSalias] os2call DOSFREESEG ; free up SSalias endif ;frontend
ifdef MTHREAD FREEthreadDS ; defined in emthread.asm ; uses DOSFREESEG endif ;MTHREAD
ret endif ;DOS5
subttl emdos.asm - reset and clearexceptions page ;*********************************************************************; ; ; ; Reset and Clearexceptions ; ; ; ;*********************************************************************;
pub reset
ifndef frontend ifndef only87 cmp [Have8087],0 ; Nonzero if 8087 chip exists je noFINIT endif ;only87 FNINIT ; Initialize 8087. endif ;frontend
pub noFINIT mov ax,[BASstk] mov [CURstk],ax ; reset stack to bottom
; fall into clearexceptions
pub clearexceptions
xor ax,ax ifndef frontend ifndef only87 cmp al,[Have8087] ; Nonzero if 8087 chip exists je noFCLEX endif ;only87 FCLEX ; clear exceptions endif ;frontend
pub noFCLEX ifndef only87 mov [StatusWord],ax ; clear status word endif ;only87 mov [UserStatusWord],ax ; clear exception status word
ifdef QB3 mov ax,[initCW] call loadcontrolword ; reload 8087 control word endif ;QB3
ret
subttl emdos.asm - setsignal --------------------------------- page ;*********************************************************************; ; ; ; Setsignal ; ; ; ;*********************************************************************;
ifndef QB3
pub setsignal mov word ptr [SignalAddress],ax ; set offset mov word ptr [SignalAddress+2],dx ; set segment ret
endif ;QB3
ifdef DOS3
pub set_vectors
mov cx,NUMVEC ; save old vectors under DOS 3 mov ax,35h*256 + BEGINT ; get vector mov di,offset oldvec ; di = old vector table pub getvecs int 21h inc ax mov [di],bx ; save old vector mov [di+2],es add di,4 loop getvecs
ifndef only87 mov dx,offset DStrap ; assume emulator mov si,offset SOtrap mov di,offset FWtrap endif ;only87
ifndef frontend ifndef only87 cmp [Have8087],0 ; are we using 8087 ? jz setvectors ; no - go ahead and set them endif ;only87
mov dx,offset DSFixUpOnFly ; set up for fixup-on-the-fly mov si,offset SOFixUpOnFly mov di,offset FWFixUpOnFly endif ;frontend
pub setvectors push ds
push cs pop ds mov ax,25h*256 + BEGINT mov cx,8 ; 8 vectors for DStrap pub vecloop int 21h ; set vector inc ax ; bump to next one loop vecloop
mov dx,si ; set Segtrap int 21h inc ax mov dx,di ; set FWtrap int 21h
pop ds ; restore task data area
ret
pub rst_vectors
mov cx,NUMVEC mov ax,25h*256 + BEGINT ; set vector mov di,offset oldvec ; di = old vector table
pub termresetvecs push ds lds dx,[di] ; get old vector value int 21h pop ds inc ax add di,4 loop termresetvecs
ret
endif ;DOS3
pub NumStack ; returns the number of stack elements in ax
xor dx, dx ; dx will count nonzero elements
ifndef only87 cmp Have8087, 0 je CountEmulatorStack endif ;only87
sub sp, 14 ; need 14 bytes for fstenv mov bx, sp fstenv ss:[bx] fldcw ss:[bx] ; reset control word mov ax, ss:[bx+4] ; put tag word in ax add sp, 14 ; reset stack
mov cx, 8 pub NotEmptyLoop mov bx, ax
shr ax, 1 shr ax, 1
and bx, 3 cmp bx, 3 je StackEntryEmpty
inc dx ; stack element was not empty pub StackEntryEmpty loop NotEmptyLoop
pub CountEmulatorStack
mov ax, CURstk sub ax, BASstk
mov bl, Reg87Len
div bl
add ax, dx ; add elements on 80x87 stack
ret
ReturnHave8087 proc near
mov al, [Have8087] cbw
ret ReturnHave8087 endp
SetExtendedStack proc near
mov [ExtendStack], ax
ret SetExtendedStack endp
ProfEnd DOS
|