home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c065 / 2.ddi / MATH.ZIP / FPINIT.ASM < prev    next >
Encoding:
Assembly Source File  |  1990-06-07  |  19.3 KB  |  806 lines

  1. ;/* MODES: TAB 8 */
  2.  
  3.     NAME    fpInit
  4.  
  5. ;[]------------------------------------------------------------[]
  6. ;|    FPINIT.ASM -- Emulator initialization            |
  7. ;|                                |
  8. ;|    Turbo C++ Run Time Library                              |
  9. ;|                                |
  10. ;|    Copyright (c) 1990 by Borland International Inc.    |
  11. ;|    All Rights Reserved.                    |
  12. ;[]------------------------------------------------------------[]
  13.  
  14. ; Floating point (FPU) initialization.
  15. ; Includes detection of coprocessor, checking for environment override
  16. ; (SET 87=N), installation of interrupt vectors, and FINIT.
  17.  
  18. ; This module replaces EMUINIT and 87INIT, both used in TC 2.0.
  19. ; It also replaces some code in C0 related to floating point.
  20. ; Assemble with /DFP87 for hard 80x87 opcodes.
  21.  
  22. ; Caution: This code is in the _TEXT segment, and assumes that certain
  23. ; external routines can be called with NEAR calls.
  24.  
  25. .287
  26. locals    @@
  27.  
  28. include equates.asi
  29.  
  30. ifdef    FP87
  31. _Emu_    equ    0        ; no emulation, '87 required
  32. else
  33. _Emu_    equ    1        ; emulator
  34. endif
  35.  
  36. include emurules.asi
  37. include    emuvars.asi
  38.  
  39. ; Segment and Group declarations
  40.  
  41. Header@
  42.  
  43. DSeg@
  44.  
  45. ; Public data
  46. ; initialize to -1
  47. ; if executed, emu1st will change it to 0, 1, 2, or 3
  48. PubSym@        _8087,    <dw    -1>,    __CDECL__
  49.  
  50. ; External References
  51. ExtSym@        _version, WORD, __CDECL__
  52. ExtSym@        _psp, WORD, __CDECL__
  53. ExtSym@        _protected, BYTE, __CDECL__
  54. ExtSym@        _LDT, WORD, __CDECL__
  55. ExtSym@        _default87, WORD, __CDECL__
  56.  
  57. DSegEnd@
  58.  
  59. ; External data, possibly not in DGROUP.
  60. ExtSym@        _fpstklen, word, __CDECL__
  61. ExtSym@        _stklen, word, __CDECL__
  62. extrn    __turboCvt : ABS    ; To force the link of REALCVT for printf
  63. extrn    __emu : byte
  64.  
  65. EmuAssume@    SS
  66.  
  67. ; Public procs.
  68.  
  69. public    ___fpreset
  70.  
  71. ; External procs.
  72.  
  73. ;extrn    __fperror : far
  74. extrn    __fperror : near
  75. ExtProc@    abort,    __CDECL__    ; called if init fails
  76. ;extrn    _abort : near            ; called if init fails
  77.  
  78. ;-----------------------------------------------------------------------------
  79.  
  80. FpuPriority    equ    16d
  81. StartupStack    equ    24    ; must be even
  82.  
  83. ; debug symbols
  84. ifdef    DEBUG
  85. public    int2handler
  86. public    int75handler
  87. public    emu1st
  88. public    emuLast
  89. public    init87
  90. ;public    failure
  91. ;public    __fpustate
  92. endif
  93.  
  94.     PAGE
  95. ;[]------------------------------------------------------------[]
  96. ;|                                |
  97. ;|      General notes                        |
  98. ;|      =============                        |
  99. ;|                                |
  100. ;|      Emu086 is  designed to run  in either of  two modes:    |
  101. ;|      with   or   without   the   presence   of  the  8087    |
  102. ;|      co-processor. The  first action it takes  is to test    |
  103. ;|      for the  presence of the co-processor.  Depending on    |
  104. ;|      which it  finds, it connects  one of two  modules to    |
  105. ;|      the   interrupt   vectors   reserved   for   numeric    |
  106. ;|      coprocessor emulation.                    |
  107. ;|                                |
  108. ;|      E087ENTR.ASM ("Real-87")                |
  109. ;|                                |
  110. ;|      This module  is to be  used when there  is hardware     |
  111. ;|      support.  It  is  much  the  smaller  module.  This     |
  112. ;|      module will service 10  interrupt vectors (34h thru     |
  113. ;|      3Dh) which are used for floating point invocation by    |
  114. ;|      application  programs.  For  the first eight of  the    |
  115. ;|      vectors  plus some  functions of  the ninth, Real-87    |
  116. ;|      will patch  the calling program with  the equivalent    |
  117. ;|      8087  instruction  sequence  and  then  restart  the    |
  118. ;|      program to run the  patch. The application will thus    |
  119. ;|      be  converted  at  run  time   to  the  use  of  the    |
  120. ;|      co-processor.                        |
  121. ;|                                |
  122. ;|      The non-converted  functions of the  ninth interrupt    |
  123. ;|      are transcendental  functions not directly  provided    |
  124. ;|      by the 8087. These  functions must be interpreted by    |
  125. ;|      a library  provided in Real-87, which  uses the 8087    |
  126. ;|      for computations.                    |
  127. ;|                                |
  128. ;|      The  tenth   interrupt  is  used  for   a  NOP-FWAIT    |
  129. ;|      sequence. It is  patched the first time it  is used,    |
  130. ;|      like the other direct iNDP instructions.        |
  131. ;|                                |
  132. ;|      The  shortcut  vector  is  used  for instructions or    |
  133. ;|      sequences frequently  used by the compiler.  Some of    |
  134. ;|      them  are  equivalent  to  '87  instructions,  while    |
  135. ;|      others cannot be reduced  to a simple sequence. When    |
  136. ;|      the '87  is present the  direct equivalents will  be    |
  137. ;|      patched  with  in-line  code,  while  the  composite    |
  138. ;|      sequences are excuted in the interrupt routine.        |
  139. ;|                                |
  140. ;|      E086ENTR.ASM ("Virtual-87")                |
  141. ;|                                |
  142. ;|      The Virtual-87 module is to be used when the 8087 is    |
  143. ;|      not  present.  It  supplies  all  code  necessary to    |
  144. ;|      emulate the  8087 (excepting some rare  details. See    |
  145. ;|      the   description   in   the   general   notes   for    |
  146. ;|      e086Entr.asm).  No  patching  occurs  in  this case,    |
  147. ;|      except for the tenth  interrupt which can be patched    |
  148. ;|      to a No-op sequence.                    |
  149. ;|                                |
  150. ;[]------------------------------------------------------------[]
  151.  
  152.     PAGE
  153. ;[]------------------------------------------------------------[]
  154. ;|                                |
  155. ;|    FIXUP constants for FPU                    |
  156. ;|                                |
  157. ;|    If none of the F??RQQ publics are used, then no        |
  158. ;|    floating point code will be linked.            |
  159. ;|                                |
  160. ;[]------------------------------------------------------------[]
  161.  
  162. emInt        equ    34h     ; allocated to 8087 by Microsoft Corp.
  163. shortcutInt    equ    3Eh     ; used by Borland for shortcuts
  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 + 2h
  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:DGROUP
  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.     xor    ax, ax
  486.     out    0F0h, al    ; Clear the busy latch (INT REQ)
  487.     out    0F1h, al    ; Reset chip in real mode
  488.  
  489. ; Distinguish between 8088/8086 and 80286/80386.
  490.     push    sp
  491.     pop    cx
  492.     cmp    cx, sp
  493.     jne    TestPresence
  494.  
  495. ; Possibly override BIOS test.
  496.     or    bx, bx
  497.     jg    @@test_inf
  498.     jz    @@set_flag
  499.  
  500. ; The CPU is an 80286 or 80386, so trust the BIOS equipment flag.
  501.     int    11h
  502.     and    al, 2
  503.     jz    @@test_done        ; jump with al = 0
  504.  
  505. ; Distinguish between a 80287 and 80387 using the infinity control.
  506. ; 8087 and 80287 support both infinity modes, defaults to projective
  507. ; 80387 supports affine infinity only
  508.  
  509. @@test_inf:
  510. ;    xor    ax, ax
  511. ;    out    0F0h, al    ; Clear the busy latch (INT REQ)
  512. ;    out    0F1h, al    ; Reset chip in real mode
  513.  
  514.     fninit
  515. ifdef    Intel_Test
  516.     fld1
  517.     fldz
  518.     fdiv            ; generate infinity
  519.     fld    st        ; duplicate TOS
  520.     fchs            ; form -INF
  521.     fcompp            ; compare +INF to -INF
  522. else
  523.     fld    plus_inf
  524.     fchs
  525.     fcomp    plus_inf    ; compare +INF to -INF
  526. endif
  527.     fstsw    ax        ; we have a 287 or better
  528.     sahf
  529.  
  530.     mov    al, 2
  531.     je    @@test_done    ; equal on 80287 only
  532.     inc    al
  533.     jmp    short @@test_done
  534.  
  535. ; First check to see if a real 8087 is available. That allows
  536. ;    us to select which version of NDP support is to remain
  537. ;    resident.
  538.  
  539. TestPresence:
  540. ;    xor    ax, ax
  541. ;    out    0F0h, al    ; Clear the busy latch (INT REQ)
  542.     FNINIT
  543.     mov    _8087@, 0
  544.     FNSTCW    _8087@        ; Store the control word
  545.  
  546.     mov    cx, 20
  547.     loop    this near        ; Delay awhile
  548.     mov    cx, _8087@        ; Get NPX control word
  549.     and    cx, 0F3Fh        ; Mask off undefined bits
  550.     cmp    cx, 033Fh        ; Do we have a math coprocessor
  551.     jne    @@test_done        ; No ...
  552.  
  553.     mov    _8087@, -1
  554.     FNSTSW    _8087@            ; Store the status word
  555.     mov    cx, 20
  556.     loop    this near        ; Delay awhile
  557.     test    _8087@, 0B8BFh        ; All bits off that should be?
  558.     jnz    @@test_done
  559.     inc    al
  560.  
  561. @@test_done:
  562.     cbw
  563.     xchg    ax, bx
  564.  
  565. @@set_flag:
  566.     mov    _8087@, bx
  567.     mov    SS:__emu.ws_8087, bl
  568.     pop    DS
  569. ; fall thru to reset everything
  570. emu1st    ENDP
  571.  
  572. temp1    equ    [bp-8]
  573. temp2    equ    [bp-4]
  574.  
  575. ___fpreset    proc    near
  576.     push    DS
  577.     push    bp
  578.     mov    bp, sp
  579.     sub    sp, 8
  580.  
  581.     mov    bx, seg _8087@
  582.     mov    DS, bx            ; save DGROUP for later
  583.     cmp    _8087@, 0
  584.     mov    temp1.W0, offset e087_Entry
  585.     mov    temp1.W1, seg e087_Entry
  586.     mov    temp2.W0, offset e087_Shortcut
  587.     mov    temp2.W1, seg e087_Shortcut
  588.  
  589. if    _Emu_
  590.     jne    doCapture
  591.     mov    temp1.W0, offset e086_Entry
  592.     mov    temp1.W1, seg e086_Entry
  593.     mov    temp2.W0, offset e086_Shortcut
  594.     mov    temp2.W1, seg e086_Shortcut
  595. endif
  596.  
  597. ; Now take over the vectors.
  598.  
  599. doCapture:
  600.     mov    ax, 2500h + emInt
  601.     mov    cx, 10        ; there are 10 emulation vectors
  602.     lds    dx, temp1.DD0
  603. captureLoop:
  604.     MSDOS@            ; Set interrupt vector with DS:DX
  605.     inc    ax
  606.     loop    captureLoop
  607. ; The Shortcut vector must be captured too.
  608.  
  609.     mov    ax, 2500h + shortcutInt
  610.     lds    dx, temp2.DD0
  611.     MSDOS@            ; Set interrupt vector with DS:DX
  612.  
  613. ; install INT 2 handler
  614.     mov    ax, 2500h + 2
  615.     push    CS
  616.     pop    DS
  617.     mov    dx, offset int2handler
  618.     MSDOS@            ; Set interrupt vector with DS:DX
  619.  
  620. ; No need for the INT 75 hack if
  621. ;    the 8087 is being emulated, or
  622. ;    the version of DOS different from 3.20
  623.     mov    DS, bx            ; set DS = DGROUP
  624.     cmp    _8087@, 0
  625.     je    init87
  626.     mov    ax, _version@
  627.     xchg    ah, al
  628.     cmp    ax, 20 * 100h + 3    ; ok if version != 3.20
  629.     jne    init87
  630.  
  631. ; install INT 75 handler
  632.     mov    ax, 2500h + 75h
  633.     push    CS
  634.     pop    DS
  635.     mov    dx, offset int75handler
  636.     MSDOS@            ; Set interrupt vector with DS:DX
  637.  
  638. ; Now emulation is installed. Ensure it is initialized.
  639. ; We must use an emulated FINIT in all cases.
  640. init87:
  641.     Int    emInt + 3
  642.     db    0E3h        ; (Wait, FINIT) equivalent
  643.     mov    SS:__emu.ecount1, 0
  644.     mov    SS:__emu.ecount2, 0
  645.  
  646. ; FINIT will disable all exception interrupts.  We want some enabled.
  647.     mov    DS, bx            ; set DS = DGROUP
  648. ;    mov    temp1.W0, CW_DEFAULT
  649.     mov    ax, _default87@
  650.     mov    temp1.W0, ax
  651.  
  652. ; 80387 is fully IEEE, need not trap denormal exception
  653.     cmp    _8087@, 3
  654.     jl    @@control
  655.     or    temp1.W0, EM_DENORMAL
  656. @@control:
  657.     emul
  658.     FLDCW    temp1.W0
  659. ; set shadow control
  660.     mov    ax, temp1.W0
  661.     and    SS:__emu.ws_control, ax
  662.  
  663. ; dual mode startup requires AX=DX=0
  664.     xor    ax, ax
  665.     cwd
  666.  
  667.     mov    sp, bp
  668.     pop    bp
  669.     pop    DS
  670.     ret
  671. ___fpreset    endp
  672.  
  673.     PAGE
  674. ;[]------------------------------------------------------------[]
  675. ;|                                |
  676. ;|      emuLast -- Emulator termination routine            |
  677. ;|                                |
  678. ;|      emuLast  is called  by RTLstart  after the  "main"    |
  679. ;|      routine returns or the program exits. Its purpose is    |
  680. ;|      to  restore the  original contents  of the interrupt    |
  681. ;|      vectors 34h..3Dh, plus the Shortcut vector.        |
  682. ;|                                |
  683. ;[]------------------------------------------------------------[]
  684.  
  685. emuLast    proc    near    ; called only by startup code
  686.     push    DS
  687.  
  688. ; Set DS := DGROUP
  689.     mov    ax, seg _8087@
  690.     mov    DS, ax
  691.  
  692.     ASSUME    CS:_TEXT, DS:DGROUP
  693.  
  694. ; Did we ever get initialized?
  695.     cmp    _8087@, 0
  696.     jl    @@done
  697.  
  698. ; leave the chip in a clean state
  699.     emul
  700.     finit
  701.  
  702.     mov    ax, 2500h + emInt
  703.     mov    bx, offset originalVectors
  704.     mov    cx, 11        ; there are 10 emulation vectors
  705. restoreLoop:
  706.     lds    dx, CS:[bx]
  707.     MSDOS@            ; Set interrupt vector with DS:DX
  708.     add    bx, 4
  709.     inc    ax
  710.     loop    restoreLoop
  711.  
  712. ; restore INT 75h
  713.     mov    ax, 2500h + 75h
  714.     lds    dx, CS:[bx]
  715.     MSDOS@            ; Set interrupt vector with DS:DX
  716.  
  717. ; restore INT 2
  718.     mov    ax, 2500h + 2
  719.     lds    dx, CS:[bx+4]
  720.     MSDOS@            ; Set interrupt vector with DS:DX
  721.  
  722. @@done:
  723.     pop    DS
  724.     ret
  725. emuLast    endp
  726.  
  727. ifdef    VarStack
  728.  
  729. ; clean off all '87 registers, put chip in a predictable state
  730. ; preserves all but bx, cx, flags
  731. ; no segment assumptions other than SS
  732. ; leave current FPU stack pointer in a word at SS:bx
  733. ; void far cdecl fpustate(void);
  734.  
  735. public    __fpustate
  736.  
  737. __fpustate    proc    far
  738.     cmp    SS:__emu.ws_8087, 0
  739.     je    @@ret
  740.     noemul
  741. ; fill the '87
  742.     mov    cx, 8
  743. @@1:    fldz
  744.     loop    @@1
  745.     fcom    st(7)
  746. ; empty the '87
  747.     mov    cl, 8
  748. @@2:    fstp    st(0)
  749.     loop    @@2
  750. ; put the '87 in a predictable state
  751.     mov    cx, SS:__emu.ws_adjust
  752.     and    cx, 111b
  753.     jz    @@4
  754. @@3:    fincstp
  755.     loop    @@3
  756. @@4:
  757.     mov    SS:__emu.ws_adjust, cx        ; cx = 0
  758. @@ret:
  759.     lea    bx, SS:__emu.ws_TOS
  760.     ret
  761. __fpustate    endp
  762.  
  763. endif
  764.  
  765. CSegEnd@
  766.  
  767. ifdef    VarStack
  768.  
  769. _EMUSEG    SEGMENT PARA COMMON 'DATA'
  770.     dw    __fpustate
  771. _EMUSEG    ENDS
  772.  
  773. endif
  774.  
  775.     PAGE
  776. ;[]------------------------------------------------------------[]
  777. ;|                                |
  778. ;|    FPU automatic initialization logic            |
  779. ;|                                |
  780. ;[]------------------------------------------------------------[]
  781.  
  782. PNEAR        EQU    0
  783. PFAR        EQU    1
  784. NOTUSED        EQU    0ffh
  785.  
  786. SE        STRUC
  787. calltype    db    ?            ; 0=near,1=far,ff=not used
  788. priority    db    ?            ; 0=highest,ff=lowest
  789. addrlow        dw    ?
  790. IFNDEF    __TINY__
  791. addrhigh    dw    ?
  792. ENDIF
  793. SE        ENDS
  794.  
  795. _INIT_        SEGMENT WORD PUBLIC 'INITDATA'
  796. ;SE    < PFAR, FpuPriority, offset emu1st, seg emu1st >
  797. SE    < PNEAR, FpuPriority, offset emu1st, 0 >
  798. _INIT_        ENDS
  799.  
  800. _EXIT_        SEGMENT WORD PUBLIC 'EXITDATA'
  801. ;SE    < PFAR, FpuPriority, offset emuLast, seg emuLast >
  802. SE    < PNEAR, FpuPriority, offset emuLast, 0 >
  803. _EXIT_        ENDS
  804.  
  805. END
  806.