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 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