home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 9.ddi / EMUSRC.ZIP / FPINIT.ASM < prev   
Encoding:
Assembly Source File  |  1992-06-10  |  26.7 KB  |  830 lines

  1. ;[]------------------------------------------------------------[]
  2. ;|      FPINIT.ASM -- Emulator initialization                   |
  3. ;[]------------------------------------------------------------[]
  4.  
  5. ;
  6. ;       C/C++ Run Time Library - Version 5.0
  7. ;       Copyright (c) 1986, 1992 by Borland International
  8. ;       All Rights Reserved.
  9.  
  10.         NAME    fpInit
  11.  
  12. ; Floating point (FPU) initialization.
  13. ; Includes detection of coprocessor, checking for environment override
  14. ; (SET 87=N), installation of interrupt vectors, and FINIT.
  15.  
  16. ; This module replaces EMUINIT and 87INIT, both used in TC 2.0.
  17. ; It also replaces some code in C0 related to floating point.
  18. ; Assemble with /DFP87 for hard 80x87 opcodes.
  19.  
  20. ; Caution: This code is in the _TEXT segment, and assumes that certain
  21. ; external routines can be called with NEAR calls.
  22.  
  23. .286
  24. .287
  25. locals  @@
  26.  
  27. include equates.asi
  28.  
  29. ifdef   FP87
  30. _Emu_   equ     0               ; no emulation, '87 required
  31. else
  32. _Emu_   equ     1               ; emulator
  33. endif
  34.  
  35. include emurules.asi
  36. include emuvars.asi
  37.  
  38. ; Segment and Group declarations
  39.  
  40. Header@
  41.  
  42. DSeg@
  43.  
  44. ; Public data
  45. ; initialize to -1
  46. ; if executed, emu1st will change it to 0, 1, 2, or 3
  47. PubSym@         _8087,  <dw     -1>,    __CDECL__
  48.  
  49. ; External References
  50. ExtSym@         _version, WORD, __CDECL__
  51. ExtSym@         _psp, WORD, __CDECL__
  52. ExtSym@         _protected, BYTE, __CDECL__
  53. ExtSym@         _LDT, WORD, __CDECL__
  54. ExtSym@         _default87, WORD, __CDECL__
  55.  
  56. DSegEnd@
  57.  
  58. ; External data, possibly not in DGROUP.
  59. ExtSym@         _fpstklen, word, __CDECL__
  60. ExtSym@         _stklen, word, __CDECL__
  61. extrn   __turboCvt : ABS        ; To force the link of REALCVT for printf
  62. extrn   __emu : byte
  63.  
  64. EmuAssume@      SS
  65.  
  66. ; Public procs.
  67.  
  68. public  ___fpreset
  69.  
  70. ; External procs.
  71.  
  72. ;extrn  __fperror : far
  73. extrn   __fperror : near
  74. ExtProc@        abort,  __CDECL__       ; called if init fails
  75. ;extrn  _abort : near                   ; called if init fails
  76.  
  77. ;-----------------------------------------------------------------------------
  78.  
  79. FpuPriority     equ     16d
  80. StartupStack    equ     24      ; must be even
  81.  
  82. ; debug symbols
  83. ifdef   DEBUG
  84. public  int2handler
  85. public  int75handler
  86. public  emu1st
  87. public  emuLast
  88. public  init87
  89. ;public failure
  90. ;public __fpustate
  91. endif
  92.  
  93.         PAGE
  94. ;[]------------------------------------------------------------[]
  95. ;|                                                              |
  96. ;|      General notes                                           |
  97. ;|      =============                                           |
  98. ;|                                                              |
  99. ;|      Emu086 is  designed to run  in either of  two modes:    |
  100. ;|      with   or   without   the   presence   of  the  8087    |
  101. ;|      co-processor. The  first action it takes  is to test    |
  102. ;|      for the  presence of the co-processor.  Depending on    |
  103. ;|      which it  finds, it connects  one of two  modules to    |
  104. ;|      the   interrupt   vectors   reserved   for   numeric    |
  105. ;|      coprocessor emulation.                                  |
  106. ;|                                                              |
  107. ;|      E087ENTR.ASM ("Real-87")                                |
  108. ;|                                                              |
  109. ;|      This module  is to be  used when there  is hardware     |
  110. ;|      support.  It  is  much  the  smaller  module.  This     |
  111. ;|      module will service 10  interrupt vectors (34h thru     |
  112. ;|      3Dh) which are used for floating point invocation by    |
  113. ;|      application  programs.  For  the first eight of  the    |
  114. ;|      vectors  plus some  functions of  the ninth, Real-87    |
  115. ;|      will patch  the calling program with  the equivalent    |
  116. ;|      8087  instruction  sequence  and  then  restart  the    |
  117. ;|      program to run the  patch. The application will thus    |
  118. ;|      be  converted  at  run  time   to  the  use  of  the    |
  119. ;|      co-processor.                                           |
  120. ;|                                                              |
  121. ;|      The non-converted  functions of the  ninth interrupt    |
  122. ;|      are transcendental  functions not directly  provided    |
  123. ;|      by the 8087. These  functions must be interpreted by    |
  124. ;|      a library  provided in Real-87, which  uses the 8087    |
  125. ;|      for computations.                                       |
  126. ;|                                                              |
  127. ;|      The  tenth   interrupt  is  used  for   a  NOP-FWAIT    |
  128. ;|      sequence. It is  patched the first time it  is used,    |
  129. ;|      like the other direct iNDP instructions.                |
  130. ;|                                                              |
  131. ;|      The  shortcut  vector  is  used  for instructions or    |
  132. ;|      sequences frequently  used by the compiler.  Some of    |
  133. ;|      them  are  equivalent  to  '87  instructions,  while    |
  134. ;|      others cannot be reduced  to a simple sequence. When    |
  135. ;|      the '87  is present the  direct equivalents will  be    |
  136. ;|      patched  with  in-line  code,  while  the  composite    |
  137. ;|      sequences are excuted in the interrupt routine.         |
  138. ;|                                                              |
  139. ;|      E086ENTR.ASM ("Virtual-87")                             |
  140. ;|                                                              |
  141. ;|      The Virtual-87 module is to be used when the 8087 is    |
  142. ;|      not  present.  It  supplies  all  code  necessary to    |
  143. ;|      emulate the  8087 (excepting some rare  details. See    |
  144. ;|      the   description   in   the   general   notes   for    |
  145. ;|      e086Entr.asm).  No  patching  occurs  in  this case,    |
  146. ;|      except for the tenth  interrupt which can be patched    |
  147. ;|      to a No-op sequence.                                    |
  148. ;|                                                              |
  149. ;[]------------------------------------------------------------[]
  150.  
  151.         PAGE
  152. ;[]------------------------------------------------------------[]
  153. ;|                                                              |
  154. ;|      FIXUP constants for FPU                                 |
  155. ;|                                                              |
  156. ;|      If none of the F??RQQ publics are used, then no         |
  157. ;|      floating point code will be linked.                     |
  158. ;|                                                              |
  159. ;[]------------------------------------------------------------[]
  160.  
  161. emInt           equ     34h     ; allocated to 8087 by Microsoft Corp.
  162. shortcutInt     equ     3Eh     ; used by Borland for shortcuts
  163. fpuInt          equ     02h     ; FPU interrupt number (normally = NMI)
  164.  
  165.         public  FIDRQQ          ; wait, esc
  166.         public  FIARQQ          ; wait, DS:
  167.         public  FICRQQ          ; wait, CS:
  168.         public  FIERQQ          ; wait, ES:
  169.         public  FISRQQ          ; wait, SS:
  170.         public  FIWRQQ          ; nop, wait
  171.         public  FJARQQ          ; Esc nn -> DS:nn
  172.         public  FJCRQQ          ; Esc nn -> CS:nn
  173.         public  FJSRQQ          ; Esc nn -> ES:nn
  174.  
  175.  
  176. ; Use full emulator if _Emu_ is true.
  177.  
  178. if      _Emu_
  179.  
  180. FIDRQQ  equ     05C32h
  181. FIARQQ  equ     0FE32h
  182. FICRQQ  equ     00E32h
  183. FIERQQ  equ     01632h
  184. FISRQQ  equ     00632h
  185. FIWRQQ  equ     0A23Dh
  186. FJARQQ  equ     04000h
  187. FJCRQQ  equ     0C000h
  188. FJSRQQ  equ     08000h
  189.  
  190. else
  191.  
  192. FIDRQQ  equ     00000h
  193. FIARQQ  equ     00000h
  194. FICRQQ  equ     00000h
  195. FIERQQ  equ     00000h
  196. FISRQQ  equ     00000h
  197. FIWRQQ  equ     00000h
  198. FJARQQ  equ     00000h
  199. FJCRQQ  equ     00000h
  200. FJSRQQ  equ     00000h
  201.  
  202. endif
  203.  
  204.         PAGE
  205. ;[]------------------------------------------------------------[]
  206. ;|                                                              |
  207. ;|      Emulator entry points                                   |
  208. ;|                                                              |
  209. ;[]------------------------------------------------------------[]
  210.  
  211. if      _Emu_
  212. ; This is the segment containing the full emulation code.
  213. EmuSeg@
  214. EXTRN   e086_Entry      : FAR
  215. EXTRN   e086_Shortcut   : FAR
  216. EmuSegEnd@
  217. endif
  218.  
  219. ; This is the segment containing the code to work with the 8087 chip.
  220. E87Seg@
  221. EXTRN   e087_Entry      : FAR
  222. EXTRN   e087_Shortcut   : FAR
  223. EXTRN   e087_Trap       : FAR
  224. E87SegEnd@
  225.  
  226.         PAGE
  227.  
  228. CSeg@
  229.  
  230.         PAGE
  231. ;[]------------------------------------------------------------[]
  232. ;|                                                              |
  233. ;|      emu1st -- Emulator installation routine                 |
  234. ;|                                                              |
  235. ;|      This  function  is  called  by  RTLstart  before any    |
  236. ;|      numeric work  begins. It needs  to save the  initial    |
  237. ;|      interrupt vectors  before it can install  itself.       |
  238. ;|                                                              |
  239. ;|      It will sense whether an iNDP87 co-processor exists,    |
  240. ;|      only if the _8087 variable is set to -1, which means    |
  241. ;|      that no "87" environment  variable has been defined.    |
  242. ;|      In that case it will choose which of the two numeric    |
  243. ;|      support modules is to be kept. The interrupt vectors    |
  244. ;|      34..3D  are  claimed  for  iNDP  software  interrupt    |
  245. ;|      support.                                                |
  246. ;|                                                              |
  247. ;|      An  additional  interrupt,  3Eh,  is  used  for  the    |
  248. ;|      Shortcut entries.                                       |
  249. ;|                                                              |
  250. ;|      The __fpreset function installs the interrupt vectors   |
  251. ;|      and  re-initializes the  emulator. This  function is    |
  252. ;|      called by the _fpreset() function of the RTL.           |
  253. ;|                                                              |
  254. ;[]------------------------------------------------------------[]
  255.  
  256. ; vectors 34h .. 3Eh, and 75h, and 2
  257. originalVectors dd      12 DUP (?)
  258. FPEpriorVector  dd      ?               ; interrupt handler for NMI
  259.  
  260. plus_inf        dd      7F800000R       ; + infinity
  261.  
  262. ; borrowed from T. Pascal, DOS 3.1 BIOS
  263. ; avoid DOS 3.2 stack swap
  264. int75handler    proc    far
  265.         push    ax
  266.         xor     al, al                  ; Clear BUSY latch
  267.         out     0F0h, al
  268.         mov     al, 20H                 ; End-of-interrupt
  269.         out     0A0h, al
  270.         out     20h, al
  271.         pop     ax
  272.         int     2
  273.         iret
  274. int75handler    endp
  275.  
  276.  
  277. ; Floating point exceptions on  PC-compatible machines are routed
  278. ;       to the NMI  vector. This vector must be  captured but the
  279. ;       previous contents need to  be remembered. The priorVector
  280. ;       is  used if NMI occurs  but the coprocessor did not cause
  281. ;       it, and also the priorVector  must be restored at the end
  282. ;       of the program.
  283.  
  284. OpJmpf          equ     0EAh            ; opcode for far jump
  285.  
  286. int2handler     proc    far
  287.         push    ax
  288.         mov     ax, seg __emu
  289.         call    e087_Trap       ; preserves all but ax, flags
  290. ret_trap:
  291. ; returns only if error could not be handled
  292.         jc      @@err
  293.         pop     ax
  294. ;       jmp     FPEpriorVector
  295.         db      OpJmpf
  296. nmi     dw      2 dup (?)
  297.  
  298. @@err:
  299. ; trap record in ss:ax
  300. ;       mov     bx, ax
  301.         xchg    bx, ax
  302. ; Set DS := DGROUP
  303.         mov     ax, seg _8087@
  304.         mov     DS, ax
  305.         call    __fperror
  306.         pop     ax
  307.         iret
  308. int2handler     endp
  309.  
  310. ifdef   VarStack
  311.  
  312. abortMSG        db      "Insufficient FPU or CPU stack.", 13, 10
  313. lgth_abortMSG   equ     $ - abortMSG
  314.  
  315. failure proc    near
  316.         mov     ah, 040h
  317.         mov     bx, 2
  318.         mov     cx, lgth_abortMSG
  319.         mov     dx, offset abortMSG
  320.         push    CS
  321.         pop     DS
  322.         MSDOS@                  ; write message at DS:DX
  323.         call    abort@
  324. ; never returns
  325. failure endp
  326.  
  327. endif
  328.  
  329. emu1st  proc    near            ; called only by startup code
  330.         push    DS
  331.         push    si
  332.         push    di
  333.  
  334. ifdef   VarStack
  335.  
  336. ; Make some space on the stack.
  337.  
  338.         mov     ax, seg _fpstklen@
  339.         mov     ES, ax
  340.         mov     ax, ES:_fpstklen@
  341.         and     al, 0FEh                ; round to even
  342.         mov     dx, seg _stklen@
  343.         mov     ES, dx
  344.         cmp     ax, ES:_stklen@
  345.         jae     failure
  346.         cmp     ax, MinFpStack
  347.         jb      failure
  348.  
  349.         mov     cx, StartupStack
  350.         mov     si, sp
  351.         add     ax, cx
  352.         sub     sp, ax
  353.         mov     di, sp
  354.  
  355. ; set start of FPU stack
  356. ; leave a spare to trap emulated underflows
  357.         lea     ax, [si-size_emu_temp]
  358.         mov     SS:__emu.ws_initSP, ax
  359.  
  360. ; move the stack down
  361.         mov     dx, SS
  362.         mov     DS, dx
  363.         mov     ES, dx
  364.         cld
  365.         shr     cx, 1
  366.         rep     movsw
  367.  
  368. ; set end of FPU stack
  369.         mov     SS:__emu.ws_lastSP, di
  370.  
  371. else
  372.  
  373. ; set end of FPU stack
  374.         lea     ax, __emu + (size fpu)
  375.         mov     SS:__emu.ws_lastSP, ax
  376.  
  377. ; set start of FPU stack
  378. ; leave a spare to trap emulated underflows
  379.         add     ax, MinFpStack - size_emu_temp
  380.         mov     SS:__emu.ws_initSP, ax
  381.  
  382. endif
  383.  
  384. ; Save prior vectors in the code segment.
  385. ; If in protected mode, make the segment writeable.
  386. ; Save _protected in SS where FPU can find it.
  387.  
  388.         mov     ax, _LDT@
  389.         mov     SS:__emu.ws_LDT, ax
  390.         mov     al, _protected@
  391.         mov     SS:__emu.ws_protected, al
  392.         mov     cx, CS
  393.         xor     cl, al                  ; al = 0 or 8
  394.         mov     DS, cx
  395.  
  396.         ASSUME  DS:_TEXT
  397.  
  398.         mov     ax, 3500h + emInt
  399.         mov     cx, 11          ; there are 10 emulation vectors
  400.         mov     di, offset originalVectors
  401. rememberLoop:
  402.         MSDOS@                  ; ES:BX = read interrupt vector
  403.         mov     DS:[di].W0, bx
  404.         mov     DS:[di].W1, ES
  405.         add     di, 4
  406.         inc     ax
  407.         loop    rememberLoop
  408.  
  409. ; grab INT 75h
  410.         mov     ax,3500h + 75h
  411.         MSDOS@                  ; ES:BX = read interrupt vector
  412.         mov     DS:[di].W0, bx
  413.         mov     DS:[di].W1, ES
  414.         add     di, 4
  415.  
  416. ; grab INT 2
  417.         mov     ax,3500h + fpuInt
  418.         MSDOS@                  ; ES:BX = read interrupt vector
  419.         mov     DS:[di].W0, bx
  420.         mov     DS:[di].W1, ES
  421.         mov     DS:nmi[0], bx
  422.         mov     DS:nmi[2], ES
  423.  
  424. ; Set DS := DGROUP
  425.         mov     ax, seg _8087@
  426.         mov     DS, ax
  427.  
  428.         ASSUME  CS:_TEXT, DS:seg _8087@
  429.  
  430. ; Do we need to test 80?87 presence ?
  431.  
  432.         mov     bx, -1
  433. if      _Emu_
  434.         mov     ES, _psp@
  435.  
  436. ; Look for a "87" environment variable.
  437. ; Each variable is ended by a 0 and a zero-length variable stops
  438. ; the environment. The environment can NOT be greater than 32k.
  439.  
  440.         mov     ES, ES: word ptr [2Ch]  ; environment segment
  441.         sub     di, di                  ; ES:[di] points to environ
  442.         mov     cx, 07FFFh              ; Environment cannot be > 32 Kbytes
  443.         mov     al, 0
  444.         cld
  445. env87next:
  446.         repne   scasb           ; direction flag is clear
  447.         jcxz    env87done       ; count exhausted imply end
  448.         cmp     al, ES:[di]     ; double zero bytes imply end
  449.         je      env87done
  450.         cmp     word ptr ES:[di], 3738h         ; low = '8', hi = '7'
  451.         jne     env87next
  452.         mov     dx, ES:[di+2]
  453.         cmp     dl, '='
  454.         jne     env87next
  455.         inc     bx
  456.         and     dh, not ('y' - 'Y')
  457.         cmp     dh, 'Y'
  458.         jne     env87done
  459.         inc     bx
  460. env87done:
  461. endif
  462.         pop     di
  463.         pop     si
  464.  
  465. ;[]------------------------------------------------------------[]
  466. ;|                                                              |
  467. ;|      Co-processor autosense routine                          |
  468. ;|                                                              |
  469. ;|      Note:   The code used to test the presence of a         |
  470. ;|              numeric coprocessor is similar to that          |
  471. ;|              recommended by IBM.                             |
  472. ;|                                                              |
  473. ;[]------------------------------------------------------------[]
  474.  
  475. ; If  CPU is  an 80286,  the FNINIT  instruction can  generate an
  476. ;       interrupt  if  the  NDP?87  is  not  present.  On IBM, an
  477. ;       interrupt handler is provided by  the BIOS but it may NOT
  478. ;       on clones. So won't test if there is or not an NDP?87, we
  479. ;       will just trust the BIOS equipment flag.
  480.  
  481. ; IBM uses these ports to reset the coprocessor.
  482. ; Some clone have the ports wired incorrectly, in which case it may
  483. ; be necessary to delete the OUT instructions.
  484.  
  485. ; Check whether 87=N
  486.         or      bx, bx
  487.         jz      @@set_flag
  488.  
  489. ;       xor     ax, ax
  490. ;       out     0F0h, al        ; Clear the busy latch (INT REQ)
  491. ;       out     0F1h, al        ; Reset chip in real mode
  492.  
  493. ; Distinguish between 8088/8086 and 80286/80386.
  494.         push    sp
  495.         pop     cx
  496.         cmp     cx, sp
  497.         jne     TestPresence
  498.  
  499. ; Possibly override BIOS test.
  500.         or      bx, bx
  501.         jg      @@test_inf
  502.  
  503. ; The CPU is an 80286 or 80386, so trust the BIOS equipment flag.
  504.         int     11h
  505.         and     al, 2
  506.         jz      @@test_done             ; jump with al = 0
  507.  
  508. ; Distinguish between a 80287 and 80387 using the infinity control.
  509. ; 8087 and 80287 support both infinity modes, defaults to projective
  510. ; 80387 supports affine infinity only
  511.  
  512. @@test_inf:
  513. ;       xor     ax, ax
  514. ;       out     0F0h, al        ; Clear the busy latch (INT REQ)
  515. ;       out     0F1h, al        ; Reset chip in real mode
  516.  
  517.         fninit
  518. ifdef   Intel_Test
  519.         fld1
  520.         fldz
  521.         fdiv                    ; generate infinity
  522.         fld     st              ; duplicate TOS
  523.         fchs                    ; form -INF
  524.         fcompp                  ; compare +INF to -INF
  525. else
  526.         fld     plus_inf
  527.         fchs
  528.         fcomp   plus_inf        ; compare +INF to -INF
  529. endif
  530.         fstsw   ax              ; we have a 287 or better
  531.         sahf
  532.  
  533.         mov     al, 2
  534.         je      @@test_done     ; equal on 80287 only
  535.         inc     al
  536.         jmp     short @@test_done
  537.  
  538. ; First check to see if a real 8087 is available. That allows
  539. ;       us to select which version of NDP support is to remain
  540. ;       resident.
  541.  
  542. TestPresence:
  543. ;       xor     ax, ax
  544. ;       out     0F0h, al        ; Clear the busy latch (INT REQ)
  545.         FNINIT
  546.         mov     _8087@, 0
  547.         FNSTCW  _8087@          ; Store the control word
  548.  
  549.         mov     cx, 20
  550.         loop    this near               ; Delay awhile
  551.         mov     cx, _8087@              ; Get NPX control word
  552.         and     cx, 0F3Fh               ; Mask off undefined bits
  553.         cmp     cx, 033Fh               ; Do we have a math coprocessor
  554.         jne     @@test_done             ; No ...
  555.  
  556.         mov     _8087@, -1
  557.         FNSTSW  _8087@                  ; Store the status word
  558.         mov     cx, 20
  559.         loop    this near               ; Delay awhile
  560.         test    _8087@, 0B8BFh          ; All bits off that should be?
  561.         jnz     @@test_done
  562.         inc     al
  563.  
  564. @@test_done:
  565.         cbw
  566.         xchg    ax, bx
  567.  
  568. @@set_flag:
  569.         mov     _8087@, bx
  570.         mov     SS:__emu.ws_8087, bl
  571.         pop     DS
  572. ; fall thru to reset everything
  573. emu1st  ENDP
  574.  
  575. temp1   equ     [bp-8]
  576. temp2   equ     [bp-4]
  577.  
  578. ___fpreset      proc    near
  579.         push    DS
  580.         push    bp
  581.         mov     bp, sp
  582.         sub     sp, 8
  583.  
  584.         mov     bx, seg _8087@
  585.         mov     DS, bx                  ; save DGROUP for later
  586.  
  587.         ASSUME  CS:_TEXT, DS:seg _8087@
  588.  
  589.         cmp     _8087@, 0
  590.         mov     temp1.W0, offset e087_Entry
  591.         mov     temp1.W1, seg e087_Entry
  592.         mov     temp2.W0, offset e087_Shortcut
  593.         mov     temp2.W1, seg e087_Shortcut
  594.  
  595. if      _Emu_
  596.         jne     doCapture
  597.         mov     temp1.W0, offset e086_Entry
  598.         mov     temp1.W1, seg e086_Entry
  599.         mov     temp2.W0, offset e086_Shortcut
  600.         mov     temp2.W1, seg e086_Shortcut
  601. endif
  602.  
  603. ; Now take over the vectors.
  604.  
  605. doCapture:
  606.         mov     ax, 2500h + emInt
  607.         mov     cx, 10          ; there are 10 emulation vectors
  608.         lds     dx, temp1.DD0
  609. captureLoop:
  610.         MSDOS@                  ; Set interrupt vector with DS:DX
  611.         inc     ax
  612.         loop    captureLoop
  613. ; The Shortcut vector must be captured too.
  614.  
  615.         mov     ax, 2500h + shortcutInt
  616.         lds     dx, temp2.DD0
  617.         MSDOS@                  ; Set interrupt vector with DS:DX
  618.  
  619. ; install INT 2 handler
  620.         mov     ax, 2500h + fpuInt
  621.         push    CS
  622.         pop     DS
  623.         mov     dx, offset int2handler
  624.         MSDOS@                  ; Set interrupt vector with DS:DX
  625.  
  626. ; No need for the INT 75 hack if
  627. ;       the 8087 is being emulated, or
  628. ;       the version of DOS different from 3.20
  629.         mov     DS, bx                  ; set DS = DGROUP
  630.         cmp     _8087@, 0
  631.         je      init87
  632.         mov     ax, _version@
  633.         xchg    ah, al
  634.         cmp     ax, 20 * 100h + 3       ; ok if version != 3.20
  635.         jne     init87
  636.  
  637. ; install INT 75 handler
  638.         mov     ax, 2500h + 75h
  639.         push    CS
  640.         pop     DS
  641.         mov     dx, offset int75handler
  642.         MSDOS@                  ; Set interrupt vector with DS:DX
  643.  
  644. ; Now emulation is installed. Ensure it is initialized.
  645. ; We must use an emulated FINIT in all cases.
  646. init87:
  647.         Int     emInt + 3
  648.         db      0E3h            ; (Wait, FINIT) equivalent
  649.         mov     SS:__emu.ecount1, 0
  650.         mov     SS:__emu.ecount2, 0
  651.  
  652. ; FINIT will disable all exception interrupts.  We want some enabled.
  653.         mov     DS, bx                  ; set DS = DGROUP
  654. ;       mov     temp1.W0, CW_DEFAULT
  655.         mov     ax, _default87@
  656.         mov     temp1.W0, ax
  657.  
  658. ; 80387 is fully IEEE, need not trap denormal exception
  659.         cmp     _8087@, 3
  660.         jl      @@control
  661.         or      temp1.W0, EM_DENORMAL
  662. @@control:
  663.         emul
  664.         FLDCW   temp1.W0
  665. ; set shadow control
  666.         mov     ax, temp1.W0
  667.         and     SS:__emu.ws_control, ax
  668.  
  669. ; dual mode startup requires AX=DX=0
  670.         xor     ax, ax
  671.         cwd
  672.  
  673.         mov     sp, bp
  674.         pop     bp
  675.         pop     DS
  676.         ret
  677. ___fpreset      endp
  678.  
  679.         PAGE
  680. ;[]------------------------------------------------------------[]
  681. ;|                                                              |
  682. ;|      emuLast -- Emulator termination routine                 |
  683. ;|                                                              |
  684. ;|      emuLast  is called  by RTLstart  after the  "main"      |
  685. ;|      routine returns or the program exits. Its purpose is    |
  686. ;|      to  restore the  original contents  of the interrupt    |
  687. ;|      vectors 34h..3Dh, plus the Shortcut vector.             |
  688. ;|                                                              |
  689. ;[]------------------------------------------------------------[]
  690.  
  691. emuLast proc    near    ; called only by startup code
  692.         push    DS
  693.  
  694. ; Set DS := DGROUP
  695.         mov     ax, seg _8087@
  696.         mov     DS, ax
  697.  
  698.         ASSUME  CS:_TEXT, DS:seg _8087@
  699.  
  700. ; Did we ever get initialized?
  701.         cmp     _8087@, 0
  702.         jl      @@done
  703.  
  704. ; leave the chip in a clean state
  705.         emul
  706.         finit
  707.  
  708.         mov     ax, 2500h + emInt
  709.         mov     bx, offset originalVectors
  710.         mov     cx, 11          ; there are 10 emulation vectors
  711. restoreLoop:
  712.         lds     dx, CS:[bx]
  713.         MSDOS@                  ; Set interrupt vector with DS:DX
  714.         add     bx, 4
  715.         inc     ax
  716.         loop    restoreLoop
  717.  
  718. ; restore INT 75h
  719.         mov     ax, 2500h + 75h
  720.         lds     dx, CS:[bx]
  721.         MSDOS@                  ; Set interrupt vector with DS:DX
  722.  
  723. ; restore INT 2
  724.         mov     ax, 2500h + fpuInt
  725.         lds     dx, CS:[bx+4]
  726.         MSDOS@                  ; Set interrupt vector with DS:DX
  727.  
  728. @@done:
  729.         pop     DS
  730.         ret
  731. emuLast endp
  732.  
  733. ifdef   VarStack
  734.  
  735. ; clean off all '87 registers, put chip in a predictable state
  736. ; preserves all but bx, cx, flags
  737. ; no segment assumptions other than SS
  738. ; leave current FPU stack pointer in a word at SS:bx
  739. ; void far cdecl fpustate(void);
  740.  
  741. public  __fpustate
  742.  
  743. __fpustate      proc    far
  744.         cmp     SS:__emu.ws_8087, 0
  745.         je      @@ret
  746.         noemul
  747. ; fill the '87
  748.         mov     cx, 8
  749. @@1:    fldz
  750.         loop    @@1
  751.         fcom    st(7)
  752. ; empty the '87
  753.         mov     cl, 8
  754. @@2:    fstp    st(0)
  755.         loop    @@2
  756. ; put the '87 in a predictable state
  757.         mov     cx, SS:__emu.ws_adjust
  758.         and     cx, 111b
  759.         jz      @@4
  760. @@3:    fincstp
  761.         loop    @@3
  762. @@4:
  763.         mov     SS:__emu.ws_adjust, cx          ; cx = 0
  764. @@ret:
  765.         lea     bx, SS:__emu.ws_TOS
  766.         ret
  767. __fpustate      endp
  768.  
  769. endif
  770.  
  771. ;[]------------------------------------------------------------[]
  772. ;|                                                              |
  773. ;|      __fpuint - return FPU interrupt number                  |
  774. ;|                                                              |
  775. ;|      This function returns the FPU exception number in AX.   |
  776. ;|      Used by emudecod.asm.                                   |
  777. ;|                                                              |
  778. ;[]------------------------------------------------------------[]
  779.  
  780.         public  __fpuint
  781.  
  782. __fpuint        proc    far
  783.         mov     ax, fpuInt
  784.         ret
  785. __fpuint        endp
  786.  
  787. CSegEnd@
  788.  
  789. ifdef   VarStack
  790.  
  791. _EMUSEG SEGMENT PARA COMMON 'DATA'
  792.         dw      __fpustate
  793. _EMUSEG ENDS
  794.  
  795. endif
  796.  
  797.         PAGE
  798. ;[]------------------------------------------------------------[]
  799. ;|                                                              |
  800. ;|      FPU automatic initialization logic                      |
  801. ;|                                                              |
  802. ;[]------------------------------------------------------------[]
  803.  
  804. PNEAR           EQU     0
  805. PFAR            EQU     1
  806. NOTUSED         EQU     0ffh
  807.  
  808. SE              STRUC
  809. calltype        db      ?                       ; 0=near,1=far,ff=not used
  810. priority        db      ?                       ; 0=highest,ff=lowest
  811. addrlow         dw      ?
  812. IFNDEF  __TINY__
  813. addrhigh        dw      ?
  814. ENDIF
  815. SE              ENDS
  816.  
  817. _INIT_          SEGMENT WORD PUBLIC 'INITDATA'
  818. ;SE     < PFAR, FpuPriority, offset emu1st, seg emu1st >
  819. SE      < PNEAR, FpuPriority, offset emu1st, 0 >
  820. _INIT_          ENDS
  821.  
  822. _EXIT_          SEGMENT WORD PUBLIC 'EXITDATA'
  823. ;SE     < PFAR, FpuPriority, offset emuLast, seg emuLast >
  824. SE      < PNEAR, FpuPriority, offset emuLast, 0 >
  825. _EXIT_          ENDS
  826.  
  827. END
  828.