home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 9.ddi / EMUSRC.ZIP / E87TRANS.ASM next >
Encoding:
Assembly Source File  |  1992-06-10  |  18.9 KB  |  714 lines

  1. ;
  2. ;       C/C++ Run Time Library - Version 5.0
  3. ;       Copyright (c) 1986, 1992 by Borland International
  4. ;       All Rights Reserved.
  5.  
  6. subttl  e87trans
  7.  
  8. ifdef _WINDOWS
  9.  
  10. f87_Sine    equ <__f87_Sine>
  11. f87_Cosine  equ <__f87_Cosine>
  12. f87_Tangent equ <__f87_Tangent>
  13. f87_ArcTan  equ <__f87_ArcTan>
  14. f87_Log     equ <__f87_Log>
  15. f87_Log2    equ <__f87_Log2>
  16. f87_Log10   equ <__f87_Log10>
  17. f87_Exp     equ <__f87_Exp>
  18. f87_Exp2    equ <__f87_Exp2>
  19. f87_Exp10   equ <__f87_Exp10>
  20.  
  21.  
  22.         PUBLIC  __f87_Sine,  __f87_Cosine,  __f87_Tangent,  __f87_ArcTan
  23.         PUBLIC  __f87_Log,   __f87_Log2 ,  __f87_Log10
  24.         PUBLIC  __f87_Exp,   __f87_Exp2,  __f87_Exp10
  25.  
  26. else
  27.  
  28. E87Seg@
  29.  
  30. endif
  31.  
  32.  
  33. ; special constants are placed here
  34.  
  35. piBy4   dt      3FFEC90FDAA22168C235r
  36. piBy2   dt      3FFFC90FDAA22168C235r
  37.  
  38.     NANtrig             dd      0FFC04200r
  39.     NANlog              dd      0FFC04800r
  40.     NANpower            dd      0FFC04A00r
  41. half            dd      03F000000r
  42.  
  43. sqrt2   dt      3FFFB504F333F9DE6485r
  44.  
  45. infinity        dd      7F800000R               ; plus infinity
  46.  
  47.  
  48.  
  49. ; {
  50. ; General notes:
  51.  
  52. ; - operands are on the iNDP stack
  53. ; - results will be on the iNDP stack
  54. ; - AX,BX,CX,DX may be consumed.  Others must be preserved.
  55. ; - SS, DS, ES belongs to the application program and must be preserved.
  56. ; - all procedures are near and should quit by near return.
  57.  
  58. ASSUME  SS: nothing
  59. ASSUME  DS: nothing
  60. ASSUME  ES: nothing
  61.  
  62. ; - unnormals are not specifically processed because this module is
  63. ;       intended to work with HLL's which place results into IEEE
  64. ;       "double" format, whereas only the IEEE "temporary" format can
  65. ;       handle unnormals.  If you want to run with assembler programs
  66. ;       that may use unnormals then you should check these algorithms
  67. ;       for what happens with un-normal parameters.  De-normals are
  68. ;       processed correctly, since they have been arranged to follow
  69. ;       the same paths as zeroes with only slight extra care needed to
  70. ;       accomodate them.
  71. ; }
  72.  
  73.  
  74.  
  75. f87_Sine:
  76.  
  77.         mov     cl, 0           ; remember we want the Sine
  78.         jmp     short   trig
  79.  
  80.  
  81. f87_Cosine:
  82.  
  83.         mov     cl, 2           ; remember we want the Cosine
  84.         jmp     short   trig
  85.  
  86.  
  87.  
  88. f87_Tangent   PROC
  89.  
  90.         mov     cl, 4           ; remember we want the Tangent
  91.  
  92.  
  93. ; the following code is shared by Sine, Cosine, and Tangent
  94.  
  95. trig:
  96.  
  97. ; trig_sign     CH
  98. ; trig_fun      CL
  99. ; trig_octant   AL
  100. trig_status     equ     [bp-2].w0
  101.  
  102.         fxam                            ; '87 works while we enter routine
  103.  
  104.         push    bp
  105.         mov     bp, sp
  106.         lea     sp, trig_status
  107.  
  108.         fstsw   trig_status
  109.         wait
  110.         mov     ah, trig_status.by1
  111.         sahf                            ; FL now reflects FXAM status
  112.         jc      trig_badParam
  113.         jnz     trig_normal
  114.  
  115. trig_tiny:                              ; denormal or zero
  116.         cmp     cl, 2                   ; are we trying for cosine ?
  117.         jne     trig_noChange           ;   Sin or Tan (tiny) = tiny
  118.         fstp    ST(0)                   ; pop stack
  119.         fld1                            ; Cos (tiny) = 1.0
  120. trig_noChange:
  121.         jmp     short   trig_endJmp
  122.  
  123. trig_badParam:                          ; NAN, infinite, or Empty
  124.         jz      trig_empty              ; st(0) was empty
  125.         jnp     trig_NAN                ; st(0) was NAN
  126.         fstp    st(0)                   ; pop st(0)
  127.         fld     NANtrig                 ; st(0) was infinite, now NAN
  128.         ftst                            ; trigger exception
  129. trig_NAN:
  130. trig_empty:
  131.         jmp     short   trig_endJmp
  132.  
  133.  
  134. ; For numbers of size 2^62 or larger in magnitude, the error of just
  135. ;       one lsb in the parameter is equivalent to at least 0.25 radian,
  136. ;       and so it is spurious to compute exact results.
  137.  
  138. ; Note that parameters between 2^62 and 2^64 could be exact integers, for
  139. ;       which the result may be valid.  However, as we are designing
  140. ;       this module to support an HLL which will be using IEEE Long for
  141. ;       ordinary storage of variables, only numbers up to 2^53 could be
  142. ;       exactly represented (and indeed the limit of 2^62 on parameter is
  143. ;       far beyond accurate range).
  144.  
  145. ; This reasoning is also convenient, since the 8087 REM instruction
  146. ;       does not process numbers differing by more than 64 bits magnitude.
  147.  
  148. trig_tooBig:
  149.         fcompp          ; convenient double pop
  150.         fld     NANtrig
  151.         ftst                            ; trigger exception
  152. trig_endJmp:
  153.         jmp     trig_end
  154.  
  155.  
  156.  
  157. trig_normal:                            ; or un-normal
  158.         fabs
  159.         fld     piBy4
  160. ifdef _WINDOWS
  161.         fxam            ; From Intel 287 doc, if quotient is less than 2 then
  162.                         ; C3 equals the value C1 had before the FPREM.
  163.                         ; The FXAM clears C1 since PI/4 is positive.
  164.                         ; NOTE: This behavior does not happen on my 287, but
  165.                         ; it does in the Windows emulator
  166. endif
  167.         fxch
  168.         fprem
  169.  
  170. ; while the '87 crunches that, we check the sign the parameter had
  171.  
  172.         mov     ch, 2
  173.         and     ch, ah                  ; what was the sign ?
  174.         shr     ch, 1                   ; CH = sign
  175.  
  176.         fstsw   trig_status
  177.         wait
  178.         mov     ah, trig_status.by1
  179.         sahf
  180.         jp      trig_tooBig
  181.  
  182.  
  183. ; apologies for the following mindbending paragraph.  It takes fewer
  184. ;       bytes than a table look-up.
  185.  
  186.         mov     al, 3
  187.         and     al, ah          ; select the C3, C1, and C0 status bits
  188.         shl     ah, 1
  189.         shl     ah, 1
  190.         rcl     al, 1           ; arrange them in the ls 3 bits of BX
  191.         add     al, 0FCh
  192.         rcl     al, 1           ; al now contains the octant number
  193.  
  194.         cmp     cl, 2                   ; are we doing Cosine ?
  195.         jne     trig_notCosine
  196.  
  197.         add     al, cl                  ; Cos (x) = Sin (x + 2 octants)
  198.         mov     ch, 0                   ; Cosine has even symmetry around 0
  199. trig_notCosine:
  200.         and     al, 7
  201.  
  202.  
  203. ; the octants 1,3,5,7 need (pi/4 - x) as their operand
  204.  
  205.         test    al, 1
  206.         jz      trig_evens
  207.  
  208.         fsub                            ; overwrites pi/4 in st(1), pops.
  209.         jmp     short   trig_ptan
  210.  
  211. ; the octants 0,2,4,6 must check against zero operand and remove pi/4
  212. ;       from st(1)
  213.  
  214. trig_evens:
  215.         fstp    st(1)                   ; st(0) overwrites st(1), pops
  216.  
  217. trig_ptan:
  218.         fptan           ; returns ST(1)/ST(0) = Tan
  219.  
  220. ; while the '87 crunches that, lets decide what to do with the result
  221.  
  222.         cmp     cl, 4                   ; was it Tangent ?
  223.         je      trig_tangent
  224.  
  225. ; sine or cosine, are similar, varying only in phase of the octant, which
  226. ;       we have already adjusted so that the calculation is now only for
  227. ;       Sine.
  228.  
  229. ;   octant      sine
  230. ;       0       sin (x)
  231. ;       1       cos (pi/4 - x)
  232. ;       2       cos (x)
  233. ;       3       sin (pi/4 - x)
  234. ;       4       - sin (x)
  235. ;       5       - cos (pi/4 - x)
  236. ;       6       - cos (x)
  237. ;       7       - sin (pi/4 - x)
  238.  
  239.         test    al, 3
  240.         jpe     trig_sineOctant         ; even-parity is Sine forms
  241.  
  242. ; Sin (s) = ST(1) / Sqrt (ST(0)^2 + ST(1)^2)
  243. ; Cos (x) = ST(0) / Sqrt (ST(0)^2 + ST(1)^2)
  244.  
  245. trig_cosOctant:
  246.         fxch
  247.  
  248. trig_sineOctant:
  249.         fld     st(1)           ; make a copy of ST(1)
  250.  
  251.         fmul    st, st(0)
  252.         fxch
  253.         fmul    st, st(0)
  254.         fadd
  255.         fsqrt
  256.  
  257. ; while sqrt is crunching, what sign do we give the final result ?
  258.  
  259.         shr     al, 1
  260.         shr     al, 1
  261.         xor     al, ch
  262.         jz      trig_sineDiv
  263.  
  264.         fchs                    ; cause result to be negative
  265.  
  266. trig_sineDiv:
  267.         fdiv
  268.         jmp     short   trig_end  ; complete calculation in the caller's time
  269.  
  270.  
  271.  
  272. trig_tangent:
  273.  
  274. ; Tangent is a repeating pattern over 4 octants:
  275.  
  276. ;   octant      tangent
  277. ;       0       sin (x) / cos (x)
  278. ;       1       cos (pi/4-x) / sin (pi/4 - x)
  279. ;       2       -cos (x) / sin (x)
  280. ;       3       -sin (pi/4 - x) / cos (pi/4 - x)
  281.  
  282. ; When we arrive here AL = octant and ST(0) = x OR pi/4-x, already
  283. ;       adjusted for the octant.
  284.  
  285. ; The PTAN instruction is already initiated, so we now decide what
  286. ;       to do with the result.
  287.  
  288.         mov     ah, al
  289.         shr     ah, 1
  290.         and     ah, 1                   ; octants 2, 3 are negatives
  291.         xor     ah, ch                  ; combine with parameter's sign
  292.         jz      trig_tanSigned
  293.  
  294.         fchs
  295.  
  296. trig_tanSigned:
  297.         test    al, 3
  298.         jpe     trig_ratio      ; octants 0, 3 have even parity
  299.  
  300. ; in a freak case, like arg = pi/2 exactly, might get divide by 0
  301. ; return tan(pi/2) = +INF, although arguably it should generate an exception
  302.         fxch
  303.         ftst
  304.         fstsw   trig_status
  305.         fwait
  306.         test    trig_status.by1, 40h    ; C3 flag
  307.         jz      trig_ratio
  308.         fcompp                          ; pop st(0) and st(1)
  309.         fld     infinity
  310.         jmp     short   trig_end  ; complete calculation in the caller's time
  311.  
  312. trig_ratio:
  313.         fdiv
  314. trig_end:
  315.         mov     sp, bp
  316.         pop     bp
  317.         ret                     ; '87 calculates while we return
  318.  
  319. f87_Tangent   ENDP
  320.  
  321.  
  322.  
  323. ; There are two symmetries used here:
  324.  
  325. ; a)    ATan (1/x) = Pi/2 - ATan (x)
  326. ; b)     ATan (-x) = - ATan (x)
  327.  
  328. ; Special cases are:
  329.  
  330. ;  0 = ArcTan (0)
  331. ;  Pi/2 = ArcTan (infinity)
  332.  
  333.  
  334. f87_ArcTan    PROC
  335.  
  336. atan_status     equ     [bp-2].w0
  337.  
  338.         fxam                            ; keep '87 busy in parallel
  339.  
  340.         push    bp
  341.         mov     bp, sp
  342.         lea     sp, atan_status
  343.  
  344.         fstsw   atan_status
  345.         wait
  346.         mov     ah, atan_status.by1
  347.         sahf                            ; FL now reflects FXAM status
  348.         xchg    cx, ax                  ; save for later negation check
  349.         jc      atan_badParam
  350.         jnz     atan_normal
  351.  
  352. atan_tiny:                              ; denormal or zero
  353.         jmp     short   atan_end        ; Atan (tiny) = tiny
  354.  
  355.  
  356. atan_badParam:                          ; NAN, infinite, or Empty
  357.         jz      atan_empty              ; st(0) was empty
  358.         jnp     atan_NAN                ; st(0) was NAN
  359.         fstp    st(0)                   ; st(0) was infinite, pop it
  360.         fld     piBy2                   ;   Atan (infinity) = pi/2
  361.         jmp     short   atan_setSign
  362.  
  363.  
  364. atan_of1:
  365.         fcompp                          ; pop stack twice
  366.         fld     piBy4
  367.         jmp     short   atan_setSign
  368.  
  369.  
  370. atan_normal:
  371.         fabs
  372.         fld1
  373.         fcom
  374.         fstsw   atan_status
  375.         wait
  376.         mov     ah, atan_status.by1
  377.         sahf                            ; FL now reflects FCOM status
  378.  
  379.         je      atan_of1                ; st(1)=st(0)=1 is a special case
  380.         jnc     atan_ordered
  381.  
  382.         fxch                            ; st(1) > st(0) requires inversion
  383.  
  384. atan_ordered:
  385.         fpatan
  386.         jnc     atan_setSign            ; flags still indicate FCOM status
  387.  
  388.         fld     piBy2
  389.         fsub
  390.         xor     ch, 02                  ; invert sign flag
  391.  
  392. atan_setSign:
  393.         test    ch, 02                  ; what was parameters true sign ?
  394.         jz      atan_end
  395.  
  396.         fchs                            ; parameter was negative
  397.  
  398. atan_NAN:
  399. atan_empty:
  400. atan_end:
  401.         mov     sp, bp
  402.         pop     bp
  403.         ret
  404.  
  405. f87_ArcTan    ENDP
  406.  
  407.  
  408.  
  409. ; Log2 (X) = Log2 (X)
  410.  
  411. f87_Log2:
  412.         fld1
  413.         jmp     short   DoLogs
  414.  
  415.  
  416. ; Log10 (X) = Log10 (2) * Log2 (X)
  417.  
  418. f87_Log10:
  419.         fldlg2
  420.         jmp     short   DoLogs
  421.  
  422.  
  423. ; Log (X) = Log (2) * Log2 (X)
  424.  
  425. f87_Log:
  426.         fldln2
  427. ;       jmp     short   DoLogs
  428. ;       fall thru to DoLogs
  429.  
  430.  
  431.  
  432.  
  433. DoLogs  PROC
  434.  
  435. log_temp                equ     [bp-10]
  436. log_status      equ     [bp-10].w0
  437.  
  438.         fxch                            ; keep '87 busy in parallel
  439.  
  440.         push    bp
  441.         mov     bp, sp
  442.  
  443.         fxam
  444.  
  445.         lea     sp, log_status
  446.  
  447.         fstsw   log_status
  448.         wait
  449.         mov     ah, log_status.by1
  450.         sahf                            ; FL now reflects FXAM status
  451.         jc      log_badParam
  452.         jz      log_tiny
  453.         test    ah, 2                   ; was parameter negative ?
  454.         jz      log_normal
  455.  
  456. log_negative:
  457. log_tiny:                               ; denormal or zero
  458. log_tooBig:
  459.         fstp    st(0)                   ; pop st(0)
  460.         jmp     short   log_indefinite
  461.  
  462. log_badParam:                           ; NAN, infinite, or Empty
  463.         jz      log_empty               ; st(0) was empty
  464.         fstp    st(1)                   ; pop st(1)
  465.         jnp     log_NAN                 ; st(0) was NAN
  466.  
  467. ;infinite arg
  468.         fstp    st(1)                   ; pop st(1)
  469.         test    ah, 2                   ; was parameter negative ?
  470.         jz      log_end
  471.  
  472. log_indefinite:
  473.         fstp    st(0)                   ; pop st(0)
  474.         fld     NANlog                  ; st(0) was infinite, now NAN
  475.  
  476. log_NAN:
  477. log_empty:
  478.         ftst                            ; trigger exception
  479.         jmp     short   log_end
  480.  
  481.  
  482. log_normal:
  483.  
  484. ; the first million 8087s and 80287s had a bug
  485. ; fyl2x failed if x = smallest 10-byte real > 1
  486. ; FYL2X(1,x) gave you garbage *only* if x = 1+2**-63:
  487.  
  488. ;If you looked at Intel's CEL library code, you would see some code that
  489. ;checks if difference between x and 1 is < 2^-16, and if so does a ylogxp1
  490. ;instead.  This was explicitly commented there as a work around for an old
  491. ;chip bug.  The problem comes in the argument reduction not normalizing the
  492. ;mantissa after subtracting 1 from it, prior to doing the Cordic reduction.
  493.  
  494. ; If anyone decides this case is too obscure to bother with,
  495. ; or that everyone has bug-free chips,
  496. ; then just delete the code from here to log_normal1.
  497.  
  498. ; test whether number is near +1 by examining bits directly
  499.         fld     st(0)           ; duplicate TOS
  500. ;       lea     sp, log_temp    ; space already allocated
  501.         fstp    tbyte ptr log_temp;
  502.         fwait
  503.  
  504. ; +1 is stored as 0000 0000 0000 8000 3FFF
  505.         cmp     word ptr log_temp[8], 3FFFh
  506.         jne     log_normal1
  507.         cmp     word ptr log_temp[6], 8000h
  508.         jne     log_normal1
  509.  
  510. ; arg now in range [1,1+2^-16].
  511.         fld1
  512.         fsub
  513.         fyl2xp1
  514.         jmp     short log_end
  515.  
  516. log_normal1:
  517.         fyl2x
  518.  
  519. log_end:
  520.         mov     sp, bp
  521.         pop     bp
  522.         ret
  523.  
  524.  
  525. DoLogs  ENDP
  526.  
  527.  
  528.  
  529. ; Exp2 (X) = 2^(X)
  530.  
  531. f87_Exp2:
  532.         sub     cx, cx                  ; scale not needed
  533.         jmp     short   DoExps
  534.  
  535.  
  536. ; Exp10 (X) = 2^(X * Log2of10)
  537.  
  538. f87_Exp10:
  539.         fldl2t
  540.         mov     cl, 1                   ; scaling is needed
  541.         fxch
  542.         jmp     short   DoExps
  543.  
  544. ; Exp (X) = 2^(X * Log2ofE)
  545.  
  546. f87_Exp:
  547.         fldl2e
  548.         mov     cl, 1                   ; scaling is needed
  549.         fxch
  550. ;       jmp     short   DoExps
  551. ; fall thru
  552.  
  553.  
  554.  
  555. ; Use the following method:
  556.  
  557. ; The basic limitation of X2M1 is that it accepts parameters only in the
  558. ; range 0 <= X <= 0.5.  Thus we must reduce the parameter to that range.
  559. ; Another limitation is that we shall consider any parameter of more than
  560. ; 2047 to generate an infinite result, since the result is too large to
  561. ; express in the long IEEE format.
  562.  
  563. ; (Q, R) := Rem (X, 0.5);
  564.  
  565. ; { X = Q/2 + R exactly, and 0 <= R < 0.5 }
  566.  
  567. ; 2^X   = 2^(Q/2 + R)
  568. ;       = 2^(Q/2) * 2^R
  569. ;       = 2^(Q DIV 2) * (Sqrt(2))^(Q MOD 2) * 2^R
  570.  
  571. ; Each of those three terms is easily calculated.
  572. ; The first term is a fraction of 0.5 with exponent (Q DIV 2) + 1.
  573. ; The second term is a choice of constants 1.0 or Sqrt(2).
  574. ; The third is  1 + 2XM1 (R).
  575.  
  576. DoExps  PROC
  577.  
  578. exp_term1       equ     [bp-2].w0
  579. exp_status      equ     [bp-4].w0
  580.  
  581. ;       jcxz    exp_swapped
  582. ;       fxch
  583. ;exp_swapped:
  584.         fxam
  585.  
  586.         push    bp
  587.         mov     bp, sp
  588.         lea     sp, exp_status
  589.  
  590.         fstsw   exp_status
  591.         jcxz    exp_deppaws
  592.         fxch
  593. exp_deppaws:
  594.         wait
  595.         mov     ah, exp_status.by1
  596.         sahf                            ; FL now reflects FXAM status
  597.         jc      exp_badParam
  598.         jnz     exp_normal
  599.  
  600. exp_tiny:                               ; denormal or zero
  601.         fstp    st(0)                   ; pop TOS
  602.         jcxz    exp_result1             ; was there a scale factor also ?
  603.         fstp    st(0)
  604. exp_result1:
  605.         fld1
  606.         jmp     exp_end
  607.  
  608. exp_badParam:                           ; NAN, infinite, or Empty
  609.         jcxz    exp_badNowTos           ; was there a scale factor also ?
  610.         fstp    st(0)                   ; pop TOS
  611. exp_badNowTos:
  612.         jz      exp_empty               ; st(0) was empty
  613.         jnp     exp_NAN                 ; st(0) was NAN
  614.  
  615. exp_tooBig:
  616.         fstp    st(0)                   ; pop st(0)
  617.         fld     infinity
  618.         jmp     exp_setSign
  619.  
  620. exp_NAN:
  621. exp_empty:
  622.         ftst                            ; trigger exception
  623.         jmp     exp_end
  624.  
  625. exp_normal:
  626.         jcxz    exp_scaled
  627.         fmul
  628.  
  629. exp_scaled:
  630.         fabs
  631.         fcom    half
  632.         fstsw   exp_status
  633.         wait
  634.         test    exp_status.by1, 41h
  635.         jz      exp_notSimpleRange
  636.  
  637. ; We can run |st(0)| <= 0.5 as a special case because it is quick and easy.
  638.  
  639.         f2xm1
  640.         fld1
  641.         fadd
  642.         jmp     short   exp_setSign
  643.  
  644. ; to get a rapid division by 0.5 we double and truncate.
  645.  
  646. exp_notSimpleRange:
  647.         fld1
  648.         fld     st(1)
  649.         fstcw   exp_status
  650.         fscale
  651.         or      exp_status.by1, 0Fh     ; specify truncation mode
  652.         fldcw   exp_status
  653.         frndint
  654.         and     exp_status.by1, 0F3h    ; default back to round-nearest
  655.         fldcw   exp_status
  656.         fist    exp_term1
  657.  
  658. ; then to obtain the remainder we scale back to normal and
  659. ;       subtract from the original.
  660.  
  661.         fxch
  662.         fchs
  663.         fxch
  664.         fscale
  665.         fstp    st(1)           ; fscale did not adjust stack
  666.         fsub                    ; st(0) is now 0 <= R < 0.5
  667.  
  668. ; is this test useful?
  669. ;       cmp     exp_term1, 4095
  670. ;       jg      exp_tooBig
  671.  
  672. ; now we are into the final section.  First calculate the
  673. ;       exponent of TOS, the remainder.
  674.  
  675.         f2xm1
  676.         fld1
  677.         fadd                    ; calculated third term, 2^R
  678.  
  679.         shr     exp_term1, 1
  680.         jnc     exp_noHalf
  681.  
  682.         fld     sqrt2           ; multiply by second term
  683.         fmul
  684.  
  685. exp_noHalf:
  686.         fild    exp_term1
  687.         fxch
  688.         fscale                  ; multiply by first term, 2^(Q DIV 2)
  689.         fstp    st(1)           ; (fscale doesn't adjust stack)
  690.  
  691.  
  692. exp_setSign:
  693.         test    ah, 02          ; was original parameter negative ?
  694.         jz      exp_end         ; jump if it was positive
  695.  
  696.         fld1
  697.         fdivr
  698.  
  699. exp_end:
  700.         mov     sp, bp
  701.         pop     bp
  702.         ret
  703.  
  704.  
  705. DoExps  ENDP
  706.  
  707. ifndef _WINDOWS
  708.  
  709. E87SegEnd@
  710.  
  711. endif
  712.