home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CASM.ARJ / FLOAT.ASM < prev    next >
Assembly Source File  |  1988-09-05  |  29KB  |  1,488 lines

  1. ;_ float.asm   Sat Mar 26 1988   Modified by: Walter Bright */
  2. ; $Header$
  3. ;Copyright (C) 1984-1988 by Northwest Software
  4. ;All Rights Reserved, written by Walter Bright
  5. ;Floating point package
  6.  
  7. include macros.asm
  8.  
  9.     .8087
  10.  
  11. sgn        equ    08000h        ;mask for sign bit
  12.  
  13. shortexp    equ    07F80h        ;mask for short exponent
  14. shorthid    equ    00080h        ;mask for hidden bit
  15. shortbias    equ    07Fh        ;exponent bias
  16.  
  17. longexp        equ    07FF0h        ;mask for long exponent
  18. longhid        equ    00010h        ;mask for hidden bit
  19. longbias    equ    03FFh        ;exponent bias
  20.  
  21.     if LCODE
  22.     c_extrn    CXFERR,far
  23.     else
  24.     c_extrn    CXFERR,near
  25.     endif
  26.  
  27.     begdata
  28.     c_extrn    _8087,word        ;8087 flag word
  29.  
  30.     c_public    DBL_MAX,DBL_MIN,FLT_MAX,FLT_MIN
  31.  
  32. _DBL_MAX    dw    0,0,0,longexp    ;maximum double value
  33. _DBL_MIN    dw    0,0,0,longhid    ;minimum
  34. _FLT_MAX    dw    0,shortexp    ;maximum float value
  35. _FLT_MIN    dw    0,shorthid
  36.  
  37. roundto0    dw    0FBFh        ;8087 control word to round to 0
  38.     enddata
  39.  
  40.     begcode    float
  41.  
  42.     ;Note:    0=int    2=unsigned    3=long    4=float    5=double
  43.  
  44.     c_public    _DADD@,_DSUB@,_DMUL@,_DDIV@,_DNEG@,_DTST@,_DCMP@
  45.     c_public    _DBLINT@,_INTDBL@,_DBLUNS@,_UNSDBL@,_DBLFLT@,_FLTDBL@
  46.     c_public    _DBLLNG@,_LNGDBL@,_DBLULNG@,_ULNGDBL@
  47.     c_public    _DTST87@,_87TOPSW@,_DBLTO87@,_FLTTO87@,_DBLINT87@
  48.     c_public    _DBLLNG87@
  49.     c_public    _INTFLT@,_UNSFLT@,_LNGFLT@,_FLTINT@,_FLTUNS,_FLTLNG@
  50.  
  51. regstk    macro
  52.     mov    [BP],DX
  53.     mov    2[BP],CX
  54.     mov    4[BP],BX
  55.     mov    6[BP],AX
  56.     endm
  57.  
  58. stkreg    macro
  59.     mov    DX,[BP]
  60.     mov    CX,2[BP]
  61.     mov    BX,4[BP]
  62.     mov    AX,6[BP]
  63.     endm
  64.  
  65. xchgstkreg    macro
  66.     xchg    DX,[BP]
  67.     xchg    CX,2[BP]
  68.     xchg    BX,4[BP]
  69.     xchg    AX,6[BP]
  70.     endm
  71.  
  72. neg64    macro
  73. ;    clr    SI        ;just so happens this is true when
  74.                 ;we invoke the macro
  75.     not    CX
  76.     not    BX
  77.     not    AX
  78.     neg    DX
  79.     cmc
  80.     adc    CX,SI
  81.     adc    BX,SI
  82.     adc    AX,SI
  83.     endm
  84.  
  85. shl64    macro    r1,r2,r3,r4
  86.     shl    r4,1
  87.     rcl    r3,1
  88.     rcl    r2,1
  89.     rcl    r1,1
  90.     endm
  91.  
  92. shr64    macro    r1,r2,r3,r4
  93.     shr    r1,1
  94.     rcr    r2,1
  95.     rcr    r3,1
  96.     rcr    r4,1
  97.     endm
  98.  
  99. shlby8    macro
  100.     mov    AH,AL
  101.     mov    AL,BH
  102.     mov    BH,BL
  103.     mov    BL,CH
  104.     mov    CH,CL
  105.     mov    CL,DH
  106.     mov    DH,DL
  107.     xor    DL,DL
  108.     endm
  109.  
  110. shrby8    macro
  111.     mov    DL,DH
  112.     mov    DH,CL
  113.     mov    CL,CH
  114.     mov    CH,BL
  115.     mov    BL,BH
  116.     mov    BH,AL
  117.     mov    AL,AH
  118.     xor    AH,AH
  119.     endm
  120.  
  121. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  122. ; Short real:
  123. ;    s | exponent| significand|
  124. ;    31|30     23|22        0|
  125. ; Long real:
  126. ;    s | exponent| significand|
  127. ;    63|62     52|51        0|
  128.  
  129. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  130. ; Unpack a float. The float must not be 0.
  131. ; Input:
  132. ;    [DX,AX] = the float (with sign = 0)
  133. ; Output:
  134. ;    [DX,AX] = significand (with hidden bit in DX bit 15)
  135. ;    SI    exponent
  136. ;    DI    sign (in bit 15)
  137.  
  138. $funnorm proc    near
  139.     mov    DI,DX        ;save sign
  140.     shl    DX,1
  141.     xchg    DH,DL
  142.     clr    DH
  143.     mov    SI,DX        ;SI = exponent (AX >> 7)
  144.     mov    DX,DI
  145.     or    DL,shorthid    ;or in hidden bit
  146.  
  147.     mov    DH,DL
  148.     mov    DL,AH
  149.     mov    AH,AL
  150.     clr    AL
  151.  
  152.     ret
  153. $funnorm endp
  154.  
  155. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  156. ; Normalize and pack a float.
  157. ; Input:
  158. ;    [DX,AX] = significand
  159. ;    SI = exponent (biased)
  160. ;    DI bit 15 = sign of result
  161. ;
  162.  
  163. $fnorm    proc    near
  164.     sub    SI,8        ;offset
  165. L11:    tst    DH        ;do we need to shift right?
  166.     jz    L12        ;no
  167. L35:    shr    DX,1
  168.     rcr    AX,1
  169.     inc    SI        ;exponent
  170.     jnc    L11        ;no rounding
  171.     tst    DH        ;done shifting?
  172.     jnz    L35        ;no
  173.     inc    AX        ;round up by 1
  174.     jnz    L12        ;no carry (also, we're done shifting)
  175.     inc    DX
  176.     jmp    L11
  177.  
  178. ;see if our significand is 0
  179. L12:    tst    DX
  180.     jnz    L13
  181.     tst    AX
  182.     jnz    L13
  183.     mov    DX,shorthid
  184.     clr    SI        ;trick L13 into giving us a 0 result
  185.  
  186. L13:    test    DL,shorthid    ;hidden bit in right spot?
  187.     jnz    L14        ;yes
  188.     shl    AX,1
  189.     rcl    DX,1        ;shift left till it is
  190.     dec    SI
  191.     jmp    L13
  192.  
  193. L14:    test    SI,0FF00h    ;see if underflow or overflow
  194.     jz    L16        ;no
  195.     mov    DX,1        ;assume underflow
  196.     js    L17        ;right
  197.     inc    DX        ;overflow
  198. L17:    push    DX
  199.     callm    CXFERR
  200.     pop    DX
  201.     clr    AX
  202.     dec    DX
  203.     jz    L19        ;0 is result for underflow
  204.     mov    DX,shortexp
  205.     jmps    L18        ;infinity is result for overflow (with sign)
  206.  
  207. L16:    push    CX
  208.     mov    CX,7
  209.     shl    SI,CL        ;shift exponent into position
  210.     pop    CX
  211.     and    DL,shorthid - 1    ;dump hidden bit
  212. ;    and    SI,shortexp    ;dump extraneous bits (not necessary)
  213.     or    DX,SI        ;install exponent
  214. L18:    and    DI,sgn        ;mask sign bit
  215.     or    DX,DI        ;install sign
  216. L19:    ret
  217. $fnorm    endp
  218.  
  219. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  220. ; Unpack a double. The double must not be 0.
  221. ; Input:
  222. ;    [AX,BX,CX,DX] = the double (with sign = 0)
  223. ; Output:
  224. ;    [AX,BX,CX,DX] = significand (with hidden bit in AX bit 15)
  225. ;    SI    exponent
  226. ;    DI    sign (in bit 15)
  227.  
  228. dunnorm proc    near
  229.     mov    DI,AX        ;save sign
  230.     mov    SI,AX
  231.     and    SI,longexp    ;mask off exponent bits
  232.     shr    SI,1
  233.     shr    SI,1
  234.     shr    SI,1
  235.     shr    SI,1        ;right justify exponent
  236.     or    AL,longhid    ;or in hidden bit
  237.  
  238.     ; AX,BX,CX,DX <<= 11
  239.     shlby8
  240.     shl64    AX,BX,CX,DX
  241.     shl64    AX,BX,CX,DX
  242.     shl64    AX,BX,CX,DX
  243.     ret
  244. dunnorm endp
  245.  
  246. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  247. ; Normalize and pack a double.
  248. ; Input:
  249. ;    [AX,BX,CX,DX] = significand
  250. ;    SI = exponent (biased)
  251. ;    DI bit 15 = sign of result
  252. ;
  253.  
  254. dnorm    proc    near
  255.     sub    SI,11        ;offset
  256.     test    AH,0C0h        ;can we shift right 8 bits?
  257.     jz    dnorm2        ;no
  258.     shrby8
  259.     add    SI,8
  260. dnorm2:    test    AX,0FFE0h    ;do we need to shift right?
  261.     jz    L5        ;no
  262. L34:    shr64    AX,BX,CX,DX
  263.     inc    SI        ;exponent
  264.     jnc    dnorm2        ;don't worry about rounding
  265.     test    AX,0FFE0h    ;done shifting yet?
  266.     jnz    L34        ;no, don't round yet
  267.  
  268.     ;Round up by 1
  269.     add    DX,1
  270.     adc    CX,0
  271.     adc    BX,0
  272.     adc    AL,AH        ;note that AH is 0
  273.     jmp    dnorm2
  274.  
  275. ;see if our significand is 0
  276. L5:    tst    AL
  277.     jnz    L3
  278.     tst    BX
  279.     jnz    DN1
  280.     xchg    BX,DX
  281.     xchg    BX,CX        ;BX,CX,DX <<= 16
  282.     sub    SI,16        ;shift left by 16
  283.     tst    BX
  284.     jnz    DN1
  285.     xchg    BX,CX        ;BX,CX <<= 16
  286.     sub    SI,16
  287.     tst    BX
  288.     jz    L9        ;result is 0
  289.     tst    BH
  290.     jnz    DN1
  291.     xchg    BH,BL        ;BX <<= 8
  292.     sub    SI,8
  293.  
  294. L3:    test    AL,longhid    ;hidden bit in right spot?
  295.     jnz    L4        ;yes
  296. DN1:    shl64    AL,BX,CX,DX    ;shift left till it is
  297.     dec    SI
  298.     jmp    L3
  299.  
  300. L4:    test    SI,0F800h    ;see if underflow or overflow
  301.     jnz    L6        ;yes
  302.     shl    SI,1
  303.     shl    SI,1
  304.     shl    SI,1
  305.     shl    SI,1
  306.     and    AL,longhid - 1    ;dump hidden bit
  307. ;    and    SI,longexp    ;dump extraneous bits (not necessary)
  308.     or    AX,SI        ;install exponent
  309. L8:    and    DI,sgn        ;mask sign bit
  310.     or    AX,DI        ;install sign
  311. L9:    ret
  312.  
  313. L6:    mov    AL,1        ;assume underflow
  314.     js    L7        ;right
  315.     inc    AX        ;overflow
  316. L7:    push    DI        ;save sign
  317.     push    AX
  318.     callm    CXFERR
  319.     pop    AX
  320.     pop    DI
  321.     clr    BX
  322.     mov    CX,BX
  323.     mov    DX,BX
  324.     dec    AX
  325.     jz    L9        ;0 is result for underflow
  326.     mov    AX,longexp
  327.     jmps    L8        ;infinity is result for overflow (with sign)
  328. dnorm    endp
  329.  
  330. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  331. ; Test and see if [] is 0
  332. ;
  333.  
  334. func    _DTST@
  335.     push    AX
  336.     shl    AX,1        ;dump sign bit
  337.     or     AX,DX
  338.     or     AX,CX
  339.     or     AX,BX
  340.     pop    AX
  341.     ret
  342. c_endp    _DTST@
  343.  
  344. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  345. ; Double floating subtract.
  346. ;    a = b - c
  347. ; Input:
  348. ;    b is on stack
  349. ;    [AX,BX,CX,DX] = b
  350. ; Output:
  351. ;    a = [AX,BX,CX,DX]
  352. ;    SI,DI = preserved
  353.  
  354. func    _DSUB@
  355.     push    BP
  356.     sub    SP,nn        ;make room for nn variables
  357.     mov    BP,SP
  358.  
  359.     .if    _8087 e 0, S1        ;if no 8087
  360.     fld    qword ptr nn+P[BP]    ;load b
  361.     .push    <AX,BX,CX,DX>        ;push c
  362.     fsub    qword ptr -8[BP]    ;sub c
  363.  
  364. fltret:
  365.     ;Check for floating point error
  366.     fstsw    -2[BP]
  367.     fwait
  368.     test    byte ptr -2[BP],1Ch
  369.     jz    fltret4
  370.     mov    AX,1
  371.     test    byte ptr -2[BP],10h    ;underflow?
  372.     jnz    callferr        ;yes
  373.     inc    AX
  374.     test    byte ptr -2[BP],8    ;overflow?
  375.     jnz    callferr        ;yes
  376.     inc    AX            ;else divide by 0
  377.  
  378. callferr:
  379.     push    AX
  380.     callm    CXFERR
  381.     pop    AX
  382. fltret4:
  383.     fstp    qword ptr -8[BP]
  384.     fwait            ;wait for it to finish
  385.     .pop    <DX,CX,BX,AX>    ;pop result
  386.     add    SP,nn
  387.     pop    BP
  388.     ret    8
  389.  
  390. S1:    stc            ;indicate subtraction
  391.     jmps    L22
  392. c_endp    _DSUB@
  393.  
  394. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  395. ; Double floating add.
  396. ;    a = b + c
  397. ; Input:
  398. ;    b is on stack
  399. ;    [AX,BX,CX,DX] = c
  400. ; Output:
  401. ;    a = [AX,BX,CX,DX]
  402. ;    SI,DI = preserved
  403.  
  404. ; Stack offsets
  405.  
  406.     padnn    =    22    ;so nn == dd == mm == 38
  407.     signb    =    padnn+8
  408.     signc    =    signb+2
  409.     exp    =    signc+2
  410.     minus    =    exp+2
  411.     nn    =    minus+2
  412.  
  413. func    _DADD@
  414.     push    BP
  415.     sub    SP,nn        ;make room for nn variables
  416.     mov    BP,SP
  417.     .if    _8087 e 0, A1        ;if no 8087
  418.     fld    qword ptr nn+P[BP]    ;load b
  419.     .push    <AX,BX,CX,DX>        ;push c
  420.     fadd    qword ptr -8[BP]    ;add c
  421.     jmp    fltret
  422.  
  423. L23:    ;Result is b
  424.     mov    AX,nn+P+6[BP]
  425.     mov    BX,nn+P+4[BP]
  426.     mov    CX,nn+P+2[BP]
  427.     mov    DX,nn+P[BP]
  428.     jmp    L24
  429.  
  430. L30:    ;we have the case 0 +- c
  431.     and    DI,8000h    ;isolate sign bit
  432.     xor    AX,DI        ;toggle sign if it was a minus
  433.     jmp    L24
  434.  
  435. A1:    ;clc            ;indicate addition (C is already 0)
  436.  
  437. L22:    push    DI
  438.     rcr    DI,1        ;bit 15 is sign
  439.  
  440.     push    AX
  441.     shl    AX,1        ;dump sign bit
  442.     or     AX,DX
  443.     or     AX,CX
  444.     or     AX,BX
  445.     pop    AX        ;see if second operand is 0
  446.     jz    L23        ;yes, result is first operand
  447.  
  448.     push    AX
  449.     mov    AX,nn+P+6[BP]
  450.     mov    signb+1[BP],AH    ;save sign of b
  451.     shl    AX,1        ;dump sign bit
  452.     or    AX,nn+P+4[BP]
  453.     or    AX,nn+P+2[BP]
  454.     or    AX,nn+P[BP]
  455.     pop    AX
  456.     jz    L30        ;yes, result is second operand
  457.  
  458.     push    SI
  459.  
  460.     xor    DI,AX        ;produce sign of second operand
  461.     mov    signc[BP],DI    ;save sign of c
  462.     xor    DI,signb[BP]    ;if sign(b) != sign(c), then subtraction
  463.     mov    minus[BP],DI    ;flag for subtraction
  464.  
  465.     call    dunnorm        ;unpack second operand (c)
  466.     mov    exp[BP],SI    ;save exponent of c
  467.     regstk            ;move registers to stack
  468.     mov    AX,nn+P+6[BP]
  469.     mov    BX,nn+P+4[BP]
  470.     mov    CX,nn+P+2[BP]
  471.     mov    DX,nn+P[BP]
  472.     call    dunnorm        ;unpack first operand (b)
  473.     sub    SI,exp[BP]    ;SI = exp(b) - exp(c)
  474.     ja    shiftc        ;exp(b) > exp(c)
  475.  
  476.     ; exp(b) <= exp(c)
  477.     ; exp(result) = exp(c)
  478.     ; if (SI <= -64)
  479.     ;    result is c
  480.     ; shift b right by -SI times so it matches with c
  481.  
  482.     .if    SI g -64, L25
  483.     ; result is c
  484.     mov    DI,signc[BP]    ;sign of result
  485.     stkreg
  486.     jmps    L33
  487.  
  488.     ; shift b right -SI times so it matches c
  489. L25:
  490.  
  491. CXA2:    .if    SI g -8, CXA1
  492.     shrby8
  493.     add    SI,8
  494.     jnz    CXA2
  495.  
  496. CXA1:    xchg    CX,SI
  497.     jcxz    L26        ;no shifting need be done
  498.     neg    CX
  499.  
  500. L27:    shr64    AX,BX,SI,DX
  501.     loop    L27
  502.  
  503. L26:    xchg    CX,SI        ;restore CX, SI = 0
  504.  
  505.     jmps    addsub
  506.  
  507.     ; exp(b) > exp(c)
  508.     ; exp(result) = exp(b)
  509.     ; if (SI <= 64)
  510.     ;    result is b
  511.     ; shift c right by SI times so it matches with b
  512.  
  513. shiftc:    add    exp[BP],SI    ;exp[BP] = exp(b)
  514.     .if    SI b 64, L28
  515.     ; result is b
  516.     mov    DI,signb[BP]    ;get sign of b
  517. L33:    mov    SI,exp[BP]
  518.     call    dnorm        ;normalize result
  519.     jmp    done
  520.  
  521. L28:    xchgstkreg
  522.  
  523. CXA3:    .if    SI b 8, CXA4
  524.     shrby8
  525.     sub    SI,8
  526.     jnz    CXA3
  527.     jmps    L36
  528.  
  529. CXA4:    xchg    CX,SI
  530. L32:    shr64    AX,BX,SI,DX
  531.     loop    L32
  532.     xchg    CX,SI        ;restore CX, SI = 0
  533.  
  534. L36:    xchgstkreg
  535.  
  536.     ;the following code depends on SI=0 (specifically, the neg64)
  537. addsub:                    ;b is in reg, c is on stack
  538.     shl    byte ptr minus+1[BP],1    ;subtracting? (test bit 15)
  539.     jnc    L29            ;no
  540.  
  541.     sub    DX,[BP]
  542.     sbb    CX,2[BP]
  543.     sbb    BX,4[BP]
  544.     sbb    AX,6[BP]
  545.     jnc    L31                ;no borrow
  546.     xor    byte ptr signb+1[BP],80h    ;toggle sign of result
  547.     neg64                    ;SI must be 0 for this to work
  548.     jmps    L31
  549.  
  550. L29:    add    DX,[BP]
  551.     adc    CX,2[BP]
  552.     adc    BX,4[BP]
  553.     adc    AX,6[BP]
  554.     jnc    L31
  555.     rcr    AX,1
  556.     rcr    BX,1
  557.     rcr    CX,1
  558.     rcr    DX,1
  559.     inc    word ptr exp[BP]    ;bump exponent
  560.  
  561. L31:    mov    DI,signb[BP]
  562.     mov    SI,exp[BP]    ;exponent of result
  563.     call    dnorm        ;normalize and pack result
  564.  
  565. done:    pop    SI
  566. L24:    pop    DI
  567.     add    SP,nn
  568.     pop    BP
  569.     ret    8
  570. c_endp    _DADD@
  571.  
  572. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  573. ; Double compare
  574. ;    a = b ? c
  575. ; Input:
  576. ;    stack = b
  577. ;    [AX,BX,CX,DX] = c
  578. ; Output:
  579. ;    a = [AX,BX,CX,DX]
  580. ; Be careful about negative 0 bugs.
  581.  
  582. func    _DCMP@
  583.     push    BP
  584.     mov    BP,SP
  585.     push    DI
  586.  
  587.     push    AX
  588.  
  589.     ;test if c is 0
  590.     mov    DI,AX
  591.     shl    DI,1            ;dump sign bit
  592.     or     DI,DX
  593.     or     DI,CX
  594.     or     DI,BX
  595.     jnz    C3            ;no
  596.     and    AH,7Fh            ;no -0 bugs
  597. C3:
  598.     mov    DI,6+P[BP]
  599.     shl    DI,1            ;dump sign bit
  600.     or    DI,4+P[BP]
  601.     or    DI,2+P[BP]
  602.     or    DI,P[BP]
  603.     jnz    C2            ;no
  604.     and    byte ptr 7+P[BP],7Fh    ;convert -0 to 0
  605. C2:
  606.     mov    DI,AX
  607.     xor    DI,word ptr 6+P[BP]
  608.     js    C52            ;signs are different
  609.     mov    DI,1            ;1 for positive compares
  610.     tst    AX
  611.     jns    C51
  612.     neg    DI            ;-1 for negative compares
  613. C51:    .if    6+P[BP] ne AX, C6    ;compare MSW
  614.     .if    4+P[BP] ne BX, C6
  615.     .if    2+P[BP] ne CX, C6
  616.     .if    P[BP] e DX, L21
  617. C6:    ja    C7
  618.     neg    DI
  619. C7:    tst    DI
  620. L21:    pop    AX
  621.     pop    DI
  622.     pop    BP
  623.     ret    8
  624.  
  625. C52:    cmp    6+P[BP],AX
  626.     jmp    L21
  627. c_endp    _DCMP@
  628.  
  629. ;;;;;;;;;;;;;;;;;;;
  630. ; Negate a double (or a float)
  631. ; Input:
  632. ;    [AX,BX,CX,DX]
  633. ; Output:
  634. ;    [AX,BX,CX,DX] = - [AX,BX,CX,DX]
  635.  
  636. func    _DNEG@
  637.     xor    AH,80h        ;toggle sign bit
  638.     ret
  639. c_endp    _DNEG@
  640.  
  641. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  642. ; Double floating divide.
  643. ;    a = b / c
  644. ; Input:
  645. ;    [BP] = b
  646. ;    [AX,BX,CX,DX] = c
  647. ; Output:
  648. ;    a = [AX,BX,CX,DX]
  649. ;    SI,DI preserved
  650.  
  651. ; Stack offsets:
  652.  
  653.     paddd    =    14        ;so nn == cxdd == mm == 38
  654.     resp    =    paddd+16    ;pointer to result
  655.     sign    =    resp+2        ;sign of result
  656.     exp    =    sign+2        ;exponent of result
  657.     count    =    exp+2        ;loop counter
  658.     cxdd    =    count+2        ;amount of local variables
  659.  
  660. func    _DDIV@
  661.     push    BP
  662.     sub    SP,cxdd
  663.     mov    BP,SP
  664.  
  665.     .if    _8087 e 0, D7        ;if no 8087
  666.     fld    qword ptr cxdd+P[BP]    ;load b
  667.     .push    <AX,BX,CX,DX>        ;push c
  668.     fdiv    qword ptr -8[BP]    ;div c
  669.     jmp    fltret
  670.  
  671. D2:    push    AX
  672.     mov    AX,3            ;divide by 0 error
  673.     push    AX
  674.     callm    CXFERR
  675.     pop    AX
  676.     pop    AX
  677.     xor    AX,cxdd+P+6[BP]
  678.     and    AX,8000h        ;isolate sign of result
  679.     or    AX,longexp        ;+ or - infinity
  680. D11:    clr    BX
  681.     mov    CX,BX
  682.     mov    DX,BX
  683. D1:    jmp    D8
  684.  
  685. D10:    clr    AX
  686.     jmp    D11
  687.  
  688. D7:    push    SI
  689.     push    DI
  690.     mov    DI,cxdd+P+6[BP]
  691.     shl    DI,1            ;dump sign bit
  692.     or    DI,cxdd+P+4[BP]
  693.     or    DI,cxdd+P+2[BP]
  694.     or    DI,cxdd+P+[BP]        ;is b 0?
  695.     jz    D10            ;yes, return 0
  696.  
  697.     mov    DI,AX
  698.     shl    DI,1            ;dump sign bit
  699.     or    DI,BX
  700.     or    DI,CX
  701.     or    DI,DX            ;is c 0?
  702.     jz    D2            ;yes, return +- infinity
  703.  
  704.     ;unpack c
  705.     mov    sign[BP],AX        ;sign of result
  706.     mov    DI,AX
  707.     and    DI,longexp        ;mask off exponent bits
  708.     xor    AX,DI            ;turn off exponent bits in AX
  709.     or    AL,longhid        ;or in hidden bit
  710.  
  711.     regstk                ;transfer sig(b) to 0[BP]
  712.  
  713.     mov    AX,cxdd+P+6[BP]
  714.     mov    BX,cxdd+P+4[BP]
  715.     mov    CX,cxdd+P+2[BP]
  716.     mov    DX,cxdd+P+[BP]        ;mov b into registers
  717.  
  718.     ;unpack b
  719.     xor    sign[BP],AX        ;sign(result) = sign(b) ^ sign(c)
  720.     mov    SI,AX
  721.     and    SI,longexp        ;mask off exponent bits
  722.     xor    AX,SI            ;turn off exponent bits in AX
  723.     or    AL,longhid        ;or in hidden bit
  724.  
  725.     sub    DI,longbias*16        ;so bias is retained after subtraction
  726.     sub    SI,DI            ;exp(result) = exp(b) - exp(c)
  727.  
  728.     shr    SI,1
  729.     shr    SI,1
  730.     shr    SI,1
  731.     shr    SI,1            ;right justify exponent
  732.     mov    exp[BP],SI        ;exponent of result
  733.  
  734.     mov    SI,CX            ;free up CX for loop counter
  735.     mov    AH,6[BP]
  736. ;;;;;;;
  737.     ;if (b >= c) goto D31 else D41
  738.     mov    CX,16            ;16 bits per word
  739.  
  740. D51:    .if    AL a AH, D31
  741.     jb    D41
  742.     .if    BX a 4[BP], D31
  743.     jb    D41
  744.     .if    SI a 2[BP], D31
  745.     jb    D41
  746.     .if    DX b 0[BP], D41
  747.  
  748.     ;b -= c
  749.  
  750. D31:    sub    DX,0[BP]
  751.     sbb    SI,2[BP]
  752.     sbb    BX,4[BP]
  753.     sbb    AL,AH            ;since b >= c, C == 0
  754.  
  755. D41:    rcl    DI,1            ;0 if we subtracted, 1 if not
  756.     shl64    AL,BX,SI,DX        ;b <<= 1
  757.     loop    D51
  758.     not    DI            ;we shifted in the complement
  759.     push    DI
  760.  
  761. ;;;;;;;
  762.     ;if (b >= c) goto D32 else D42
  763.     mov    CL,16
  764.     mov    DX,4[BP]        ;DX is free'd up, use it
  765.  
  766. D52:    .if    AL a AH, D32
  767.     jb    D42
  768.     .if    BX a DX, D32
  769.     jb    D42
  770.     .if    SI b 2[BP], D42
  771.  
  772.     ;b -= c
  773.  
  774. D32:    sub    SI,2[BP]
  775.     sbb    BX,DX
  776.     sbb    AL,AH            ;since b >= c, C == 0
  777.  
  778. D42:    rcl    DI,1            ;0 if we subtracted, 1 if not
  779.     shl    SI,1
  780.     rcl    BX,1
  781.     rcl    AL,1            ;b <<= 1
  782.     loop    D52
  783.     not    DI            ;we shifted in the complement
  784.     push    DI
  785.  
  786. ;;;;;;;
  787.     ;if (b >= c) goto D33 else D43
  788.     mov    CL,16
  789.  
  790. D53:    .if    AL a AH, D33
  791.     jb    D43
  792.     .if    BX b DX, D43
  793.  
  794.     ;b -= c
  795.  
  796. D33:    sub    BX,DX
  797.     sbb    AL,AH            ;since b >= c, C == 0
  798.  
  799. D43:    rcl    DI,1            ;0 if we subtracted, 1 if not
  800.     shl    BX,1
  801.     rcl    AL,1            ;b <<= 1
  802.     loop    D53
  803.     not    DI            ;we shifted in the complement
  804.  
  805. ;;;;;;;
  806.     ;if (b >= c) goto D34 else D44
  807.     mov    CL,8
  808.  
  809. D54:    .if    AL b AH, D44
  810.  
  811.     ;b -= c
  812.  
  813.     sub    AL,AH            ;since b >= c, C == 0
  814.  
  815. D44:    rcl    DH,1            ;0 if we subtracted, 1 if not
  816.     shl    AL,1            ;b <<= 1
  817.     loop    D54
  818.     not    DH            ;we shifted in the complement
  819.     mov    DL,CH            ;DX <<= 8 (CH == 0)
  820.  
  821. ;;;;;;;
  822.  
  823.     mov    CX,DI
  824.     pop    BX
  825.     pop    AX            ;load sig(result)
  826.     mov    SI,exp[BP]
  827.     mov    DI,sign[BP]
  828.     call    dnorm            ;normalize result
  829. D8:    pop    DI
  830.     pop    SI
  831.     add    SP,cxdd
  832.     pop    BP
  833.     ret    8
  834. c_endp    _DDIV@
  835.  
  836. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  837. ; Double floating multiply.
  838. ;    a = b * c
  839. ; Input:
  840. ;    [BP] = c
  841. ;    [AX,BX,CX,DX] = c
  842. ; Output:
  843. ;    a = [AX,BX,CX,DX]
  844. ;    SI,DI preserved
  845.  
  846. ; Stack offsets:
  847.  
  848.     sign    =    8+8+16        ;sig(b) + sig(c) + sig(result)
  849.     exp    =    sign+2
  850.     count    =    exp+2
  851.     mm    =    count+2
  852.  
  853. func    _DMUL@
  854.     push    BP
  855.     sub    SP,mm
  856.     mov    BP,SP
  857.     .if    _8087 e 0, M7        ;if no 8087
  858.  
  859.     fld    qword ptr mm+P[BP]    ;load b
  860.     .push    <AX,BX,CX,DX>        ;push c
  861.     fmul    qword ptr -8[BP]    ;mul c
  862.     jmp    fltret
  863.  
  864. M1:    jmp    M8
  865.  
  866. M7:    push    SI
  867.     push    DI
  868.     mov    DI,AX
  869.     shl    DI,1            ;dump sign bit
  870.     rcr    word ptr sign[BP],1    ;save sign
  871.     or    DI,BX
  872.     or    DI,CX
  873.     or    DI,DX            ;is c 0?
  874.     jz    M1            ;yes
  875.  
  876.     mov    exp[BP],AX        ;exponent of result
  877.     and    word ptr exp[BP],longexp ;mask off exponent bits
  878.     or    AL,longhid        ;or in hidden bit
  879.     and    AX,01Fh
  880.  
  881.     regstk                ;transfer sig(c) to 0[BP]
  882.  
  883.     mov    AX,nn+P+6[BP]
  884.     mov    BX,nn+P+4[BP]
  885.     mov    CX,nn+P+2[BP]
  886.     mov    DX,nn+P[BP]        ;get b
  887.  
  888.     mov    DI,AX
  889.     shl    DI,1            ;dump sign bit
  890.     or    DI,BX
  891.     or    DI,CX
  892.     or    DI,DX            ;is b 0?
  893.     jz    M1            ;yes
  894.  
  895.     xor    sign[BP],AX        ;sign(result) = sign(b) ^ sign(c)
  896.     mov    SI,AX
  897.     and    SI,longexp        ;mask off exponent bits
  898.     add    SI,exp[BP]
  899.     shr    SI,1
  900.     shr    SI,1
  901.     shr    SI,1
  902.     shr    SI,1            ;right justify exponent
  903.     add    SI,11+11-(longbias-1)    ;don't want 2 * bias
  904.     mov    exp[BP],SI        ;exp(result) = exp(b) + exp(c)
  905.  
  906.     or    AL,longhid        ;or in hidden bit
  907.     and    AX,01Fh
  908.  
  909.     ife ESeqDS
  910.     mov    SI,ES
  911.     mov    DI,SS
  912.     mov    ES,DI
  913.     endif
  914.     lea    DI,14[BP]
  915.     mov    8[BP],DX
  916.     mov    10[BP],CX
  917.     mov    12[BP],BX
  918.     cld
  919.     stosw                ;transfer c to 8[BP]
  920.     clr    AX
  921.     mov    CX,8            ;8 words of 0 to product
  922.     rep    stosw
  923.     ife ESeqDS
  924.     mov    ES,SI
  925.     endif
  926.  
  927.     ;Compute the 128 bit result of sig(b)*sig(c), and use the high 64 bits.
  928.  
  929.     if LPTR
  930.     push    DS
  931.     mov    AX,SS
  932.     mov    DS,AX
  933.     endif
  934.     ;BP -> b
  935.     sub    DI,16+8            ;DI -> c (BP + 8)
  936.     clr    BX
  937.     mov    CX,6[DI]
  938.     mov    SI,4[DI]
  939.  
  940.     ;BP    -> b
  941.     ;BP+16 -> result
  942.     mov    AX,[BP]            ;get word from b
  943.  
  944.     mul    word ptr [DI]        ;* word from c
  945.     mov    2[BP+16],DX        ;msw of multiply
  946.  
  947.     mov    AX,[BP]            ;get word from b
  948.     mul    word ptr 2[DI]        ;* word from c
  949.     add    2[BP+16],AX        ;lsw of multiply
  950.     adc    4[BP+16],DX        ;msw of multiply
  951.  
  952.     mov    AX,[BP]            ;get word from b
  953.     mul    SI            ;* word from c
  954.     add    4[BP+16],AX        ;lsw of multiply
  955.     adc    22[BP],DX        ;msw of multiply
  956.  
  957.     mov    AX,[BP]            ;get word from b
  958.     mul    CX            ;* word from c
  959.     add    22[BP],AX        ;lsw of multiply
  960.     adc    24[BP],DX        ;msw of multiply
  961.  
  962.     mov    AX,2[BP]        ;get word from b
  963.  
  964.     mul    word ptr [DI]        ;* word from c
  965.     add    2[BP+16],AX        ;lsw of multiply
  966.     adc    4[BP+16],DX        ;msw of multiply
  967.     adc    22[BP],BX
  968.     adc    24[BP],BX
  969.  
  970.     mov    AX,2[BP]        ;get word from b
  971.     mul    word ptr 2[DI]        ;* word from c
  972.     add    4[BP+16],AX        ;lsw of multiply
  973.     adc    22[BP],DX        ;msw of multiply
  974.     adc    24[BP],BX
  975.  
  976.     mov    AX,2[BP]        ;get word from b
  977.     mul    SI            ;* word from c
  978.     add    22[BP],AX        ;lsw of multiply
  979.     adc    24[BP],DX        ;msw of multiply
  980.     adc    26[BP],BX
  981.  
  982.     mov    AX,2[BP]        ;get word from b
  983.     mul    CX            ;* word from c
  984.     add    24[BP],AX        ;lsw of multiply
  985.     adc    26[BP],DX        ;msw of multiply
  986.  
  987.     mov    AX,4[BP]        ;get word from b
  988.  
  989.     mul    word ptr [DI]        ;* word from c
  990.     add    4[BP+16],AX        ;lsw of multiply
  991.     adc    22[BP],DX        ;msw of multiply
  992.     adc    24[BP],BX
  993.     adc    26[BP],BX
  994.  
  995.     mov    AX,4[BP]        ;get word from b
  996.     mul    word ptr 2[DI]        ;* word from c
  997.     add    22[BP],AX        ;lsw of multiply
  998.     adc    24[BP],DX        ;msw of multiply
  999.     adc    26[BP],BX
  1000.  
  1001.     mov    AX,4[BP]        ;get word from b
  1002.     mul    SI            ;* word from c
  1003.     add    24[BP],AX        ;lsw of multiply
  1004.     adc    26[BP],DX        ;msw of multiply
  1005.     adc    28[BP],BX
  1006.  
  1007.     mov    AX,4[BP]        ;get word from b
  1008.     mul    CX            ;* word from c
  1009.     add    26[BP],AX        ;lsw of multiply
  1010.     adc    28[BP],DX        ;msw of multiply
  1011.  
  1012.     mov    AX,6[BP]        ;get word from b
  1013.  
  1014.     mul    word ptr [DI]        ;* word from c
  1015.     add    22[BP],AX        ;lsw of multiply
  1016.     adc    24[BP],DX        ;msw of multiply
  1017.     adc    26[BP],BX
  1018.     adc    28[BP],BX
  1019.  
  1020.     mov    AX,6[BP]        ;get word from b
  1021.     mul    word ptr 2[DI]        ;* word from c
  1022.     add    24[BP],AX        ;lsw of multiply
  1023.     adc    26[BP],DX        ;msw of multiply
  1024.     adc    28[BP],BX
  1025.  
  1026.     mov    AX,6[BP]        ;get word from b
  1027.     mul    SI            ;* word from c
  1028.     add    26[BP],AX        ;lsw of multiply
  1029.     adc    DX,28[BP]        ;msw of multiply
  1030.  
  1031.     mov    AX,6[BP]        ;get word from b
  1032.     mul    CL            ;* word from c
  1033.     add    AX,DX            ;lsw of multiply
  1034.  
  1035.  
  1036.     if LPTR
  1037.     pop    DS
  1038.     endif
  1039.  
  1040.     ;Gather result, pack it and return it
  1041.  
  1042.     mov    DX,22[BP]
  1043.     mov    CX,24[BP]
  1044.     mov    BX,26[BP]
  1045. ;    mov    AX,28[BP]        ;get high 64 bits of result
  1046.                     ;knowing that top 16 bits of 128 bit
  1047.                     ;result is 0
  1048.     shr64    AX,BX,CX,DX
  1049.     shr64    AX,BX,CX,DX
  1050.     shr64    AX,BX,CX,DX
  1051.     mov    SI,exp[BP]
  1052.     sub    SI,16-3+11        ;we've already shifted 16-3 bits
  1053.                     ;the 11 is from 1st part of dnorm()
  1054.     mov    DI,sign[BP]
  1055.     call    dnorm2            ;normalize result
  1056. M8:    pop    DI
  1057.     pop    SI
  1058.     add    SP,mm
  1059.     pop    BP
  1060.     ret    8
  1061. c_endp    _DMUL@
  1062.  
  1063. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1064. ; Convert unsigned int to double.
  1065. ; SI,DI preserved.
  1066.  
  1067. func    _UNSDBL@
  1068.     clc
  1069.     jmps    A10
  1070. c_endp    _UNSDBL@
  1071.  
  1072. ; Convert int to double
  1073.  
  1074. func    _INTDBL@
  1075.     .if    _8087 e 0, A11        ;if no 8087
  1076.     push    AX
  1077.     sub    SP,6            ;3 extra words
  1078.     push    BP
  1079.     mov    BP,SP
  1080.     fild    word ptr 6+2[BP]    ;load integer into 8087
  1081.     jmp    fltret2
  1082.  
  1083. A11:    or    AX,AX            ;negative? (also clear C)
  1084.     jns    A10            ;no
  1085.     neg    AX            ;abs value (also set C)
  1086. A10:    .push    <SI,DI>
  1087.     rcr    DI,1            ;bit 15 becomes sign of result
  1088.     cwd
  1089.     mov    CX,DX
  1090.     mov    BX,DX            ;rest of significand is 0
  1091.     mov    SI,15+longbias        ;2^15
  1092.     call    dnorm            ;pack result into a double
  1093.     .pop    <DI,SI>
  1094.     ret
  1095. c_endp    _INTDBL@
  1096.  
  1097. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1098. ; Convert unsigned long to double.
  1099. ; SI,DI preserved.
  1100.  
  1101. func    _ULNGDBL@
  1102.     clc
  1103.     jmps    A8
  1104. c_endp    _ULNGDBL@
  1105.  
  1106. ; Convert long to double.
  1107.  
  1108. func    _LNGDBL@
  1109.     .if    _8087 e 0, A12    ;if no 8087
  1110.     .push    <DX,AX>
  1111.     sub    SP,4        ;2 extra words
  1112.     push    BP
  1113.     mov    BP,SP
  1114.     fild    dword ptr 6[BP]    ;load long into 8087
  1115.     jmp    fltret2
  1116.  
  1117. A12:    or    DX,DX            ;negative? (also clear C)
  1118.     jns    A8            ;no
  1119.     neg32    DX,AX            ;abs value
  1120.     stc                ;indicate negative result
  1121. A8:    .push    <SI,DI>
  1122.     rcr    DI,1            ;bit 15 becomes sign of result
  1123.     clr    CX
  1124.     mov    BX,CX            ;rest of significand is 0
  1125.     xchg    AX,BX
  1126.     xchg    AX,DX
  1127.     mov    SI,31+longbias        ;2^15
  1128.     call    dnorm            ;pack result into a double
  1129.     .pop    <DI,SI>
  1130.     ret
  1131. c_endp    _LNGDBL@
  1132.  
  1133. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1134. ; Convert from float to long.
  1135. ; Input:
  1136. ;    [DX,AX] = float
  1137. ; Output:
  1138. ;    [DX,AX] = long, BX,CX,SI,DI are preserved
  1139.  
  1140. func    _FLTLNG@
  1141.     .push    <BX,CX>
  1142.     callm    _FLTDBL@        ;convert float to double
  1143.     callm    _DBLLNG@        ;and the double to a long
  1144.     .pop    <CX,BX>
  1145.     ret
  1146. c_endp    _FLTLNG@
  1147.  
  1148. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1149. ; Convert from float to double.
  1150. ; Input:
  1151. ;    [DX,AX] = float
  1152. ; Output:
  1153. ;    [AX,BX,CX,DX] = double
  1154.  
  1155. func    _FLTDBL@
  1156.     .if    _8087 e 0, C4    ;if no 8087
  1157.     .push    <DX,AX>        ;push b
  1158.     sub    SP,4        ;2 extra words
  1159.     push    BP
  1160.     mov    BP,SP
  1161.     fld    dword ptr 6[BP]    ;load float into 8087
  1162. fltret2:
  1163.     fstp    qword ptr 2[BP]
  1164.     pop    BP
  1165.     fwait            ;wait for it to finish
  1166.     .pop    <DX,CX,BX,AX>    ;pop result
  1167.     ret
  1168.  
  1169. C4:    push    DI
  1170.     clr    CX
  1171.     mov    BX,CX
  1172.     mov    DI,DX            ;save sign
  1173.     shl    DI,1            ;strip sign
  1174.     or    DI,AX            ;is the float 0?
  1175.     jz    C1            ;yes, 0 result
  1176.     push    SI
  1177.     call    $funnorm        ;unpack the float
  1178.     xchg    AX,BX
  1179.     xchg    AX,DX
  1180.     add    SI,longbias-shortbias    ;fix the bias on the exponent
  1181.     call    dnorm            ;pack a double
  1182.     pop    SI
  1183. C1:    pop    DI
  1184.     ret
  1185. c_endp    _FLTDBL@
  1186.  
  1187. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1188. ; Convert double to unsigned.
  1189.  
  1190. func    _DBLUNS@
  1191.     callm    _DTST@        ;is the double 0?
  1192.     jz    A7        ;yes
  1193.     .push    <SI,DI>
  1194.     call    dunnorm        ;unpack double
  1195.     tst    DI        ;negative?
  1196.     js    A3        ;negative doubles map to 0
  1197. ;    clc            ;flag unsigned
  1198.     jmps    A6
  1199. c_endp    _DBLUNS@
  1200.  
  1201. ; Convert double to int.
  1202.  
  1203. func    _DBLINT@
  1204.     callm    _DTST@        ;is the double 0?
  1205.     jz    A7        ;yes
  1206.     .push    <SI,DI>
  1207.     call    dunnorm        ;unpack double
  1208.     stc            ;flag signed
  1209. A6:    rcr    BL,1        ;BL sign bit is sign flag
  1210.     sub    SI,longbias    ;un-bias the exponent
  1211.     js    A3        ;for neg exponents, the result is 0
  1212.     mov    CX,15
  1213.     sub    CX,SI        ;15-exp is # of bits to shift
  1214.     jc    A9        ;overflow (double is too large)
  1215.     je    A13        ;bit 15 is set in result (AX was left-justified)
  1216.     shr    AX,CL
  1217. ;    adc    AX,0        ;round up
  1218. ;    js    A13        ;handle bit 15 being set in the result
  1219.     tst    DI        ;is result negative?
  1220.     jns    A4        ;no
  1221.     neg    AX        ;yes
  1222. A4:    .pop    <DI,SI>
  1223.     ret
  1224.  
  1225. A3:    .pop    <DI,SI>
  1226. A7:    clr    AX        ;result is 0
  1227.     ret
  1228.  
  1229. A9:    mov    AX,0FFFFh    ;unsigned infinity
  1230.     tst    BL        ;unsigned conversion?
  1231.     jns    A4        ;yes
  1232.     shr    AX,1        ;signed positive infinity (7FFFh)
  1233.     tst    DI        ;negative?
  1234.     jns    A4        ;no
  1235.     not    AX        ;AX = 8000h, which is negative infinity
  1236.     jmp    A4
  1237.  
  1238. A13:    tst    BL        ;signed conversion?
  1239.     js    A9        ;yes, overflow
  1240.     jmp    A4        ;no, AX has result
  1241. c_endp    _DBLINT@
  1242.  
  1243.  
  1244. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  1245. ; Convert double to unsigned long.
  1246.  
  1247. func    _DBLULNG@
  1248.     callm    _DTST@        ;is the double 0?
  1249.     jz    B7        ;yes
  1250.     .push    <SI,DI>
  1251.     call    dunnorm        ;unpack double
  1252.     tst    DI        ;negative?
  1253.     js    B3        ;negative doubles map to 0
  1254. ;    clc            ;flag unsigned
  1255.     jmps    B6
  1256. c_endp    _DBLULNG@
  1257.  
  1258. ; Convert double to long
  1259.  
  1260. func    _DBLLNG@
  1261.     callm    _DTST@        ;is the double 0?
  1262.     jz    B7        ;yes
  1263.     .push    <SI,DI>
  1264.     call    dunnorm        ;unpack double
  1265.     stc            ;flag signed
  1266. B6:    mov    DX,AX
  1267.     mov    AX,BX
  1268.     rcr    BL,1
  1269.     sub    SI,longbias    ;un-bias the exponent
  1270.     js    B3        ;for neg exponents, the result is 0
  1271.     mov    CX,31
  1272.     .if    SI a CX, B9    ;number is too large
  1273.     sub    CX,SI        ;31-exp is # of bits to shift
  1274.     jcxz    B13
  1275. B1:    shr    DX,1
  1276.     rcr    AX,1
  1277.     loop    B1
  1278. ;    adc    AX,CX
  1279. ;    adc    DX,CX        ;round up
  1280. ;    js    B13        ;most significant bit is set
  1281.     tst    DI        ;is result negative?
  1282.     jns    B4        ;no
  1283.     neg32    DX,AX        ;yes
  1284. B4:    .pop    <DI,SI>
  1285.     ret
  1286.  
  1287. B3:    .pop    <DI,SI>
  1288. B7:    clr    AX        ;result is 0
  1289.     cwd
  1290.     ret
  1291.  
  1292. B9:    mov    AX,0FFFFh
  1293.     cwd            ;unsigned infinity
  1294.     tst    BL        ;unsigned conversion?
  1295.     jns    B4        ;yes
  1296.     shr    DX,1        ;signed positive infinity (7FFFh)
  1297.     tst    DI        ;negative?
  1298.     jns    B4        ;no
  1299.     not    AX
  1300.     not    DX        ;DX,AX = 80000000h, which is -infinity
  1301.     jmp    B4
  1302.  
  1303. B13:    tst    BL        ;signed conversion?
  1304.     js    B9        ;signed overflow
  1305.     jmp    B4        ;no, DX,AX has the result
  1306. c_endp    _DBLLNG@
  1307.  
  1308.  
  1309. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1310. ; Convert from double to float.
  1311. ; Input:
  1312. ;    [AX,BX,CX,DX]
  1313. ; Output:
  1314. ;    [DX,AX]
  1315. ;    CX,BX    destroyed
  1316. ;    SI,DI    preserved
  1317.  
  1318. func    _DBLFLT@
  1319.     .if    _8087 e 0, C5    ;if no 8087
  1320.     .push    <AX,BX,CX,DX>    ;push double
  1321.     push    BP
  1322.     mov    BP,SP
  1323.     fld    qword ptr 2[BP]    ;load b into 8087
  1324.     fstp    dword ptr 6[BP]    ;store float result
  1325.     pop    BP
  1326.     add    SP,4
  1327.     fwait            ;wait for it to finish
  1328.     .pop    <AX,DX>        ;pop result
  1329.     ret
  1330.  
  1331. C5:    callm    _DTST@            ;is the double 0?
  1332.     jz    L10            ;yes, float is 0
  1333.     .push    <SI,DI>
  1334.     call    dunnorm            ;unpack double
  1335.     sub    SI,longbias-shortbias    ;fix exponent bias
  1336.     xchg    DX,AX
  1337.     xchg    AX,BX
  1338.     call    $fnorm            ;pack float
  1339.     .pop    <DI,SI>
  1340.     ret
  1341.  
  1342. L10:    cbw                ;make sure AX is 0
  1343.     ret
  1344. c_endp    _DBLFLT@
  1345.  
  1346. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1347. ; Convert int to float
  1348.  
  1349. func    _INTFLT@
  1350.     .push    <BX,CX>
  1351.     callm    _INTDBL@
  1352. CX1:    callm    _DBLFLT@
  1353. CX2:    .pop    <CX,BX>
  1354.     ret
  1355. c_endp    _INTFLT@
  1356.  
  1357. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1358. ; Convert unsigned to float
  1359.  
  1360. func    _UNSFLT@
  1361.     .push    <BX,CX>
  1362.     callm    _UNSDBL@
  1363.     jmp    CX1
  1364. c_endp    _UNSFLT@
  1365.  
  1366. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1367. ; Convert long to float
  1368.  
  1369. __LNGFLT@:
  1370.     .push    <BX,CX>
  1371.     callm    _LNGDBL@
  1372.     jmp    CX1
  1373.  
  1374. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1375. ; Convert float to int
  1376.  
  1377. __FLTINT@:
  1378.     .push    <BX,CX>
  1379.     callm    _FLTDBL@
  1380.     callm    _DBLINT@
  1381.     jmp    CX2
  1382.  
  1383. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1384. ; Convert float to unsigned
  1385.  
  1386. __FLTUNS:
  1387.     .push    <BX,CX>
  1388.     callm    _FLTDBL@
  1389.     callm    _DBLUNS@
  1390.     jmp    CX2
  1391.  
  1392. ;;;;;;;;;;;;;;;;;;;; INLINE 8087 SUPPORT ;;;;;;;;;;;;;;;;;;;;;
  1393.  
  1394. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1395. ; Test ST0, pop it, and set results in PSW.
  1396.  
  1397. func    _DTST87@
  1398.     FTST
  1399.     FSTP    ST(0)
  1400. ;    callm    _87TOPSW@
  1401. ;    ret
  1402. c_endp    _DTST87@
  1403.  
  1404. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1405. ; Convert 8087 flags into 8088 flags.
  1406.  
  1407. func    _87TOPSW@
  1408.     push    BP
  1409.     mov    BP,SP
  1410.     sub    SP,2            ;can only transfer through memory
  1411.     fstsw    word ptr -2[BP]        ;transfer 8087 status word
  1412.     push    AX            ;save AX, allow 8087 time to finish
  1413.     fwait                ;make sure 8087 is finished
  1414.     mov    AH,byte ptr -1[BP]    ;interested in second byte
  1415.     sahf                ;transfer to 8088 flags
  1416.     pop    AX
  1417.     mov    SP,BP
  1418.     pop    BP
  1419.     ret
  1420. c_endp    _87TOPSW@
  1421.  
  1422. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1423. ; Convert AX,BX,CX,DX into ST0.
  1424.  
  1425. func    _DBLTO87@
  1426.     push    BP
  1427.     mov    BP,SP
  1428.     .push    <AX,BX,CX,DX>
  1429.     fld    qword ptr -8[BP]
  1430. N1:    fwait            ;make sure it's done before popping stack
  1431.     mov    SP,BP
  1432.     pop    BP
  1433.     ret
  1434. c_endp    _DBLTO87@
  1435.  
  1436. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1437. ; Convert DX,AX (float) into ST0.
  1438.  
  1439. func    _FLTTO87@
  1440.     push    BP
  1441.     mov    BP,SP
  1442.     .push    <DX,AX>
  1443.     fld    dword ptr -4[BP]
  1444.     jmps    N1
  1445. c_endp    _FLTTO87@
  1446.  
  1447. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1448. ; Convert ST0 into an int in AX.
  1449. ; ANSI says that rounding to int truncates towards 0.
  1450.  
  1451. func    _DBLINT87@
  1452.     push    BP
  1453.     mov    BP,SP
  1454.     sub    SP,4
  1455.     fstcw    -2[BP]        ;save original control word
  1456.     fldcw    roundto0
  1457.     fistp    word ptr -4[BP]
  1458.     fwait
  1459.     pop    AX
  1460. N3:    ;fnldcw    -2[BP]        ;restore original control word
  1461.     db    0D8h+1,06Eh,-2
  1462.     fwait
  1463.     mov    SP,BP
  1464.     pop    BP
  1465.     ret
  1466. c_endp    _DBLINT87@
  1467.  
  1468. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1469. ; Convert ST0 into a long in DX,AX.
  1470. ; ANSI says that rounding to long truncates towards 0.
  1471.  
  1472. func    _DBLLNG87@
  1473.     push    BP
  1474.     mov    BP,SP
  1475.     sub    SP,6
  1476.     fstcw    -2[BP]        ;save original control word
  1477.     fldcw    roundto0
  1478.     fistp    dword ptr -6[BP]
  1479.     fwait
  1480.     pop    AX
  1481.     pop    DX
  1482.     jmps    N3
  1483. c_endp    _DBLLNG87@
  1484.  
  1485.     endcode    float
  1486.  
  1487.     end
  1488.