Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

979 lines
18 KiB

  1. page ,132
  2. subttl emdos.asm - Initialization and Termination
  3. ;***
  4. ;emdos.asm - Initialization and Termination
  5. ;
  6. ; Copyright (c) 1987-89, Microsoft Corporation
  7. ;
  8. ;Purpose:
  9. ; Initialization and Termination
  10. ;
  11. ; This Module contains Proprietary Information of Microsoft
  12. ; Corporation and should be treated as Confidential.
  13. ;
  14. ;Revision History: (Also see emulator.hst)
  15. ;
  16. ; 12-10-89 WAJ Added MTHREAD DS == 0 check.
  17. ;
  18. ;*******************************************************************************
  19. comment !
  20. DOS interfaces to emulator/8087 functions
  21. Certain emulator/8087 functions are performed by calling __fpmath
  22. with an function code and arguments.
  23. __fpmath general floating point math package interface used
  24. by the emulator/8087 and float calls interfaces. This
  25. is a far routine and must be far called.
  26. entry:
  27. bx = 0 initialize floating point math
  28. dx:ax = task data area (dx = segment , ax = size)
  29. extra size is used to increase floating point stack
  30. (can pass segmented address of __fptaskdata in dx:ax)
  31. si = environment segment
  32. returns:
  33. ax = 0 if successful and using software floating point
  34. 1 if successful and using 8087
  35. negative if error
  36. bx = 1 reset (FINIT)
  37. bx = 2 terminate floating point math
  38. bx = 3 set error signal address
  39. dx:ax = segment:offset of user error handler
  40. bx = 4 load user control word
  41. (user should not use FLDCW instruction directly)
  42. ax = user control word value
  43. bx = 5 store user control word
  44. returns:
  45. ax = user control word value
  46. bx = 6 truncate TOS to integer TOS
  47. ax = user control word (only use round mode)
  48. bx = 7 truncate TOS to 32-bit integer in DX:AX
  49. ax = user control word (only use round mode)
  50. bx = 8 store user status word
  51. returns:
  52. ax = user status word value
  53. bx = 9 clear exceptions
  54. bx = 10 return number of stack elements in ax
  55. bx = 11 returns 1 if using 80x87, 0 if not
  56. bx = 12 if ax = 0, turn off extended stack. if ax = 1, turn on e.s.
  57. QB3 version
  58. bx = 0 init, ax = initCW, es = PSP
  59. bx = 1 reset
  60. bx = 2 term
  61. bx = 3 set vectors
  62. bx = 4 reset vectors
  63. !
  64. glb <functab>
  65. functab label word
  66. dw initialization ; 0 - initialize emulator/8087
  67. dw reset ; 1 - reset emulator/8087 stack
  68. dw termination ; 2 - terminate emulator/8087
  69. ifdef QB3
  70. dw set_vectors ; 3 - set interrupt vectors
  71. dw rst_vectors ; 4 - reset interrupt vectors
  72. SizeJmpTab equ 4
  73. else ;not QB3
  74. dw setsignal ; 3 - set error signal address
  75. dw loadcontrolword ; 4 - load user control word
  76. dw storecontrolword ; 5 - store user control word
  77. dw truncateTOS ; 6 - truncate TOS to integer TOS
  78. dw truncateTOSto32int ; 7 - truncate TOS to integer in DX:AX
  79. dw storestatusword ; 8 - store user status word
  80. dw clearexceptions ; 9 - clear execeptions
  81. dw NumStack ; 10 - report number of elements in stack
  82. dw ReturnHave8087 ; 11 - report if using coprocessor
  83. dw SetExtendedStack ; 12 - turn on or off extended stack
  84. SizeJmpTab equ 12
  85. endif ;not QB3
  86. endfunc label word
  87. szfunctab= endfunc - functab
  88. public __fpmath ; emulator entry point
  89. ; (if linked with user program)
  90. __fpmath proc far
  91. cmp bx, SizeJmpTab
  92. ja RetFPErr
  93. shl bx,1
  94. push ds ; save DS
  95. ifdef QB3
  96. push es
  97. push ax
  98. push cx
  99. push dx
  100. push si
  101. push di
  102. endif
  103. ifdef MTHREAD
  104. or bx,bx ; check for initialization
  105. jz callfunc ; yes - skip set up of ds
  106. push ax ; preserve AX = __fpmath argument
  107. LOADthreadDS ; macro in emthread.asm
  108. ; loads thread's DS; trashes AX
  109. mov ax, ds
  110. or ax, ax ; check for DS of zero.
  111. pop ax
  112. jz FPMathRet
  113. callfunc:
  114. else ;MTHREAD
  115. ifdef standalone
  116. xor cx,cx
  117. mov ds,cx
  118. mov ds,ds:[TSKINT*4+2] ; point to task data area
  119. elseifdef _COM_
  120. mov ds, [__EmDataSeg]
  121. else
  122. mov cx, edataBASE
  123. mov ds,cx
  124. endif ;standalone
  125. endif ;MTHREAD
  126. call functab[bx]
  127. ifdef QB3
  128. pop di
  129. pop si
  130. pop dx
  131. pop cx
  132. pop ax
  133. pop es
  134. endif
  135. lab FPMathRet
  136. pop ds ; restore DS
  137. pub emuret
  138. ret
  139. RetFPErr:
  140. or ax, -1
  141. mov dx, ax
  142. jmp emuret
  143. __fpmath endp
  144. ProfBegin DOS
  145. subttl emdos.asm - Initialization and Termination
  146. page
  147. ;*********************************************************************;
  148. ; ;
  149. ; Initialization and Termination ;
  150. ; ;
  151. ;*********************************************************************;
  152. wastetime macro
  153. push cx
  154. mov cx,20 ;; wait for a short time
  155. loop $
  156. pop cx
  157. endm
  158. ifndef only87
  159. CHIPKEY db 'NO87='
  160. CHIPKEYLEN equ $ - CHIPKEY
  161. crlf db 13,10
  162. endif ;only87
  163. ifdef standalone
  164. Installed db 0 ; installation flag
  165. pub sizeerror
  166. mov ax,-1 ; return size error
  167. stc
  168. ret
  169. endif ;standalone
  170. ; initialization
  171. ;
  172. ; entry dx:ax = task data area (segment and size) for standalone
  173. ; si = DOS environment segment for NO87 lookup
  174. pub initialization
  175. ifdef QB3
  176. mov [initCW],ax ; save initial BASIC control word
  177. endif
  178. setstacklimits macro
  179. mov di,offset BEGstk ; di = base of register stack
  180. mov [BASstk],di ; initialize stack base
  181. mov cx,Reg87Len ; cx = register length
  182. xchg ax,dx ; ax = task data segment size
  183. sub ax,di ; ax = number bytes for stack
  184. cwd ; dx:ax = number of bytes
  185. div cx ; ax = number of entries
  186. mul cx ; ax = number of bytes
  187. add ax,di ; ax = top of stack
  188. sub ax,cx ; Leave room for one on overflow
  189. mov [LIMstk],ax ; set top of stack
  190. endm
  191. ifdef standalone
  192. ; check task data area sizes for correctness
  193. cmp ax,offset __fptaskdata ; compare against minimum size
  194. jb sizeerror ; too small
  195. mov ds,dx ; set up task data segment
  196. xchg dx,ax ; set up size
  197. mov ax,25h*256 + TSKINT ; set TASK DATA pointer vector
  198. int 21h
  199. setstacklimits
  200. endif ;standalone
  201. ifdef MTHREAD
  202. ALLOCthreadDS ; macro in emthread.asm
  203. mov dx,(offset __fptaskdata)-cvtbufsize
  204. ; set up size in dx
  205. ; cvt buf not part of stack
  206. setstacklimits
  207. endif ;MTHREAD
  208. ifdef QP
  209. mov ax, edataOFFSET BEGstk ; initialize BASstk, CURstk, LIMstk
  210. mov [BASstk], ax ; QuickPascal has no data initialization
  211. mov [CURstk], ax
  212. mov ax, edataOFFSET ENDstk
  213. sub ax, 2*Reg87Len
  214. mov [LIMstk], ax
  215. endif ;QP
  216. ifndef frontend
  217. ifdef DOS5
  218. push ss ; current stack segment selector
  219. push ds
  220. mov ax,offset SSalias
  221. push ax ; address of SSalias
  222. os2call DOSCREATECSALIAS ; get SS alias for exception handling
  223. endif ;DOS5
  224. endif ;frontend
  225. ifdef DOS3and5
  226. push ds
  227. mov ax,offset protmode
  228. push ax
  229. os2call DOSGETMACHINEMODE ; get machine mode flag
  230. endif ;DOS3and5
  231. ifdef MTHREAD
  232. mov ax,ds
  233. cmp ax,EMULATOR_DATA ; check for thread 1
  234. je initcheckenv ; yes - go look for NO87=
  235. ; other threads should copy thread 1's Have8087 value
  236. ; and then go to initfinish
  237. push ds
  238. mov ax,EMULATOR_DATA
  239. mov ds,ax
  240. mov al,[Have8087]
  241. pop ds
  242. mov [Have8087],al
  243. jmp initfinish
  244. endif ;MTHREAD
  245. pub initcheckenv
  246. ifdef frontend
  247. mov [Have8087],0 ; indicate no 8087
  248. else
  249. ifndef only87
  250. push ds
  251. ; Examine the environment looking for the NO87= switch
  252. or si,si ; check for no environment passed in
  253. je init1 ; don't look for NO87=
  254. mov es,si ; ES = environment segment
  255. push cs
  256. pop ds
  257. xor di,di ; DI -> 1st byte of environment
  258. cld
  259. pub envstart
  260. cmp byte ptr es:[di],0 ; 1st byte zero means end of env.
  261. je init1 ; continue with initialization
  262. mov cx,CHIPKEYLEN ; Length of key 'NO87='
  263. mov si,offset CHIPKEY ; key string address
  264. repe cmpsb
  265. je envwrtmsg
  266. mov cx,7FFFh ; Scan rest of environment
  267. xor al,al ; for 0
  268. repne scasb
  269. je envstart ; yes - check next entry
  270. jmp short init1 ; UNDONE - bad environment if here
  271. pub envwrtmsg
  272. mov cx,7FFFh
  273. mov al,' ' ; skip leading blanks
  274. repe scasb
  275. dec di
  276. mov dl,es:[di] ; Get character of message
  277. or dl,dl ; Do we have a null?
  278. jz envmsgend ; If so we're done
  279. pub envwrtlp
  280. xor ax,ax ;** vvv ; scan for a null byte
  281. mov cx,7FFFh
  282. mov bx,di ; save offset of string
  283. repne scasb
  284. dec di
  285. sub di,bx
  286. mov cx,di ; count of characters before null byte
  287. ;
  288. ; write out NO87= environment string to standard output
  289. ;
  290. ifdef DOS5
  291. mov di,bx ; restore offset of string
  292. push ax
  293. mov ax,sp ; allocate space for return count
  294. mov bx,1
  295. push bx ; file handle (standard output)
  296. push es
  297. push di ; address of buffer
  298. push cx ; number of bytes to write
  299. push ss
  300. push ax ; address for return count
  301. os2call DOSWRITE
  302. ;
  303. ; write out CR-LF pair to standard output
  304. ;
  305. mov ax,sp ; pointer to space for return count
  306. mov bx,1
  307. push bx ; file handle (standard output)
  308. push cs
  309. mov di,offset crlf
  310. push di ; address of CR-LF pair
  311. mov bx,2
  312. push bx ; number of bytes to write: 2
  313. push ss
  314. push ax ; address for return count
  315. os2call DOSWRITE
  316. pop bx ;** ^^^ ; deallocate space for return count
  317. else
  318. push es
  319. pop ds
  320. mov dx,bx ; ds:dx = string
  321. mov bx,1 ; bx = file handle (1)
  322. mov ah,40H
  323. int 21h ; call DOS - write string
  324. push cs
  325. pop ds
  326. mov dx,offset crlf ; ds:dx = CR/LF
  327. mov cx,2 ; cx = 2 bytes
  328. mov ah,40H
  329. int 21h ; call DOS - write string
  330. endif
  331. pub envmsgend
  332. pop ds ; restore user data area
  333. mov [Have8087],0 ; indicate emulation
  334. ifdef _NO87INSTALL
  335. jmp initinstallno87 ; go call __FPINSTALLNO87
  336. else ;_NO87INSTALL
  337. jmp initvec ; initialize for emulation
  338. endif ;_NO87INSTALL
  339. pub init1
  340. pop ds ; restore user data area
  341. endif ;only87
  342. ; check if 8087/80287 is present
  343. ifdef DOS3and5
  344. cmp [protmode],0 ; check for protect mode
  345. jne prot287chk ; yes - check for 287
  346. endif ;DOS3and5
  347. ifdef DOS3
  348. ; real mode 8087/80287 check
  349. ifdef PCDOS
  350. PCBIOSEQ equ 11H ; PC BIO's Equipment determination call.
  351. COPROCESSORMASK equ 2H ; Mask for Coprocessor sense switch.
  352. int PCBIOSEQ ; PC-DOS Bios Equipment
  353. and al,COPROCESSORMASK ; Coprocessor present?
  354. shr al,1 ; al = 0 if no 8087/80287 , 1 = if yes
  355. ifdef only87
  356. jz installerror ; error if no 8087/80287
  357. endif ;only87
  358. else
  359. fninit ; Initialize the 8087.
  360. wastetime
  361. xor ax,ax ; Clean AX.
  362. mov [statwd],ax ; Clear temporary.
  363. fnstcw [statwd] ; have bits 033Fh set if 8087
  364. wastetime
  365. and [statwd],0F3Fh ; (was 1F3Fh, but now allows for 80387-A1 step)
  366. cmp [statwd],033Fh
  367. jnz realno87 ; no 8087 or 287
  368. ; 80287 can fool you - also check for status word
  369. fnstsw [statwd] ; save status word
  370. wastetime
  371. inc ax ; al = 1 (assume have an 80287)
  372. test [statwd],0B8BFh ; should be off if present
  373. pub realno87
  374. jz realhave87
  375. ifdef only87
  376. jmp short installerror ; error if no 8087/80287
  377. else
  378. xor ax,ax ; al = 0
  379. endif ;only87
  380. pub realhave87
  381. endif ;PCDOS
  382. MOV [Have8087],al
  383. endif ;DOS3
  384. ifdef DOS3and5
  385. jmp short initinstall
  386. endif ;DOS3and5
  387. ifdef DOS5
  388. ; protect mode 80287 check
  389. pub prot287chk
  390. push ds
  391. .286
  392. push offset Have8087 ; directly change Have8087
  393. push 3 ; 3rd byte is coprocessor flag
  394. push 0 ; reserved parameter
  395. ifndef DOS5only
  396. .8086
  397. endif
  398. os2call DOSDEVCONFIG
  399. ifdef only87
  400. cmp [Have8087],0 ; error if no 87 present
  401. je installerror
  402. endif ;only87
  403. endif ;DOS5
  404. endif ;frontend
  405. ; check if floating point emulator/8087 already installed (device driver)
  406. pub initinstall
  407. ifndef QB3
  408. ifndef frontend
  409. ifndef only87
  410. cmp [Have8087],0 ; check for 8087/80287
  411. ifdef _NO87INSTALL
  412. jne initcontinue
  413. pub initinstallno87
  414. extrn __FPINSTALLNO87:near
  415. call __FPINSTALLNO87
  416. jmp initvec
  417. initcontinue:
  418. else ;_NO87INSTALL
  419. je initvec ; no - don't install hardware
  420. endif ;_NO87INSTALL
  421. endif ;only87
  422. ifdef DOS3and5
  423. cmp [protmode],0 ; check for protect mode
  424. jne initprotinstall ; yes - don't install hardware
  425. endif ;DOS3and5
  426. ifdef DOS5only
  427. jmp initprotinstall
  428. endif
  429. ifdef DOS3
  430. ifdef standalone
  431. cmp [Installed],0 ; note - in code segment (not task)
  432. jnz initvec ; installed - skip installation
  433. endif ;standalone
  434. extrn __FPINSTALL87:near
  435. call __FPINSTALL87 ; OEM installation
  436. jnc initvec
  437. endif ;DOS3
  438. pub installerror
  439. mov ax,-2 ; return installation error
  440. stc
  441. ret
  442. ifdef DOS5
  443. pub initprotinstall
  444. .286
  445. push 16 ; exception error
  446. push cs
  447. push offset protexception
  448. push ds
  449. push offset oldvec+4 ; address for old exception vector
  450. ifndef DOS5only
  451. .8086
  452. endif
  453. os2call DOSSETVEC
  454. endif ;DOS5
  455. endif ;frontend
  456. endif ;QB3
  457. ; set up interrupt vectors for emulator or fixup-on-the-fly
  458. pub initvec
  459. ifdef DOS3and5
  460. cmp [protmode],0
  461. jne initvecprot ; yes - protect mode setup
  462. endif ;DOS3and5
  463. ifdef DOS3
  464. ; real mode emulation and fixup on the fly vector setup
  465. ifndef QB3
  466. call set_vectors
  467. endif
  468. endif ;DOS3
  469. ifdef DOS3and5
  470. jmp short initfinish
  471. endif
  472. ifdef DOS5
  473. pub initvecprot
  474. ifndef only87
  475. cmp [Have8087],0 ; emulation?
  476. jne initfinish ; no - don't setup vector
  477. .286
  478. push 7 ; emulation
  479. push cs
  480. push offset protemulation
  481. push ds
  482. push offset oldvec ; address for old emulation vector
  483. ifndef DOS5only
  484. .8086
  485. endif
  486. os2call DOSSETVEC
  487. endif ;only87
  488. endif ;DOS5
  489. ; finish initialization
  490. pub initfinish
  491. call reset ; reset (0), FINIT if 8087 present
  492. ifdef QB3
  493. mov ax,[initCW]
  494. else
  495. mov ax,InitControlWord ; setup initial control word
  496. endif
  497. call loadcontrolword
  498. ifndef QB3
  499. xor ax,ax
  500. mov word ptr [SignalAddress],ax ; clear SignalAddress
  501. mov word ptr [SignalAddress+2],ax
  502. endif
  503. ifdef MTHREAD
  504. mov [ExtendStack],1
  505. endif ;MTHREAD
  506. ifndef only87
  507. ifdef LOOK_AHEAD
  508. ifdef DOS3and5
  509. mov ax, offset DOSLookAhead
  510. cmp [protmode], 0
  511. je SetLookAheadRoutine
  512. mov ax, offset ProtLookAhead
  513. SetLookAheadRoutine:
  514. mov [LookAheadRoutine], ax
  515. endif ;DOS3and5
  516. endif ;LOOK_AHEAD
  517. endif ;not only87
  518. mov al,[Have8087]
  519. cbw ; ax = 0 or 1 depending on 8087
  520. ret
  521. ifdef MTHREAD
  522. lab LoadDS_EDI ; this is used from emds.asm
  523. push bx
  524. push cx
  525. push dx
  526. mov bx, DGROUP
  527. mov ds, bx
  528. call __FarGetTidTab
  529. mov ds, dx
  530. mov di, ax
  531. add di, __fpds
  532. pop dx
  533. pop cx
  534. pop bx
  535. ret
  536. endif ;MTHREAD
  537. ;------ termination ----------------------------------------------------
  538. pub termination
  539. ifdef DOS3and5
  540. cmp [protmode],0 ; are we in protect mode?
  541. jne termprot ; yes
  542. endif ;DOS3and5
  543. ifdef DOS3
  544. ; real mode termination
  545. ifndef QB3
  546. call rst_vectors
  547. endif
  548. ifndef frontend
  549. ifndef only87
  550. cmp [Have8087],0 ; Non zero if 8087 chip exists
  551. ifdef _NO87INSTALL
  552. jne termcontinue
  553. extrn __FPTERMINATENO87:near
  554. call __FPTERMINATENO87
  555. ret
  556. termcontinue:
  557. else ;_NO87INSTALL
  558. je termrealdone
  559. endif ;_NO87INSTALL
  560. endif ;only87
  561. FNINIT ; Clean up 8087.
  562. ifndef QB3
  563. extrn __FPTERMINATE87:near
  564. call __FPTERMINATE87 ; OEM 8087 cleanup routine
  565. endif
  566. endif ;frontend
  567. pub termrealdone
  568. ret
  569. endif ;DOS3
  570. ifdef DOS5
  571. ; protect mode termination
  572. pub termprot
  573. ; UNDONE - don't do any cleanup - should be handled by DOS
  574. ifndef frontend ; UNDONE - should not be needed
  575. push [SSalias]
  576. os2call DOSFREESEG ; free up SSalias
  577. endif ;frontend
  578. ifdef MTHREAD
  579. FREEthreadDS ; defined in emthread.asm
  580. ; uses DOSFREESEG
  581. endif ;MTHREAD
  582. ret
  583. endif ;DOS5
  584. subttl emdos.asm - reset and clearexceptions
  585. page
  586. ;*********************************************************************;
  587. ; ;
  588. ; Reset and Clearexceptions ;
  589. ; ;
  590. ;*********************************************************************;
  591. pub reset
  592. ifndef frontend
  593. ifndef only87
  594. cmp [Have8087],0 ; Nonzero if 8087 chip exists
  595. je noFINIT
  596. endif ;only87
  597. FNINIT ; Initialize 8087.
  598. endif ;frontend
  599. pub noFINIT
  600. mov ax,[BASstk]
  601. mov [CURstk],ax ; reset stack to bottom
  602. ; fall into clearexceptions
  603. pub clearexceptions
  604. xor ax,ax
  605. ifndef frontend
  606. ifndef only87
  607. cmp al,[Have8087] ; Nonzero if 8087 chip exists
  608. je noFCLEX
  609. endif ;only87
  610. FCLEX ; clear exceptions
  611. endif ;frontend
  612. pub noFCLEX
  613. ifndef only87
  614. mov [StatusWord],ax ; clear status word
  615. endif ;only87
  616. mov [UserStatusWord],ax ; clear exception status word
  617. ifdef QB3
  618. mov ax,[initCW]
  619. call loadcontrolword ; reload 8087 control word
  620. endif ;QB3
  621. ret
  622. subttl emdos.asm - setsignal ---------------------------------
  623. page
  624. ;*********************************************************************;
  625. ; ;
  626. ; Setsignal ;
  627. ; ;
  628. ;*********************************************************************;
  629. ifndef QB3
  630. pub setsignal
  631. mov word ptr [SignalAddress],ax ; set offset
  632. mov word ptr [SignalAddress+2],dx ; set segment
  633. ret
  634. endif ;QB3
  635. ifdef DOS3
  636. pub set_vectors
  637. mov cx,NUMVEC ; save old vectors under DOS 3
  638. mov ax,35h*256 + BEGINT ; get vector
  639. mov di,offset oldvec ; di = old vector table
  640. pub getvecs
  641. int 21h
  642. inc ax
  643. mov [di],bx ; save old vector
  644. mov [di+2],es
  645. add di,4
  646. loop getvecs
  647. ifndef only87
  648. mov dx,offset DStrap ; assume emulator
  649. mov si,offset SOtrap
  650. mov di,offset FWtrap
  651. endif ;only87
  652. ifndef frontend
  653. ifndef only87
  654. cmp [Have8087],0 ; are we using 8087 ?
  655. jz setvectors ; no - go ahead and set them
  656. endif ;only87
  657. mov dx,offset DSFixUpOnFly ; set up for fixup-on-the-fly
  658. mov si,offset SOFixUpOnFly
  659. mov di,offset FWFixUpOnFly
  660. endif ;frontend
  661. pub setvectors
  662. push ds
  663. push cs
  664. pop ds
  665. mov ax,25h*256 + BEGINT
  666. mov cx,8 ; 8 vectors for DStrap
  667. pub vecloop
  668. int 21h ; set vector
  669. inc ax ; bump to next one
  670. loop vecloop
  671. mov dx,si ; set Segtrap
  672. int 21h
  673. inc ax
  674. mov dx,di ; set FWtrap
  675. int 21h
  676. pop ds ; restore task data area
  677. ret
  678. pub rst_vectors
  679. mov cx,NUMVEC
  680. mov ax,25h*256 + BEGINT ; set vector
  681. mov di,offset oldvec ; di = old vector table
  682. pub termresetvecs
  683. push ds
  684. lds dx,[di] ; get old vector value
  685. int 21h
  686. pop ds
  687. inc ax
  688. add di,4
  689. loop termresetvecs
  690. ret
  691. endif ;DOS3
  692. pub NumStack ; returns the number of stack elements in ax
  693. xor dx, dx ; dx will count nonzero elements
  694. ifndef only87
  695. cmp Have8087, 0
  696. je CountEmulatorStack
  697. endif ;only87
  698. sub sp, 14 ; need 14 bytes for fstenv
  699. mov bx, sp
  700. fstenv ss:[bx]
  701. fldcw ss:[bx] ; reset control word
  702. mov ax, ss:[bx+4] ; put tag word in ax
  703. add sp, 14 ; reset stack
  704. mov cx, 8
  705. pub NotEmptyLoop
  706. mov bx, ax
  707. shr ax, 1
  708. shr ax, 1
  709. and bx, 3
  710. cmp bx, 3
  711. je StackEntryEmpty
  712. inc dx ; stack element was not empty
  713. pub StackEntryEmpty
  714. loop NotEmptyLoop
  715. pub CountEmulatorStack
  716. mov ax, CURstk
  717. sub ax, BASstk
  718. mov bl, Reg87Len
  719. div bl
  720. add ax, dx ; add elements on 80x87 stack
  721. ret
  722. ReturnHave8087 proc near
  723. mov al, [Have8087]
  724. cbw
  725. ret
  726. ReturnHave8087 endp
  727. SetExtendedStack proc near
  728. mov [ExtendStack], ax
  729. ret
  730. SetExtendedStack endp
  731. ProfEnd DOS