home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v17n03 / ucrasm.exe / SOURCE.EXE / FP.ASM < prev    next >
Encoding:
Assembly Source File  |  1991-10-31  |  80.0 KB  |  3,612 lines

  1. ;
  2. StdGrp        group    StdLib, StdData
  3. ;
  4. StdData        segment    para public 'sldata'
  5. ;
  6. ; Floating point package.
  7. ;
  8. ;
  9. ; Released to the public domain
  10. ; Created by: Randall Hyde
  11. ; Date: 8/13/90
  12. ;    8/28/91
  13. ;
  14. ;
  15. ; FP format:
  16. ;
  17. ; 80 bits:
  18. ; bit 79            bit 63                           bit 0
  19. ; |                 |                                    |
  20. ; seeeeeee eeeeeeee mmmmmmmm m...m m...m m...m m...m m...m
  21. ;
  22. ; e = bias 16384 exponent
  23. ; m = 64 bit mantissa with NO implied bit!
  24. ; s = sign (for mantissa)
  25. ;
  26. ;
  27. ; 64 bits:
  28. ; bit 63       bit 51                                               bit 0
  29. ; |            |                                                        |
  30. ; seeeeeee eeeemmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm
  31. ;
  32. ; e = bias 1023 exponent.
  33. ; s = sign bit.
  34. ; m = mantissa bits.  Bit 52 is an implied one bit.
  35. ;
  36. ; 32 bits:
  37. ; Bit 31    Bit 22              Bit 0
  38. ; |         |                       |
  39. ; seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
  40. ;
  41. ; e = bias 127 exponent
  42. ; s = sign bit
  43. ; m = mantissa bits, bit 23 is an implied one bit.
  44. ;
  45. ;
  46. ;
  47. ; WARNING: Although this package uses IEEE format floating point numbers,
  48. ;       it is by no means IEEE compliant.  In particular, it does not
  49. ;       support denormalized numbers, special rounding options, and
  50. ;       so on.  Why not?  Two reasons:  I'm lazy and I'm ignorant.
  51. ;       I do not know all the little details surround the IEEE
  52. ;       implementation and I'm not willing to spend more of my life
  53. ;       (than I already have) figuring it out.  There are more
  54. ;       important things to do in life.  Yep, numerical analysts can
  55. ;       rip this stuff to shreads and come up with all kinds of degenerate
  56. ;       cases where this package fails and the IEEE algorithms succeed,
  57. ;       however, such cases are very rare.  One should not get the idea
  58. ;       that IEEE is perfect.  It blows up with lots of degenerate cases
  59. ;       too.  They just designed it so that it handles a few additional
  60. ;       cases that mediocre packages (like this one) do not.  For most
  61. ;       normal computations this package works just fine (what it lacks
  62. ;       it good algorithms it more than makes up for by using an 88-bit
  63. ;       internal format during internal computations).
  64. ;
  65. ;       Moral of the story: If you need highly accurate routines which
  66. ;          produce okay results in the worst of cases, look elsewhere please.
  67. ;       I don't want to be responsible for your blowups.  OTOH, if you need
  68. ;       a fast floating point package which is reasonably accurate and
  69. ;       you're not a statistician, astronomer, or other type for whom
  70. ;       features like denormalized numbers are important, this package
  71. ;       may work out just fine for you.
  72. ;
  73. ;                        Randy Hyde
  74. ;                        August 1990
  75. ;                        (Hard to believe I started this
  76. ;                         a year ago and I'm just coming
  77. ;                         back to it now!)
  78. ;
  79. ;                        UC Riverside &
  80. ;                        Cal Poly Pomona.
  81. ;
  82. ; FPACC- Floating point accumuator.
  83. ; FPOP-  Floating point operand.
  84. ;
  85. ; These variables use the following format:
  86. ;
  87. ; 88 bits:
  88. ; sxxxxxxx eeeeeeee eeeeeeee m..m m..m m..m m..m m..m m..m m..m m..m
  89. ; Sign          exponent                   mantissa (64 bits)
  90. ;
  91. ; Only H.O. bit of Sign byte is significant.  The rest is garbage.
  92. ; Exponent is bias 32767 exponent.
  93. ; Mantissa does NOT have an implied one bit.
  94. ;
  95. ; This format was picked for convenience (it is easy to work with) and it
  96. ; exceeds the 80-bit format used by Intel on the 80x87 chips.
  97. ;
  98. fptype        struc
  99. Mantissa    dw    4 dup (?)
  100. Exponent    dw    ?
  101. Sign        db    ?
  102.         db    ?        ;Padding
  103. fptype        ends
  104. ;
  105. ;
  106. ;
  107. ;
  108.         public    fpacc
  109. fpacc        fptype    <>
  110. ;
  111.         public    fpop
  112. fpop        fptype  <>
  113. ;
  114. ;
  115. ; FProd- Holds 144-bit result obtained by multiplying fpacc.mant x fpop.mant
  116. ;
  117. Quotient    equ    this word
  118. fprod        dw    9 dup (?)
  119. ;
  120. ;
  121. ; Variables used by the floating point I/O routines:
  122. ;
  123. TempExp        dw    ?
  124. ExpSign        db    ?
  125. DecExponent    dw    ?
  126. DecSign        db    0
  127. DecDigits    db    31 dup (?)
  128. ;
  129. ;
  130. ;
  131. StdData        ends
  132. ;
  133. ;
  134. stdlib        segment    para public 'slcode'
  135.         assume    cs:stdgrp, ds:nothing, es:nothing, ss:nothing
  136. ;
  137. ;
  138. ;
  139. ;
  140. ;
  141. ;
  142. ;
  143. ;
  144. ;
  145. ;
  146. ;---------------------------------------------------------------------------
  147. ;        Floating Point Load/Store Routines
  148. ;---------------------------------------------------------------------------
  149. ;
  150. ; sl_AccOp    Copies the floating point accumulator to the floating point
  151. ;        operand.
  152. ;
  153.         public    sl_AccOp
  154. sl_AccOp    proc    far
  155.         assume    ds:StdGrp
  156.         push    ax
  157.         push    ds
  158.         mov    ax, StdGrp
  159.         mov    ds, ax
  160. ;
  161.         mov    ax, FPacc.Exponent
  162.         mov    FPop.Exponent, ax
  163.         mov    ax, FPacc.Mantissa
  164.         mov    FPop.Mantissa, ax
  165.         mov    ax, FPacc.Mantissa+2
  166.         mov    FPop.Mantissa+2, ax
  167.         mov    ax, FPacc.Mantissa+4
  168.         mov    FPop.Mantissa+4, ax
  169.         mov    ax, FPacc.Mantissa+6
  170.         mov    FPop.Mantissa+6, ax
  171.         mov    al, Fpacc.Sign
  172.         mov    FPop.Sign, al
  173. ;
  174.         pop    ds
  175.         pop    ax
  176.         ret
  177. sl_AccOp    endp
  178.         assume    ds:nothing
  179. ;
  180. ;
  181. ; sl_XAccOp-    Exchanges the values in the floating point accumulator
  182. ;        and floating point operand.
  183. ;
  184.         public    sl_XAccOp
  185. sl_XAccOp    proc    far
  186.         assume    ds:StdGrp
  187.         push    ax
  188.         push    ds
  189.         mov    ax, StdGrp
  190.         mov    ds, ax
  191. ;
  192.         mov    ax, FPacc.Exponent
  193.         xchg    ax, FPop.Exponent
  194.         mov    FPacc.Exponent, ax
  195. ;
  196.         mov    ax, FPacc.Mantissa
  197.         xchg    ax, FPop.Mantissa
  198.         mov    FPacc.Mantissa, ax
  199. ;
  200.         mov    ax, FPacc.Mantissa+2
  201.         xchg    ax, FPop.Mantissa+2
  202.         mov    FPacc.Mantissa+2, ax
  203. ;
  204.         mov    ax, FPacc.Mantissa+4
  205.         xchg    ax, FPop.Mantissa+4
  206.         mov    FPacc.Mantissa+4, ax
  207. ;
  208.         mov    ax, FPacc.Mantissa+6
  209.         xchg    ax, FPop.Mantissa+6
  210.         mov    FPacc.Mantissa+6, ax
  211. ;
  212.         mov    al, FPacc.Sign
  213.         xchg    al, FPop.Sign
  214.         mov    FPacc.Sign, al
  215. ;
  216.         pop    ds
  217.         pop    ax
  218.         ret
  219. sl_XAccOp    endp
  220.         assume    ds:nothing
  221. ;
  222. ;
  223. ;
  224. ; sl_LSFPA-     Loads a single precision (32-bit) IEEE format number into
  225. ;        the floating point accumulator.  ES:DI points at the # to
  226. ;        load into FPACC.
  227. ;
  228.         public    sl_LSFPA
  229. sl_LSFPA    proc    far
  230.         push    ax
  231.         push    bx
  232.         mov    ax, es:[di]
  233.         mov    word ptr StdGrp:fpacc.mantissa[5], ax
  234.         mov    ax, es:2[di]
  235.         mov    bx, ax
  236.         shl    ax, 1
  237.         mov    al, ah
  238.         mov    ah, 0
  239.         add    ax, 32767-127        ;Adjust exponent bias.
  240.         mov    word ptr StdGrp:fpacc.exponent, ax
  241.         mov    StdGrp:fpacc.sign, bh    ;Save sign away.
  242.         mov    al, es:2[di]
  243.         and    al, 7fh            ;Strip out L.O. exp bit.
  244.         or    al, 80h            ;Add in implied bit.
  245.         mov    byte ptr StdGrp:fpacc.mantissa[7], al ;Save H.O. mant byte.
  246.         xor    ax, ax
  247.         mov    word ptr StdGrp:fpacc.mantissa, ax
  248.         mov    word ptr StdGrp:fpacc.mantissa[2], ax
  249.         mov    byte ptr StdGrp:fpacc.mantissa[4], al
  250.         pop    bx
  251.         pop    ax
  252.         ret
  253. sl_LSFPA    endp
  254. ;
  255. ;
  256. ;
  257. ;
  258. ; sl_SSFPA-    Stores FPACC into the single precision variable pointed at by
  259. ;        ES:DI.  Performs appropriate rounding.  Returns carry clear
  260. ;        if the operation is successful, returns carry set if FPACC
  261. ;        cannot fit into a single precision variable.
  262. ;
  263.         public    sl_SSFPA
  264. sl_SSFPA    proc    far
  265.         assume    ds:stdgrp
  266.         push    ds
  267.         push    ax
  268.         push    bx
  269.         mov    ax, StdGrp
  270.         mov    ds, ax
  271.         push    fpacc.Exponent
  272.         push    fpacc.Mantissa       ;Save the stuff we tweak
  273.         push    fpacc.Mantissa[2]    ; so that this operation
  274.         push    fpacc.Mantissa[4]    ; will be non-destructive.
  275.         push    fpacc.Mantissa[6]
  276. ;
  277. ; First, round FPACC:
  278. ;
  279.         add    fpacc.Mantissa [4], 80h
  280.         adc    fpacc.Mantissa [6], 0
  281.         jnc    StoreAway
  282.         rcl    fpacc.Mantissa [6], 1
  283.         rcl    fpacc.Mantissa [4], 1
  284.         inc    fpacc.Exponent
  285.         jz    BadSSFPA        ;If exp overflows.
  286. ;
  287. ; Store the value away:
  288. ;
  289. StoreAway:    mov    ax, fpacc.Exponent
  290.         sub    ax, 32767-127        ;Convert to bias 127
  291.         cmp    ah, 0
  292.         jne    BadSSFPA
  293.         mov    bl, fpacc.Sign
  294.         shl    bl, 1            ;Merge in the sign bit.
  295.         rcr    al, 1
  296.         mov    es:[di] + 3, al        ;Save away exponent/sign
  297.         pushf                ;Save bit shifted out.
  298.         mov    ax, fpacc.Mantissa [6]
  299.         shl    ax, 1            ;Get rid of implied bit and
  300.         popf                ; shift in the L.O. exponent
  301.         rcr    ax, 1            ; bit.
  302.         mov    es:[di] + 1, ax
  303.         mov    al, byte ptr fpacc.Mantissa [5]
  304.         mov    es:[di], al
  305.         clc
  306.         jmp    SSFPADone
  307. ;
  308. BadSSFPA:    stc
  309. SSFPADone:    pop    fpacc.Mantissa[6]
  310.         pop    fpacc.Mantissa[4]
  311.         pop    fpacc.Mantissa[2]
  312.         pop    fpacc.Mantissa
  313.         pop    fpacc.Exponent
  314.         pop    bx
  315.         pop    ax
  316.         pop    ds
  317.         ret
  318.         assume    ds:nothing
  319. sl_SSFPA    endp
  320. ;
  321. ;
  322. ; sl_LDFPA-    Loads the double precision (64-bit) IEEE format number pointed
  323. ;        at by ES:DI into FPACC.
  324. ;
  325.         public    sl_LDFPA
  326. sl_LDFPA    proc    far
  327.         push    ax
  328.         push    bx
  329.         push    cx
  330.         mov    ax, es:6[di]
  331.         mov    StdGrp:fpacc.sign, ah    ;Save sign bit.
  332.         mov    cl, 4
  333.         shr    ax, cl            ;Align exponent field.
  334.         and    ah, 111b        ;Strip the sign bit.
  335.         add    ax, 32767-1023        ;Adjust bias
  336.         mov    StdGrp:fpacc.exponent, ax
  337. ;
  338. ; Get the mantissa bits and left justify them in the FPACC.
  339. ;
  340.         mov    ax, es:5[di]
  341.         and    ax, 0fffh        ;Strip exponent bits.
  342.         or    ah, 10h            ;Add in implied bit.
  343.         mov    cl, 3
  344.         shl    ax, cl
  345.         mov    bx, es:3[di]
  346.         rol    bx, cl
  347.         mov    ch, bl
  348.         and    ch, 7
  349.         or    al, ch
  350.         mov    StdGrp:fpacc.mantissa[6], ax
  351. ;
  352.         and    bl, 0f8h
  353.         mov    ax, es:1[di]
  354.         rol    ax, cl
  355.         mov    ch, al
  356.         and    ch, 7
  357.         or    bl, ch
  358.         mov    StdGrp:fpacc.mantissa[4], bx
  359. ;
  360.         and    al, 0f8h
  361.         mov    bh, es:[di]
  362.         rol    bh, cl
  363.         mov    ch, bh
  364.         and    ch, 7
  365.         or    al, ch
  366.         mov    StdGrp:fpacc.mantissa[2], ax
  367.         and    bh, 0f8h
  368.         mov    bl, 0
  369.         mov    StdGrp:fpacc.Mantissa[0], bx
  370. ;
  371.         pop    cx
  372.         pop    bx
  373.         pop    ax
  374.         ret
  375. sl_LDFPA    endp
  376. ;
  377. ;
  378. ;
  379. ;
  380. ; sl_SDFPA-    Stores FPACC into the double precision variable pointed
  381. ;        at by ES:DI.
  382. ;
  383.         public    sl_sdfpa
  384. sl_SDFPA    proc    far
  385.         assume    ds:stdgrp
  386.         push    ds
  387.         push    ax
  388.         push    bx
  389.         push    cx
  390.         push    dx
  391.         push    di
  392. ;
  393.         mov    bx, StdGrp
  394.         mov    ds, bx
  395. ;
  396.         push    fpacc.Mantissa [0]
  397.         push    fpacc.Mantissa [2]
  398.         push    fpacc.Mantissa [4]
  399.         push    fpacc.Mantissa [6]
  400.         push    fpacc.Exponent
  401. ;
  402. ; First, round this guy to 52 bits:
  403. ;
  404.         add    byte ptr fpacc.Mantissa [1], 8
  405.         jnc    SkipRndUp
  406.         inc    fpacc.Mantissa [2]
  407.         jnz    SkipRndUp
  408.         inc    fpacc.Mantissa [4]
  409.         jnz    SkipRndUp
  410.         inc    fpacc.Mantissa [6]
  411.         jnz    SkipRndUp
  412. ;
  413. ; Whoops!  Got an overflow, fix that here:
  414. ;
  415.         stc
  416.         rcr    fpacc.Mantissa [6], 1
  417.         rcr    fpacc.Mantissa [4], 1
  418.         rcr    fpacc.Mantissa [2], 1
  419.         rcr    byte ptr fpacc.Mantissa [1], 1
  420.         inc    fpacc.Exponent
  421.         jz    BadSDFPA        ;In case exp was really big.
  422. ;
  423. ; Okay, adjust and store the exponent-
  424. ;
  425. SkipRndUp:    mov    ax, fpacc.Exponent
  426.         sub    ax, 32767-1023        ;Adjust bias
  427.         cmp    ax, 2048        ;Make sure the value will still
  428.         jae    BadSDFPA        ; fit in an 8-byte real.
  429.         mov    cl, 5
  430.         shl    ax, cl            ;Move exponent into place.
  431.         mov    bl, fpacc.Sign
  432.         shl    bl, 1
  433.         rcr    ax, 1            ;Merge in sign bit.
  434. ;
  435. ; Merge in the upper four bits of the Mantissa (don't forget that the H.O.
  436. ; Mantissa bit is lost due to the implied one bit).
  437. ;
  438.         mov    bl, byte ptr fpacc.Mantissa [7]
  439.         shr    bl, 1
  440.         shr    bl, 1
  441.         shr    bl, 1
  442.         and    bl, 0fh            ;Strip away H.O. mant bit.
  443.         or    al, bl
  444.         mov    es:[di]+6, ax        ;Store away H.O. word.
  445. ;
  446. ; Okay, now adjust and store away the rest of the mantissa:
  447. ;
  448.         mov    ax, fpacc.Mantissa [0]
  449.         mov    bx, fpacc.Mantissa [2]
  450.         mov    cx, fpacc.Mantissa [4]
  451.         mov    dx, fpacc.Mantissa [6]
  452. ;
  453. ; Shift the bits to their appropriate places (to the left five bits):
  454. ;
  455.         shl    ax, 1
  456.         rcl    bx, 1
  457.         rcl    cx, 1
  458.         rcl    dx, 1
  459. ;
  460.         shl    ax, 1
  461.         rcl    bx, 1
  462.         rcl    cx, 1
  463.         rcl    dx, 1
  464. ;
  465.         shl    ax, 1
  466.         rcl    bx, 1
  467.         rcl    cx, 1
  468.         rcl    dx, 1
  469. ;
  470.         shl    ax, 1
  471.         rcl    bx, 1
  472.         rcl    cx, 1
  473.         rcl    dx, 1
  474. ;
  475.         shl    ax, 1
  476.         rcl    bx, 1
  477.         rcl    cx, 1
  478.         rcl    dx, 1
  479. ;
  480. ; Store away the results:
  481. ;
  482.         mov    es:[di], bx
  483.         mov    es:[di] + 2, cx
  484.         mov    es: [di] + 4, dx
  485. ;
  486. ; Okay, we're done.  Return carry clear to denote success.
  487. ;
  488.         clc
  489.         jmp    short QuitSDFPA
  490. ;
  491. BadSDFPA:    stc                ;If an error occurred.
  492. QuitSDFPA:    pop    fpacc.Exponent
  493.         pop    fpacc.Mantissa [6]
  494.         pop    fpacc.Mantissa [4]
  495.         pop    fpacc.Mantissa [2]
  496.         pop    fpacc.Mantissa [0]
  497.         pop    di
  498.         pop    dx
  499.         pop    cx
  500.         pop    bx
  501.         pop    ax
  502.         pop    ds
  503.         ret
  504. ;
  505.         assume    ds:nothing
  506. sl_SDFPA    endp
  507. ;
  508. ;
  509. ;
  510. ;
  511. ; sl_LEFPA-    Loads an extended precision (80-bit) IEEE format number
  512. ;        into the floating point accumulator.  ES:DI points at the
  513. ;        number to load into FPACC.
  514. ;
  515.         public    sl_LEFPA
  516. sl_LEFPA    proc    far
  517.         push    ax
  518.         mov    ax, es:8[di]
  519.         mov    StdGrp:fpacc.Sign, ah
  520.         and     ah, 7fh
  521.         add    ax, 4000h
  522.         mov    StdGrp:fpacc.Exponent, ax
  523.         mov    ax, es:[di]
  524.         mov    StdGrp:fpacc.Mantissa, ax
  525.         mov    ax, es:2[di]
  526.         mov    StdGrp:fpacc.Mantissa[2], ax
  527.         mov    ax, es:4[di]
  528.         mov    StdGrp:fpacc.Mantissa[4], ax
  529.         mov    ax, es:6[di]
  530.         mov    StdGrp:fpacc.Mantissa[6], ax
  531.         pop    ax
  532.         ret
  533. sl_LEFPA    endp
  534. ;
  535. ;
  536. ; sl_LEFPAL-    Loads an extended precision (80-bit) IEEE format number
  537. ;        into the floating point accumulator.  The number to load
  538. ;        into FPACC follows the call in the code stream.
  539. ;
  540.         public    sl_LEFPAL
  541. sl_LEFPAL    proc    far
  542.         push    bp
  543.         mov    bp, sp
  544.         push    es
  545.         push    di
  546.         push    ax
  547.         les    di, 2[bp]
  548. ;
  549.         mov    ax, es:8[di]
  550.         mov    StdGrp:fpacc.Sign, ah
  551.         and     ah, 7fh
  552.         add    ax, 4000h
  553.         mov    StdGrp:fpacc.Exponent, ax
  554.         mov    ax, es:[di]
  555.         mov    StdGrp:fpacc.Mantissa, ax
  556.         mov    ax, es:2[di]
  557.         mov    StdGrp:fpacc.Mantissa[2], ax
  558.         mov    ax, es:4[di]
  559.         mov    StdGrp:fpacc.Mantissa[4], ax
  560.         mov    ax, es:6[di]
  561.         mov    StdGrp:fpacc.Mantissa[6], ax
  562. ;
  563. ; Adjust the return address to point past the floating point number we
  564. ; just loaded.
  565. ;
  566.         add    word ptr 2[bp], 10
  567. ;
  568.         pop    ax
  569.         pop    di
  570.         pop    es
  571.         pop    bp
  572.         ret
  573. sl_LEFPAL    endp
  574. ;
  575. ;
  576. ; sl_SEFPA-    Stores FPACC into in the extended precision variable
  577. ;        pointed at by ES:DI.
  578. ;
  579. sl_SEFPA    proc    far
  580.         assume    ds:stdgrp
  581.         push    ds
  582.         push    ax
  583.         mov    ax, StdGrp
  584.         mov    ds, ax
  585.         push    fpacc.Mantissa [0]
  586.         push    fpacc.Mantissa [2]
  587.         push    fpacc.Mantissa [4]
  588.         push    fpacc.Mantissa [6]
  589.         push    fpacc.Exponent
  590. ;
  591.         mov    ax, fpacc.Exponent
  592.         sub    ax, 4000h
  593.         cmp    ax, 8000h
  594.         jae    BadSEFPA
  595.         test    fpacc.Sign, 80h
  596.         jz    StoreSEFPA
  597.         or    ah, 80h
  598. StoreSEFPA:    mov    es:[di]+8, ax
  599.         mov    ax, fpacc.Mantissa [0]
  600.         mov    es:[di], ax
  601.         mov    ax, fpacc.Mantissa [2]
  602.         mov    es:[di] + 2, ax
  603.         mov    ax, fpacc.Mantissa [4]
  604.         mov    es:[di] + 4, ax
  605.         mov    ax, fpacc.Mantissa [6]
  606.         mov    es:[di] + 6, ax
  607.         clc
  608.         jmp    SEFPADone
  609. ;
  610. BadSEFPA:    stc
  611. SEFPADone:    pop    fpacc.Exponent
  612.         pop    fpacc.Mantissa[6]
  613.         pop    fpacc.Mantissa[4]
  614.         pop    fpacc.Mantissa[2]
  615.         pop    fpacc.Mantissa[0]
  616.         pop    ax
  617.         pop    ds
  618.         ret
  619.         assume    ds:nothing
  620. sl_SEFPA        endp
  621. ;
  622. ;
  623. ;
  624. ; sl_LSFPO-     Loads a single precision (32-bit) IEEE format number into
  625. ;        the floating point operand.  ES:DI points at the # to
  626. ;        load into FPOP.
  627. ;
  628.         public    sl_LSFPO
  629. sl_LSFPO    proc    far
  630.         push    ax
  631.         push    bx
  632.         mov    ax, es:[di]
  633.         mov    word ptr StdGrp:fpop.mantissa[5], ax
  634.         mov    ax, es:2[di]
  635.         mov    bx, ax
  636.         shl    ax, 1
  637.         mov    al, ah
  638.         mov    ah, 0
  639.         add    ax, 32767-127        ;Adjust exponent bias.
  640.         mov    word ptr StdGrp:fpop.exponent, ax
  641.         mov    StdGrp:fpop.sign, bh    ;Save sign away.
  642.         mov    al, ds:2[di]
  643.         and    al, 7fh            ;Strip out L.O. exp bit.
  644.         or    al, 80h            ;Add in implied bit.
  645.         mov    byte ptr StdGrp:fpop.mantissa[7], al
  646.         xor    ax, ax
  647.         mov    word ptr StdGrp:fpop.mantissa, ax
  648.         mov    word ptr StdGrp:fpop.mantissa[2], ax
  649.         mov    byte ptr StdGrp:fpop.mantissa[4], al
  650.         pop    bx
  651.         pop    ax
  652.         ret
  653. sl_LSFPO    endp
  654. ;
  655. ;
  656. ;
  657. ;
  658. ;
  659. ; sl_LDFPO-    Loads the double precision (64-bit) IEEE format number pointed
  660. ;        at by ES:DI into FPOP.
  661. ;
  662.         public    sl_LDFPO
  663. sl_LDFPO    proc    far
  664.         push    ax
  665.         push    bx
  666.         push    cx
  667.         mov    ax, es:6[di]
  668.         mov    StdGrp:fpop.sign, ah    ;Save sign bit.
  669.         mov    cl, 4
  670.         shr    ax, cl            ;Align exponent field.
  671.         and    ah, 111b        ;Strip the sign bit.
  672.         add    ax, 32767-1023        ;Adjust bias
  673.         mov    word ptr StdGrp:fpop.exponent, ax
  674. ;
  675. ; Get the mantissa bits and left justify them in the FPOP.
  676. ;
  677.         mov    ax, es:5[di]
  678.         and    ax, 0fffh        ;Strip exponent bits.
  679.         or    ah, 10h            ;Add in implied bit.
  680.         mov    cl, 3
  681.         shl    ax, cl
  682.         mov    bx, es:3[di]
  683.         rol    bx, cl
  684.         mov    ch, bl
  685.         and    ch, 7
  686.         or    al, ch
  687.         mov    word ptr StdGrp:fpop.mantissa[6], ax
  688. ;
  689.         and    bl, 0f8h
  690.         mov    ax, es:1[di]
  691.         rol    ax, cl
  692.         mov    ch, al
  693.         and    ch, 7
  694.         or    bl, ch
  695.         mov    word ptr StdGrp:fpop.mantissa[4], bx
  696. ;
  697.         and    al, 0f8h
  698.         mov    bh, es:[di]
  699.         rol    bh, cl
  700.         mov    ch, bh
  701.         and    ch, 7
  702.         or    al, ch
  703.         mov    word ptr StdGrp:fpop.mantissa[2], ax
  704.         and    bh, 0f8h
  705.         mov    bl, 0
  706.         mov    word ptr StdGrp:fpop.Mantissa[0], bx
  707. ;
  708.         pop    cx
  709.         pop    bx
  710.         pop    ax
  711.         ret
  712. sl_LDFPO    endp
  713. ;
  714. ;
  715. ;
  716. ;
  717. ;
  718. ; sl_LEFPO-    Loads an extended precision (80-bit) IEEE format number
  719. ;        into the floating point operand.  ES:DI points at the
  720. ;        number to load into FPACC.
  721. ;
  722.         public    sl_LEFPO
  723. sl_LEFPO    proc    far
  724.         push    ax
  725.         mov    ax, es:8[di]
  726.         mov    StdGrp:fpop.Sign, ah
  727.         and     ah, 7fh
  728.         add    ax, 4000h
  729.         mov    StdGrp:fpop.Exponent, ax
  730.         mov    ax, es:[di]
  731.         mov    StdGrp:fpop.Mantissa, ax
  732.         mov    ax, es:2[di]
  733.         mov    StdGrp:fpop.Mantissa[2], ax
  734.         mov    ax, es:4[di]
  735.         mov    StdGrp:fpop.Mantissa[4], ax
  736.         mov    ax, es:6[di]
  737.         mov    StdGrp:fpop.Mantissa[6], ax
  738.         pop    ax
  739.         ret
  740. sl_LEFPO    endp
  741. ;
  742. ;
  743. ;
  744. ;
  745. ; sl_LEFPOL-    Loads an extended precision (80-bit) IEEE format number
  746. ;        into the floating point operand.  The number to load
  747. ;        follows the call instruction in the code stream.
  748. ;
  749.         public    sl_LEFPOL
  750. sl_LEFPOL    proc    far
  751.         push    bp
  752.         mov    bp, sp
  753.         push    es
  754.         push    di
  755.         push    ax
  756.         les    di, 2[bp]
  757. ;
  758.         mov    ax, es:8[di]
  759.         mov    StdGrp:fpop.Sign, ah
  760.         and     ah, 7fh
  761.         add    ax, 4000h
  762.         mov    StdGrp:fpop.Exponent, ax
  763.         mov    ax, es:[di]
  764.         mov    StdGrp:fpop.Mantissa, ax
  765.         mov    ax, es:2[di]
  766.         mov    StdGrp:fpop.Mantissa[2], ax
  767.         mov    ax, es:4[di]
  768.         mov    StdGrp:fpop.Mantissa[4], ax
  769.         mov    ax, es:6[di]
  770.         mov    StdGrp:fpop.Mantissa[6], ax
  771. ;
  772.         add    word ptr 2[bp], 10    ;Skip rtn adrs past #.
  773. ;
  774.         pop    ax
  775.         pop    di
  776.         pop    es
  777.         pop    bp
  778.         ret
  779. sl_LEFPOL    endp
  780. ;
  781. ;
  782. ;
  783. ;
  784. ;
  785. ;
  786. ;
  787. ;--------------------------------------------------------------------------
  788. ;         Integer <=> FP Conversions
  789. ;--------------------------------------------------------------------------
  790. ;
  791. ;
  792. ;
  793. ; ITOF-        Converts 16-bit signed value in AX to a floating point value
  794. ;        in FPACC.
  795. ;
  796.         public    sl_itof
  797. sl_itof        proc    far
  798.         assume    ds:stdgrp
  799.         push    ds
  800.         push    ax
  801.         push    cx
  802.         mov    cx, StdGrp
  803.         mov    ds, cx
  804. ;
  805.         mov    cx, 800Fh        ;Magic exponent value (65536).
  806. ;
  807. ; Set the sign of the result:
  808. ;
  809.         mov    fpacc.Sign, 0        ;Assume a positive value.
  810.         or    ax, ax            ;Special case for zero!
  811.         jz    SetFPACC0
  812.         jns    DoUTOF            ;Take care of neg values.
  813.         mov    fpacc.sign, 80h        ;This guy is negative!
  814.         neg    ax            ;Work with abs(AX).
  815.         jmp    DoUTOF
  816. sl_ITOF        endp
  817. ;
  818. ;
  819. ; UTOF-        Like ITOF above except this guy works for unsigned 16-bit
  820. ;        integer values.
  821. ;
  822.         public    sl_utof
  823. sl_UTOF        proc    far
  824.         push    ds
  825.         push    ax
  826.         push    cx
  827. ;
  828. ;
  829.         mov    cx, StdGrp
  830.         mov    ds, cx
  831.         mov    cx, 800Fh        ;Magic exponent value (65536).
  832.         or    ax, ax
  833.         jz    SetFPACC0
  834.         mov    fpacc.Sign, 0
  835. ;
  836. sl_UTOF        endp
  837. ;
  838. ;
  839. ; Okay, convert the number to a floating point value:
  840. ; Remember, we need to end up with a normalized number (one where the H.O.
  841. ; bit of the mantissa contains a one).  The largest possible value (65535 or
  842. ; 0FFFFh) is equal to 800E FFFF 0000 0000 0000.  All other values have an
  843. ; exponent less than or equal to 800Eh.  If the H.O. bit of the value is
  844. ; not one, we must shift it to the left and dec the exp by 1.  E.g., if AX
  845. ; contains 1, then we will need to shift it 15 times to normalize the value,
  846. ; decrementing the exponent each time produces 7fffh which is the proper
  847. ; exponent for "1".
  848. ;
  849. ; Note: this is not a proc!  Making it a proc makes it incompatible with
  850. ; one or more different assemblers (TASM, OPTASM, MASM6).
  851. ; Besides, this has to be a near label with a far return!
  852. ;
  853. DoUTOF:
  854. UTOFWhlPos:    dec    cx
  855.         shl    ax, 1
  856.         jnc    UTOFWhlPos
  857.         rcr    ax, 1            ;Put bit back.
  858.         mov    fpacc.Exponent, cx    ;Save exponent value.
  859.         mov    fpacc.Mantissa [6], ax    ;Save Mantissa value.
  860.         xor    ax, ax
  861.         mov    fpacc.Mantissa [4], ax    ;Zero out the rest of the
  862.         mov    fpacc.Mantissa [2], ax    ; mantissa.
  863.         mov    fpacc.Mantissa [0], ax
  864.         jmp     UTOFDone
  865. ;
  866. ; Special case for zero, must zero all bytes in FPACC.  Note that AX already
  867. ; contains zero.
  868. ;
  869. SetFPACC0:    mov    fpacc.Exponent, ax
  870.         mov    fpacc.Mantissa [6], ax
  871.         mov    fpacc.Mantissa [4], ax
  872.         mov    fpacc.Mantissa [2], ax
  873.         mov    fpacc.Mantissa [0], ax
  874.         mov    fpacc.Sign, al
  875. ;
  876. UTOFDone:    pop    cx
  877.         pop    ax
  878.         pop    ds
  879.         retf
  880. ;
  881. ;
  882. ;
  883. ;
  884. ;
  885. ;
  886. ; LTOF-        Converts 32-bit signed value in DX:AX to a floating point
  887. ;        value in FPACC.
  888. ;
  889.         public    sl_ltof
  890. sl_ltof        proc    far
  891.         assume    ds:stdgrp
  892.         push    ds
  893.         push    ax
  894.         push    cx
  895.         push    dx
  896.         mov    cx, StdGrp
  897.         mov    ds, cx
  898. ;
  899. ; Set the sign of the result:
  900. ;
  901.         mov    fpacc.Sign, 0        ;Assumed a positive value.
  902.         mov    cx, dx
  903.         or    cx, ax
  904.         jz    SetUL0
  905.         or    dx, dx            ;Special case for zero!
  906.         jns    DoULTOF            ;Take care of neg values.
  907.         mov    fpacc.sign, 80h        ;This guy is negative!
  908.         neg    dx            ;Do a 32-bit NEG operation
  909.         neg    ax            ; (yes, this really does
  910.         sbb    dx, 0            ;  work!).
  911.         jmp    DoULTOF
  912. sl_LTOF        endp
  913. ;
  914. ;
  915. ; ULTOF-    Like LTOF above except this guy works for unsigned 32-bit
  916. ;        integer values.
  917. ;
  918.         public    sl_ultof
  919. sl_ULTOF    proc    far
  920.         push    ds
  921.         push    ax
  922.         push    cx
  923.         push    dx
  924. ;
  925.         mov    cx, StdGrp
  926.         mov    ds, cx
  927. ;
  928.         mov    cx, dx
  929.         or    cx, ax
  930.         jz    SetUL0
  931.         mov    fpacc.Sign, 0
  932. ;
  933. sl_ULTOF        endp
  934. ;
  935. ;
  936. ;
  937. DoULTOF:
  938.         mov    cx, 801Fh        ;Magic exponent value (65536).
  939. ULTOFWhlPos:    dec    cx
  940.         shl    ax, 1
  941.         rcl    dx, 1
  942.         jnc    ULTOFWhlPos
  943.         rcr    dx, 1            ;Put bit back.
  944.         rcr    ax, 1
  945.         mov    fpacc.Exponent, cx    ;Save exponent value.
  946.         mov    fpacc.Mantissa [6], dx    ;Save Mantissa value.
  947.         mov    fpacc.Mantissa [4], ax
  948.         xor    ax, ax            ;Zero out the rest of the
  949.         mov    fpacc.Mantissa [2], ax    ; mantissa.
  950.         mov    fpacc.Mantissa [0], ax
  951.         jmp     ULTOFDone
  952. ;
  953. ; Special case for zero, must zero all bytes in FPACC.  Note that AX already
  954. ; contains zero.
  955. ;
  956. SetUL0:        mov    fpacc.Exponent, ax
  957.         mov    fpacc.Mantissa [6], ax
  958.         mov    fpacc.Mantissa [4], ax
  959.         mov    fpacc.Mantissa [2], ax
  960.         mov    fpacc.Mantissa [0], ax
  961.         mov    fpacc.Sign, al
  962. ;
  963. ULTOFDone:    pop    dx
  964.         pop    cx
  965.         pop    ax
  966.         pop    ds
  967.         retf
  968. ;
  969. ;
  970. ;
  971. ;
  972. ; FTOI- Converts the floating point value in FPACC to a signed 16-bit
  973. ;    integer and returns this integer in AX.
  974. ;    Returns carry set if the number is too big to fit into AX.
  975. ;
  976.         public    sl_FTOI
  977. sl_FTOI        proc    far
  978.         assume    ds:stdgrp
  979.         push    ds
  980.         push    cx
  981.         mov    cx, StdGrp
  982.         mov    ds, cx
  983. ;
  984.         mov    cx, fpacc.Exponent
  985.         cmp    cx, 800eh
  986.         jb    FTOIok
  987. ;
  988. ; Handle special case of -32768:
  989. ;
  990.         call    DoFToU
  991.         cmp    ax, 8000h
  992.         je    FtoiOk2
  993.         stc
  994.         jmp    TooBig
  995. ;
  996. FTOIok:        call    DoFTOU
  997. FtoiOk2:    cmp    fpacc.Sign, 0
  998.         jns    FTOIJustRight
  999.         neg    ax
  1000. FTOIJustRight:    clc
  1001. TooBig:        pop    cx
  1002.         pop    ds
  1003.         ret
  1004. sl_FTOI        endp
  1005. ;
  1006. ;
  1007. ;
  1008. ;
  1009. ; FTOU- Like FTOI above, except this guy converts a floating point value
  1010. ;     to an unsigned integer in AX.
  1011. ;    Returns carry set if out of range (including negative numbers).
  1012. ;
  1013.         public    sl_FTOU
  1014. sl_FTOU        proc    far
  1015.         assume    ds:stdgrp
  1016.         push    ds
  1017.         push    cx
  1018.         mov    cx, StdGrp
  1019.         mov    ds, cx
  1020. ;
  1021.         mov    cx, fpacc.Exponent
  1022.         cmp    cx, 800fh
  1023.         jb    FTOUok
  1024. BadU:        stc
  1025.         jmp    UTooBig
  1026. ;
  1027. FTOUok:        call    DoFTOU
  1028.         cmp    fpacc.Sign, 0
  1029.         js    BadU
  1030. ;
  1031. FTOUJustRight:    clc
  1032. UTooBig:    pop    cx
  1033.         pop    ds
  1034.         ret
  1035. sl_FTOU        endp
  1036. ;
  1037. ;
  1038. ; DoFTOU- This code does the actual conversion!
  1039. ;
  1040. DoFTOU        proc    near
  1041.         mov    ax, fpacc.Mantissa [6]
  1042.         cmp    cx, 7fffh
  1043.         jb    SetFTOU0
  1044.         sub    cx, 800eh
  1045.         neg    cx
  1046.         shr    ax, cl
  1047.         ret
  1048. ;
  1049. SetFTOU0:    xor    ax, ax
  1050.         ret
  1051. DoFTOU        endp
  1052. ;
  1053. ;
  1054. ;
  1055. ;
  1056. ;
  1057. ; FTOL- Converts the floating point value in FPACC to a signed 32-bit
  1058. ;    integer and returns this integer in DX:AX.
  1059. ;    Returns carry set if the number is too big to fit into DX:AX.
  1060. ;
  1061.         public    sl_FTOL
  1062. sl_FTOL        proc    far
  1063.         assume    ds:StdGrp
  1064.         push    ds
  1065.         push    cx
  1066.         mov    cx, StdGrp
  1067.         mov    ds, cx
  1068. ;
  1069.         mov    cx, fpacc.Exponent
  1070.         cmp    cx, 801eh
  1071.         jb    FTOLok
  1072.         stc
  1073.         jmp    LTooBig
  1074. ;
  1075. FTOLok:        call    DoFTOUL
  1076.         cmp    fpacc.Sign, 0
  1077.         jns    FTOLJustRight
  1078.         neg    dx            ;32-bit negate operation.
  1079.         neg    ax
  1080.         sbb    dx, 0
  1081. FTOLJustRight:    clc
  1082. LTooBig:    pop    cx
  1083.         pop    ds
  1084.         ret
  1085. sl_FTOL        endp
  1086. ;
  1087. ;
  1088. ;
  1089. ;
  1090. ; FTOUL-Like FTOL above, except this guy converts a floating point value
  1091. ;     to a 32-bit unsigned integer in DX:AX.
  1092. ;    Returns carry set if out of range (including negative numbers).
  1093. ;
  1094.         public    sl_FTOUL
  1095. sl_FTOUL    proc    far
  1096.         assume    ds:StdGrp
  1097.         push    ds
  1098.         push    cx
  1099.         mov    cx, StdGrp
  1100.         mov    ds, cx
  1101. ;
  1102.         mov    cx, fpacc.Exponent
  1103.         cmp    cx, 801fh
  1104.         jb    FTOULok
  1105. BadUL:        stc
  1106.         jmp    ULTooBig
  1107. ;
  1108. FTOULok:    call    DoFTOUL
  1109.         cmp    fpacc.Sign, 0
  1110.         js    BadUL
  1111. ;
  1112.         clc                ;If the # is okay.
  1113. ULTooBig:    pop    cx
  1114.         pop    ds
  1115.         ret
  1116. sl_FTOUL    endp
  1117. ;
  1118. ;
  1119. ; DoFTOUL- This code does the actual conversion!
  1120. ;
  1121. DoFTOUL        proc    near
  1122.         mov    dx, fpacc.Mantissa [6]
  1123.         mov    ax, fpacc.Mantissa [4]
  1124.         cmp    cx, 7fffh
  1125.         jb    SetFTOUL0
  1126.         sub    cx, 801eh
  1127.         neg    cx
  1128.         jcxz    SetFTOULDone
  1129. FTOULLp:    shr    dx, 1
  1130.         rcr    ax, 1
  1131.         loop    FTOULLp
  1132. SetFToULDone:    ret
  1133. ;
  1134. SetFTOUL0:    xor    ax, ax
  1135.         xor    dx, dx
  1136.         ret
  1137. DoFTOUL        endp
  1138. ;
  1139. ;
  1140. ;
  1141. ;
  1142. ;
  1143. ;
  1144. ;
  1145. ;
  1146. ;
  1147. ;
  1148. ;
  1149. ;
  1150. ;
  1151. ;---------------------------------------------------------------------------
  1152. ;        Floating Point Addition & Subtraction
  1153. ;---------------------------------------------------------------------------
  1154. ;
  1155. ;
  1156. ;
  1157. ;
  1158. ; FADD- Adds FOP to FACC
  1159. ; FSUB- Subtracts FOP from FACC
  1160. ;    These routines destroy the value in FPOP!
  1161. ;
  1162.         public    sl_fsub
  1163.         public    sl_fadd
  1164. ;
  1165.         assume    ds:nothing
  1166. sl_fsub        proc    far
  1167.         xor    StdGrp:fpop.sign, 80h
  1168. sl_fsub        endp
  1169. ;
  1170.         assume    ds:StdGrp
  1171. sl_fadd        proc    far
  1172.         push    ds
  1173.         push    ax
  1174.         push    bx
  1175.         push    cx
  1176.         push    dx
  1177.         push    si
  1178. ;
  1179. ; Use the current CS as the data segment to get direct access to
  1180. ; the floating point accumulator and operands.
  1181. ;
  1182.         mov    ax, StdGrp
  1183.         mov    ds, ax
  1184. ;
  1185. ; Adjust the smaller of the two operands so that the exponents of the two
  1186. ; objects are the same:
  1187. ;
  1188.         mov    cx, fpacc.exponent
  1189.         sub    cx, fpop.exponent
  1190.         js    gotoAdjustFPA
  1191.         jnz    AdjustFPOP
  1192.         jmp    Adjusted        ;Only if exponents are equal.
  1193. gotoAdjustFPA:    jmp    AdjustFPACC
  1194. ;
  1195. ; Since the difference of the exponents is negative, the magnitude of FPOP
  1196. ; is smaller than the magnitude of fpacc.  Adjust FPOP here.
  1197. ;
  1198. AdjustFPOP:    cmp    cx, 64            ;If greater than 64, forget
  1199.         jb    short By16LoopTest    ; it.  Sum is equal to FPACC.
  1200.         jmp    Done
  1201. ;
  1202. ; If the difference is greater than 16 bits, adjust FPOP a word at a time.
  1203. ; Note that there may be multiple words adjusted in this fashion.
  1204. ;
  1205. By16Loop:    mov    ax, fpop.mantissa[2]
  1206.         mov    fpop.mantissa[0], ax
  1207.         mov    ax, fpop.mantissa[4]
  1208.         mov    fpop.mantissa[2], ax
  1209.         mov    ax, fpop.mantissa[6]
  1210.         mov    fpop.mantissa[4], ax
  1211.         mov    fpop.mantissa[6], 0
  1212.         sub    cx, 16
  1213. By16LoopTest:    cmp    cx, 16
  1214.         jae    By16Loop
  1215. ;
  1216. ; After adjusting sixteen bits at a time, see if there are at least eight
  1217. ; bits.  Note that this can only occur once, for if you could adjust by
  1218. ; eight bits twice, you could have adjusted by 16 above.
  1219. ;
  1220.         cmp    cx, 8
  1221.         jb    NotBy8
  1222.         mov    ax, fpop.mantissa[1]
  1223.         mov    fpop.mantissa[0], ax
  1224.         mov    ax, fpop.mantissa[3]
  1225.         mov    fpop.mantissa[2], ax
  1226.         mov    ax, fpop.mantissa[5]
  1227.         mov    fpop.mantissa[4], ax
  1228.         mov    al, byte ptr fpop.mantissa [7]
  1229.         mov    byte ptr fpop.mantissa [6], al
  1230.         mov    byte ptr fpop.mantissa[7], 0
  1231.         sub    cx, 8
  1232. ;
  1233. ; Well, now we're down to a bit at a time.
  1234. ;
  1235. NotBy8:        jcxz    AdjFPOPDone
  1236. ;
  1237. ; Load the mantissa into registers to save processing time.
  1238. ;
  1239.         mov    ax, fpop.mantissa[6]
  1240.         mov    bx, fpop.mantissa[4]
  1241.         mov    dx, fpop.mantissa[2]
  1242.         mov    si, fpop.mantissa[0]
  1243. By1Loop:    shr    ax, 1
  1244.         rcr    bx, 1
  1245.         rcr    dx, 1
  1246.         rcr    si, 1
  1247.         loop    By1Loop
  1248.         mov    fpop.mantissa[6], ax    ;Save result back into
  1249.         mov    fpop.mantissa[4], bx    ; fpop.
  1250.         mov    fpop.mantissa[2], dx
  1251.         mov    fpop.mantissa[0], si
  1252. AdjFPOPDone:    jmp     Adjusted
  1253. ;
  1254. ;
  1255. ;
  1256. ; AdjustFPACC- FPACC was smaller than FPOP, so adjust its bits down here.
  1257. ;           This code is pretty much identical to the above, the same
  1258. ;           comments apply.
  1259. ;
  1260. AdjustFPACC:    neg    cx            ;Take ABS(cx)
  1261.         cmp    cx, 64            ;If greater than 64, forget
  1262.         jb    By16LpTest        ; it.
  1263.         jmp    SetFPACC2Zero
  1264. ;
  1265. By16Lp:        mov    ax, fpacc.mantissa[2]
  1266.         mov    fpacc.mantissa[0], ax
  1267.         mov    ax, fpacc.mantissa[4]
  1268.         mov    fpacc.mantissa[2], ax
  1269.         mov    ax, fpacc.mantissa[6]
  1270.         mov    fpacc.mantissa[4], ax
  1271.         mov    fpacc.mantissa[6], 0
  1272.         sub    cx, 16
  1273. By16LpTest:    cmp    cx, 16
  1274.         jae    By16Lp
  1275. ;
  1276.         cmp    cx, 8
  1277.         jb    NotBy8a
  1278.         mov    ax, fpacc.mantissa[1]
  1279.         mov    fpacc.mantissa[0], ax
  1280.         mov    ax, fpacc.mantissa[3]
  1281.         mov    fpacc.mantissa[2], ax
  1282.         mov    ax, fpacc.mantissa[5]
  1283.         mov    fpacc.mantissa[4], ax
  1284.         mov    al, byte ptr fpacc.mantissa [7]
  1285.         mov    byte ptr fpacc.mantissa [6], al
  1286.         mov    byte ptr fpacc.mantissa[7], 0
  1287.         sub    cx, 8
  1288. ;
  1289. NotBy8a:    jcxz    Adjusted
  1290.         mov    ax, fpacc.mantissa[6]
  1291.         mov    bx, fpacc.mantissa[4]
  1292.         mov    dx, fpacc.mantissa[2]
  1293.         mov    si, fpacc.mantissa[0]
  1294. By1Lp:        shr    ax, 1
  1295.         rcr    bx, 1
  1296.         rcr    dx, 1
  1297.         rcr    si, 1
  1298.         loop    By1Lp
  1299.         mov    fpacc.mantissa[6], ax
  1300.         mov    fpacc.mantissa[4], bx
  1301.         mov    fpacc.mantissa[2], dx
  1302.         mov    fpacc.mantissa[0], si
  1303.         mov    ax, fpop.Exponent    ;FPACC assumes the same
  1304.         mov    fpacc.Exponent, ax    ; exponent as FPOP.
  1305. AdjFPACCDone:    jmp     Adjusted
  1306. ;
  1307. ; If FPACC is so much smaller than FPOP that it is insignificant, set
  1308. ; it to zero.
  1309. ;
  1310. SetFPACC2Zero:    xor    ax, ax
  1311.         mov    fpacc.mantissa[0], ax
  1312.         mov    fpacc.mantissa[2], ax
  1313.         mov    fpacc.mantissa[4], ax
  1314.         mov    fpacc.mantissa[6], ax
  1315.         mov    fpacc.exponent, ax
  1316.         mov    fpacc.sign, al
  1317. ;
  1318. ; Now that the mantissas are aligned, let's add (or subtract) them.
  1319. ;
  1320. Adjusted:    mov    al, fpacc.sign
  1321.         xor    al, fpop.sign
  1322.         js    SubEm
  1323. ;
  1324. ; If the signs are the same, simply add the mantissas together here.
  1325. ;
  1326.         mov    ax, fpop.mantissa[0]
  1327.         add    fpacc.mantissa[0], ax
  1328.         mov    ax, fpop.mantissa[2]
  1329.         adc    fpacc.mantissa[2], ax
  1330.         mov    ax, fpop.mantissa[4]
  1331.         adc    fpacc.mantissa[4], ax
  1332.         mov    ax, fpop.mantissa[6]
  1333.         adc    fpacc.mantissa[6], ax
  1334.         jnc    Normalize
  1335. ;
  1336. ; If there was a carry out of the addition (quite possible since most
  1337. ; fp values are normalized) then we need to shove the bit back into
  1338. ; the number.
  1339. ;
  1340.         rcr    fpacc.mantissa[6], 1
  1341.         rcr    fpacc.mantissa[4], 1
  1342.         rcr    fpacc.mantissa[2], 1
  1343.         rcr    fpacc.mantissa[0], 1
  1344.         inc    fpacc.exponent
  1345. ;
  1346. ; If there was a carry out of the bottom, add it back in (this rounds the
  1347. ; result).  No need to worry about a carry out of the H.O. bit this time--
  1348. ; there is no way to add together two numbers to get a carry *and* all
  1349. ; one bits in the result.  Therefore, rounding at this point will not
  1350. ; propagate all the way through.
  1351. ;
  1352.         adc    fpacc.Mantissa [0], 0
  1353.         jnc    Normalize
  1354.         inc    fpacc.Mantissa [2]
  1355.         jnz    Normalize
  1356.         inc    fpacc.Mantissa [4]
  1357.         jnz    Normalize
  1358.         inc    fpacc.Mantissa [6]
  1359.         jmp    Normalize
  1360. ;
  1361. ;
  1362. ;
  1363. ; If the signs are different, we've got to deal with four possibilities:
  1364. ;
  1365. ; 1) fpacc is negative and its magnitude is greater than fpop's.
  1366. ;    Result is negative, fpacc.mant := fpacc.mant - fpop.mant.
  1367. ;
  1368. ; 2) fpacc is positive and its magnitude is greater than fpop's.
  1369. ;    Result is positive, fpacc.mant := fpacc.mant - fpop.mant.
  1370. ;
  1371. ; 3) fpacc is negative and its magnitude is less than fpop's.
  1372. ;    Result is positive, fpacc.mant := fpop.mant - fpacc.mant.
  1373. ;
  1374. ; 4) fpacc is positive and its magnitude is less than fpop's.
  1375. ;    Result is negative, fpacc.mant := fpop.mant - fpacc.mant.
  1376. ;
  1377. SubEm:        mov    ax, fpacc.mantissa[0]
  1378.         mov    bx, fpacc.mantissa[2]
  1379.         mov    dx, fpacc.mantissa[4]
  1380.         mov    si, fpacc.mantissa[6]
  1381.         sub    ax, fpop.mantissa[0]
  1382.         sbb    bx, fpop.mantissa[2]
  1383.         sbb    dx, fpop.mantissa[4]
  1384.         sbb     si, fpop.mantissa[6]
  1385.         jnc    StoreFPACC
  1386. ;
  1387. ; Whoops!  FPOP > FPACC, fix that down here.
  1388. ;
  1389.         not    ax
  1390.         not    bx
  1391.         not    dx
  1392.         not    si
  1393.         inc     ax
  1394.         jnz    StoreFPACCSign
  1395.         inc    bx
  1396.         jnz    StoreFPAccSign
  1397.         inc    dx
  1398.         jnz    StoreFPAccSign
  1399.         inc    si
  1400. ;
  1401. StoreFPAccSign:    xor    fpacc.sign, 80h            ;Flip sign if case 3/4.
  1402. ;
  1403. StoreFPAcc:    mov    fpacc.mantissa[0], ax
  1404.         mov    fpacc.mantissa[2], bx
  1405.         mov    fpacc.mantissa[4], dx
  1406.         mov    fpacc.mantissa[6], si
  1407. ;
  1408. ;
  1409. ; Normalize the result down here.  Start by shifting 16 bits at a time,
  1410. ; then eight bits, then one bit at a time.
  1411. ;
  1412. Normalize:    mov    ax, fpacc.mantissa[6]
  1413.         or    ax, ax                  ;See if zero (which means we
  1414.         jnz    Try8Bits        ; can shift 16 bits).
  1415.         mov    ax, fpacc.mantissa[4]
  1416.         mov    fpacc.mantissa[6], ax
  1417.         mov    ax, fpacc.mantissa[2]
  1418.         mov    fpacc.mantissa[4], ax
  1419.         mov    ax, fpacc.mantissa[0]
  1420.         mov    fpacc.mantissa[2], ax
  1421.         mov    fpacc.mantissa[0],0
  1422.         sub    fpacc.exponent, 16
  1423.         jmp    Normalize
  1424. ;
  1425. ; Okay, see if we can normalize eight bits at a shot.
  1426. ;
  1427. Try8Bits:    mov    al, byte ptr fpacc.mantissa[7]
  1428.         cmp    al, 0
  1429.         jnz    Try1Bit
  1430.         mov    ax, fpacc.mantissa[5]
  1431.         mov    fpacc.mantissa[6], ax
  1432.         mov    ax, fpacc.mantissa[3]
  1433.         mov    fpacc.mantissa[4], ax
  1434.         mov    ax, fpacc.mantissa[1]
  1435.         mov    fpacc.mantissa[3], ax
  1436.         mov    al, byte ptr fpacc.mantissa[0]
  1437.         mov    byte ptr fpacc.mantissa[1], al
  1438.         mov    byte ptr fpacc.mantissa[0], 0
  1439.         sub    fpacc.exponent, 8
  1440. ;
  1441. Try1Bit:    mov    ax, fpacc.mantissa[6]
  1442.         test    ah, 80h
  1443.         jnz    Done
  1444.         mov    bx, fpacc.mantissa[4]
  1445.         mov    dx, fpacc.mantissa[2]
  1446.         mov    si, fpacc.mantissa[0]
  1447. OneBitLp:    dec    fpacc.exponent
  1448.         shl    si, 1
  1449.         rcl    dx, 1
  1450.         rcl    bx, 1
  1451.         rcl    ax, 1
  1452.         or    ax, ax            ;See if bit 15 is set.
  1453.         jns    OneBitLp
  1454.         mov    fpacc.mantissa[6], ax
  1455.         mov    fpacc.mantissa[4], bx
  1456.         mov    fpacc.mantissa[2], dx
  1457.         mov    fpacc.mantissa[0], si
  1458. ;
  1459. Done:        pop    si
  1460.         pop    dx
  1461.         pop    cx
  1462.         pop    bx
  1463.         pop    ax
  1464.         pop    ds
  1465.         ret
  1466. sl_fadd        endp
  1467. ;
  1468. ;
  1469. ;
  1470. ;
  1471. ;
  1472. ;
  1473. ;
  1474. ;
  1475. ;
  1476. ;
  1477. ;---------------------------------------------------------------------------
  1478. ; Floating point comparison.
  1479. ;---------------------------------------------------------------------------
  1480. ;
  1481. ;
  1482. ; FCMP
  1483. ; Compares value in FPACC to value in FPOP.
  1484. ; Returns -1 in AX if FPACC is less than FPOP,
  1485. ; Returns 0  in AX if FPACC is equal to FPOP,
  1486. ; Returns 1  in AX if FPACC is greater than FPOP.
  1487. ;
  1488. ; Also returns this status in the flags (by comparing AX against zero
  1489. ; before returning) so you can use JE, JNE, JG, JGE, JL, or JLE after this
  1490. ; routine to test the comparison.
  1491. ;
  1492.         public    sl_fcmp
  1493. sl_fcmp        proc    far
  1494.         assume    ds:StdGrp
  1495.         push    ds
  1496.         mov    ax, StdGrp
  1497.         mov    ds, ax
  1498. ;
  1499. ; First compare the signs of the mantissas.  If they are different, the
  1500. ; negative one is smaller.
  1501. ;
  1502.         mov    al, byte ptr FPACC+10    ;Get sign bit
  1503.         xor    al, byte ptr FPOP+10    ;See if the signs are different
  1504.         jns    SameSign
  1505. ;
  1506. ; If the signs are different, then the sign of FPACC determines the result
  1507. ;
  1508.         test    byte ptr FPACC+10, 80h
  1509.         jnz    IsLT
  1510.         jmp    short IsGT
  1511. ;
  1512. ; Down here the signs are the same.  First order of business is to compare
  1513. ; the exponents.  The one with the larger exponent wins.  If the exponents
  1514. ; are equal, then we need to compare the mantissas.  If the mantissas are
  1515. ; the same then the two numbers are equal.  If the mantissas are different
  1516. ; then the larger one wins.  Note that this discussion is for positive values
  1517. ; only, if the numbers are negative, then we must reverse the win/loss value
  1518. ; (win=GT).
  1519. ;
  1520. SameSign:    mov    ax, FPACC.exponent    ;One thing cool about bias-
  1521.         cmp    ax, FPOP.exponent    ; 1023 exponents is that we
  1522.         ja    MayBeGT            ; can use an unsigned compare
  1523.         jb    MayBeLT
  1524. ;
  1525. ; If the exponents are equal, we need to start comparing the mantissas.
  1526. ; This straight line code turns out to be about the fastest way to do it.
  1527. ;
  1528.         mov    ax, word ptr FPACC.mantissa+6
  1529.         cmp    ax, word ptr FPOP.mantissa+6
  1530.         ja    MayBeGT
  1531.         jb    MayBeLT
  1532.         mov    ax, word ptr FPACC.mantissa+4
  1533.         cmp    ax, word ptr FPOP.mantissa+4
  1534.         ja    MayBeGT
  1535.         jb    MayBeLT
  1536.         mov    ax, word ptr FPACC.mantissa+2
  1537.         cmp    ax, word ptr FPOP.mantissa+2
  1538.         ja    MayBeGT
  1539.         jb    MayBeLT
  1540.         mov    ax, word ptr FPACC.mantissa
  1541.         cmp    ax, word ptr FPOP.mantissa
  1542.         ja    MayBeGT
  1543.         je    IsEq            ;They're equal at this point.
  1544. ;
  1545. ; MayBeLT- Looks like less than so far, but we need to check the sign of the
  1546. ; numbers, if they are negative then FPACC is really GT FPOP.  Remember, the
  1547. ; sign is not part of the mantissa!
  1548. ;
  1549. MayBeLT:    test    FPACC.sign, 80h
  1550.         js    IsGT
  1551. ;
  1552. IsLT:        mov    ax, -1
  1553.         jmp    short cmpRtn
  1554. ;
  1555. ; Same story here for MayBeGT
  1556. ;
  1557. MayBeGT:    test    FPACC.sign, 80h
  1558.         js    IsLT
  1559. ;
  1560. IsGT:        mov    ax, 1
  1561.         jmp    short cmpRtn
  1562. ;
  1563. IsEq:        xor    ax, ax
  1564. cmpRtn:        pop    ds
  1565.         cmp    ax, 0            ;Set the flags as appropriate
  1566.         ret
  1567. sl_fcmp        endp
  1568.         assume    ds:nothing
  1569. ;
  1570. ;
  1571. ;
  1572. ;
  1573. ;
  1574. ;
  1575. ;
  1576. ;
  1577. ;
  1578. ;
  1579. ;
  1580. ;
  1581. ;
  1582. ;---------------------------------------------------------------------------
  1583. ;        Floating Point Multiplication
  1584. ;---------------------------------------------------------------------------
  1585. ;
  1586. ;
  1587. ;
  1588. ;
  1589. ; sl_fmul- Multiplies facc by fop and leaves the result in facc.
  1590. ;
  1591.         public    sl_fmul
  1592. sl_fmul        proc    far
  1593.         assume    ds:StdGrp
  1594.         push    ds
  1595.         push    ax
  1596.         push    bx
  1597.         push    cx
  1598.         push    dx
  1599.         push    si
  1600.         push    di
  1601. ;
  1602.         mov    ax, StdGrp
  1603.         mov    ds, ax
  1604. ;
  1605. ; See if either operand is zero:
  1606. ;
  1607.         mov    ax, fpacc.mantissa[0]    ;No need to check exponent!
  1608.         or    ax, fpacc.mantissa[2]
  1609.         or    ax, fpacc.mantissa[4]
  1610.         or    ax, fpacc.mantissa[6]
  1611.         jz    ProdIsZero
  1612. ;
  1613.         mov    ax, fpop.mantissa[0]
  1614.         or    ax, fpop.mantissa[2]
  1615.         or    ax, fpop.mantissa[4]
  1616.         or    ax, fpop.mantissa[6]
  1617.         jnz    ProdNotZero
  1618. ;
  1619. ProdIsZero:    xor    ax, ax            ;Need this!
  1620.         mov    fpacc.sign, al
  1621.         mov    fpacc.exponent, ax
  1622.         mov    fpacc.mantissa[0], ax
  1623.         mov    fpacc.mantissa[2], ax
  1624.         mov    fpacc.mantissa[4], ax
  1625.         mov    fpacc.mantissa[6], ax
  1626.         jmp    FMulDone
  1627. ;
  1628. ; If both operands are non-zero, compute the true product down here.
  1629. ;
  1630. ProdNotZero:    mov    al, fpop.sign        ;Compute the new sign.
  1631.         xor    fpacc.sign, al
  1632. ;
  1633. ; Eliminate bias in the exponents, add them, and check for 16-bit signed
  1634. ; overflow.
  1635. ;
  1636.         mov    ax, fpop.exponent    ;Compute new exponent.
  1637.         sub    ax, 7fffh        ;Subtract BIAS and adjust
  1638.         mov    bx, fpacc.Exponent
  1639.         sub    bx, 7fffh
  1640.         add    ax, bx            ; for fractional multiply.
  1641.         jno    GoodExponent
  1642. ;
  1643. ; If the exponent overflowed, set up the overflow value here.
  1644. ;
  1645.         mov    ax, 0ffffh
  1646.         mov    fpacc.exponent, ax    ;Largest exponent value
  1647.         mov    fpacc.mantissa[0], ax    ; and largest mantissa, too!
  1648.         mov    fpacc.mantissa[2], ax
  1649.         mov    fpacc.mantissa[4], ax
  1650.         mov    fpacc.mantissa[6], ax
  1651.         jmp    FMulDone
  1652. ;
  1653. GoodExponent:    add    ax, 8000h        ;Add the bias back in (note
  1654.         mov    fpacc.Exponent, ax    ; Mul64 below causes shift
  1655. ;                        ; to force bias of 7fffh.
  1656. ; Okay, compute the product of the mantissas down here.
  1657. ;
  1658.         call    Mul64
  1659. ;
  1660. ; Normalize the product.  Note: we know the product is non-zero because
  1661. ; both of the original operands were non-zero.
  1662. ;
  1663.         mov    cx, fpacc.exponent
  1664.         jmp    short TestNrmMul
  1665. NrmMul1:    sub    cx, 16
  1666.         mov    ax, fprod[12]
  1667.         mov    fprod[14], ax
  1668.         mov    ax, fprod[10]
  1669.         mov    fprod[12], ax
  1670.         mov    ax, fprod[8]
  1671.         mov    fprod[10], ax
  1672.         mov    ax, fprod[6]
  1673.         mov    fprod[8], ax
  1674.         mov    ax, fprod[4]
  1675.         mov    fprod[6], ax
  1676.         mov    ax, fprod[2]
  1677.         mov    fprod[4], ax
  1678.         mov    ax, fprod[0]
  1679.         mov    fprod[2], ax
  1680.         mov    fprod[0], 0
  1681. TestNrmMul:     cmp    cx, 16
  1682.         jb    DoNrmMul8
  1683.         mov      ax, fprod[14]
  1684.         or    ax, ax
  1685.         jz    NrmMul1
  1686. ;
  1687. ; See if we can shift the product a whole byte
  1688. ;
  1689. DoNrmMul8:    cmp    ah, 0            ;Contains fprod[15] from above.
  1690.         jnz    DoOneBits
  1691.         cmp    cx, 8
  1692.         jb    DoOneBits
  1693.         mov    ax, fprod[13]
  1694.         mov    fprod[14], ax
  1695.         mov    ax, fprod[11]
  1696.         mov    fprod[12], ax
  1697.         mov    ax, fprod[9]
  1698.         mov    fprod[10], ax
  1699.         mov    ax, fprod[7]
  1700.         mov    fprod[8], ax
  1701.         mov    ax, fprod[5]
  1702.         mov    fprod[6], ax
  1703.         mov    ax, fprod[3]
  1704.         mov    fprod[4], ax
  1705.         mov    ax, fprod[1]
  1706.         mov    fprod[2], ax
  1707.         mov    al, byte ptr fprod[0]
  1708.         mov    byte ptr fprod[1], al
  1709.         mov    byte ptr fprod[0], 0
  1710.         sub    cx, 8
  1711. ;
  1712. DoOneBits:    mov    ax, fprod[14]
  1713.         mov    bx, fprod[12]
  1714.         mov    dx, fprod[10]
  1715.         mov    si, fprod[8]
  1716.         mov    di, fprod[6]
  1717.         jmp    short TestOneBits
  1718. ;
  1719. OneBitLoop:    shl    fprod[0], 1
  1720.         rcl    fprod[2], 1
  1721.         rcl    fprod[4], 1
  1722.         rcl    di, 1
  1723.         rcl    si, 1
  1724.         rcl    dx, 1
  1725.         rcl    bx, 1
  1726.         rcl    ax, 1
  1727.         dec    cx
  1728. TestOneBits:    jcxz    StoreProd
  1729.         test    ah, 80h
  1730.         jz    OneBitLoop
  1731. ;
  1732. StoreProd:    mov    fpacc.mantissa[6], ax
  1733.         mov    fpacc.mantissa[4], bx
  1734.         mov    fpacc.mantissa[2], dx
  1735.         mov    fpacc.mantissa[0], si
  1736.         mov    fpacc.exponent, cx
  1737.         or    ax, bx
  1738.         or    ax, dx
  1739.         or    ax, si
  1740.         jnz    FMulDone
  1741. ;
  1742. ; If underflow occurs, set the result to zero.
  1743. ;
  1744.         mov    fpacc.exponent, ax
  1745.         mov    fpacc.sign, al
  1746. ;
  1747. FMulDone:    pop    di
  1748.         pop    si
  1749.         pop    dx
  1750.         pop    cx
  1751.         pop    bx
  1752.         pop    ax
  1753.         pop    ds
  1754.         ret
  1755. sl_fmul        endp
  1756.         assume    ds:nothing
  1757. ;
  1758. ;
  1759. ;
  1760. ;
  1761. ; Mul64- Multiplies the 8 bytes in fpacc.mant by the 8 bytes in fpop.mant
  1762. ;     and leaves the result in fprod.
  1763. ;
  1764. Mul64        proc    near
  1765.         assume    ds:StdGrp
  1766.         xor    ax, ax
  1767.         mov    fprod[0], ax
  1768.         mov    fprod[2], ax
  1769.         mov    fprod[4], ax
  1770.         mov    fprod[6], ax
  1771.         mov    fprod[8], ax
  1772.         mov    fprod[10], ax
  1773.         mov    fprod[12], ax
  1774.         mov    fprod[14], ax
  1775. ;
  1776. ; Computing the following (each character represents 16-bits):
  1777. ;
  1778. ;    A B C D
  1779. ;    x  E F G H
  1780. ;    -------
  1781. ;
  1782. ; Product is computed by:
  1783. ;
  1784. ;    A B C D
  1785. ;    x  E F G H
  1786. ;    ----------
  1787. ;            HD
  1788. ;        HC0
  1789. ;          HB00
  1790. ;      HA000
  1791. ;        GD0
  1792. ;          GC00
  1793. ;         GB000
  1794. ;        GA0000
  1795. ;          FD00
  1796. ;      FC000
  1797. ;        FB0000
  1798. ;       FA00000
  1799. ;         ED000
  1800. ;        EC0000
  1801. ;       EB00000
  1802. ;    + EA000000
  1803. ;    ----------
  1804. ;      xxxxxxxx
  1805. ;
  1806. ; In the loop below, si indexes through A, B, C, and D above (or E, F, G,
  1807. ; and H since multiplication is commutative).
  1808. ;
  1809.         mov    si, ax            ;Set Index to zero.
  1810. flp1:        mov    ax, fpacc.mantissa[si]    ;Multiply A, B, C, or D
  1811.         mul    fpop.mantissa[0]    ; by H.
  1812.         add    fprod [si], ax        ;Add it into the partial
  1813.         adc    fprod+2 [si], dx    ; product computed so far.
  1814.         jnc    NoCarry0
  1815.         inc    fprod+4 [si]
  1816.         jnz    NoCarry0
  1817.         inc    fprod+6 [si]
  1818.         jnz    NoCarry0
  1819.         inc    fprod+8 [si]
  1820.         jnz    NoCarry0
  1821.         inc    fprod+10 [si]
  1822.         jnz    NoCarry0
  1823.         inc    fprod+12 [si]
  1824.         jnz    NoCarry0
  1825.         inc    fprod+14 [si]
  1826. ;
  1827. NoCarry0:
  1828.         mov    ax, fpacc.mantissa[si]    ;Multiply A, B, C, or D
  1829.         mul    fpop.mantissa[2]    ; (selected by SI) by G
  1830.         add    fprod+2 [si], ax    ; and add it into the
  1831.         adc    fprod+4 [si], dx    ; partial product.
  1832.         jnc    NoCarry1
  1833.         inc    fprod+6 [si]
  1834.         jnz    NoCarry1
  1835.         inc    fprod+8 [si]
  1836.         jnz    NoCarry1
  1837.         inc    fprod+10 [si]
  1838.         jnz    NoCarry1
  1839.         inc    fprod+12 [si]
  1840.         jnz    NoCarry1
  1841.         inc    fprod [14]
  1842. ;
  1843. NoCarry1:
  1844.         mov    ax, fpacc.mantissa [si]    ;Multiply A, B, C, or D
  1845.         mul    fpop.mantissa [4]    ; (SI selects) by F and add
  1846.         add    fprod+4 [si], ax    ; it into the partial prod.
  1847.         adc    fprod+6 [si], dx
  1848.         jnc    NoCarry2
  1849.         inc    fprod+8 [si]
  1850.         jnz    NoCarry2
  1851.         inc    fprod+10 [si]
  1852.         jnz    NoCarry2
  1853.         inc    fprod+12 [si]
  1854.         jnz    NoCarry2
  1855.         inc    fprod+14 [si]
  1856. ;
  1857. NoCarry2:
  1858.         mov    ax, fpacc.mantissa [si]    ;Multiply A/B/C/D (selected
  1859.         mul    fpop.mantissa [6]    ; by SI) by E and add it
  1860.         add    fprod+6 [si], ax    ; into the partial product.
  1861.         adc    fprod+8 [si], dx
  1862.         jnc    NoCarry3
  1863.         inc    fprod+10 [si]
  1864.         jnz    NoCarry3
  1865.         inc    fprod+12 [si]
  1866.         jnz    NoCarry3
  1867.         inc    fprod+14 [si]
  1868. ;
  1869. NoCarry3:
  1870.         inc    si            ;Select next multiplier
  1871.         inc    si            ; (B, C, or D above).
  1872.         cmp    si, 8            ;Repeat for 64 bit x 64 bit
  1873.         jnb    QuitMul64        ; multiply.
  1874.         jmp    flp1
  1875. QuitMul64:    ret
  1876.         assume    ds:nothing
  1877. Mul64        endp
  1878. ;
  1879. ;
  1880. ;
  1881. ;
  1882. ;
  1883. ;
  1884. ;
  1885. ;
  1886. ;---------------------------------------------------------------------------
  1887. ;        Floating Point Division
  1888. ;---------------------------------------------------------------------------
  1889. ;
  1890. ;
  1891. ;
  1892. ;
  1893. ; Floating point division: Divides fpacc by fpop.
  1894. ;
  1895.         public    sl_fdiv
  1896. sl_fdiv        proc    far
  1897.         assume    ds:StdGrp
  1898.         push    ds
  1899.         push    ax
  1900.         push    bx
  1901.         push    cx
  1902.         push    dx
  1903.         push    si
  1904.         push    di
  1905.         push    bp
  1906. ;
  1907.         mov    ax, StdGrp
  1908.         mov    ds, ax
  1909. ;
  1910. ; See if either operand is zero:
  1911. ;
  1912.         mov    ax, fpacc.mantissa[0]    ;No need to check exponent!
  1913.         or    ax, fpacc.mantissa[2]
  1914.         or    ax, fpacc.mantissa[4]
  1915.         or    ax, fpacc.mantissa[6]
  1916.         jz    QuoIsZero
  1917. ;
  1918.         mov    ax, fpop.mantissa[0]
  1919.         or    ax, fpop.mantissa[2]
  1920.         or    ax, fpop.mantissa[4]
  1921.         or    ax, fpop.mantissa[6]
  1922.         jnz    DenomNotZero
  1923. ;
  1924. ; Whoops! Division by zero!  Set to largest possible value (+inf) and leave.
  1925. ;
  1926. DivOvfl:    mov    ax, 0ffffh
  1927.         mov    fpacc.exponent, ax
  1928.         mov    fpacc.mantissa[0], ax
  1929.         mov    fpacc.mantissa[2], ax
  1930.         mov    fpacc.mantissa[4], ax
  1931.         mov    fpacc.mantissa[6], ax
  1932.         mov    al, fpop.sign
  1933.         xor    fpacc.sign, al
  1934. ;
  1935. ; Note: we could also do an INT 0 (div by zero) or floating point exception
  1936. ; here, if necessary.
  1937. ;
  1938.         jmp    FDivDone
  1939. ;
  1940. ;
  1941. ; If the numerator is zero, the quotient is zero.  Handle that here.
  1942. ;
  1943. QuoIsZero:    xor    ax, ax            ;Need this!
  1944.         mov    fpacc.sign, al
  1945.         mov    fpacc.exponent, ax
  1946.         mov    fpacc.mantissa[0], ax
  1947.         mov    fpacc.mantissa[2], ax
  1948.         mov    fpacc.mantissa[4], ax
  1949.         mov    fpacc.mantissa[6], ax
  1950.         jmp    FDivDone
  1951. ;
  1952. ;
  1953. ;
  1954. ; If both operands are non-zero, compute the quotient down here.
  1955. ;
  1956. DenomNotZero:    mov    al, fpop.sign        ;Compute the new sign.
  1957.         xor    fpacc.sign, al
  1958. ;
  1959.         mov    ax, fpop.exponent    ;Compute new exponent.
  1960.         sub    ax, 7fffh        ;Subtract BIAS.
  1961.         mov    bx, fpacc.exponent
  1962.         sub    bx, 7fffh
  1963.         sub    bx, ax            ;Compute new exponent
  1964.         jo    DivOvfl
  1965.         add    bx, 7fffh        ;Add in BIAS
  1966.         mov    fpacc.exponent, bx    ;Save as new exponent.
  1967. ;
  1968. ; Okay, compute the quotient of the mantissas down here.
  1969. ;
  1970.         call    Div64
  1971. ;
  1972. ; Normalize the Quotient.
  1973. ;
  1974.         mov    cx, fpacc.exponent
  1975.         jmp    short TestNrmDiv
  1976. ;
  1977. ; Normalize by shifting 16 bits at a time here.
  1978. ;
  1979. NrmDiv1:    sub    cx, 16
  1980.         mov    ax, fpacc.mantissa[4]
  1981.         mov    fpacc.mantissa[6], ax
  1982.         mov    ax, fpacc.mantissa[2]
  1983.         mov    fpacc.mantissa[4], ax
  1984.         mov    ax, fpacc.mantissa[0]
  1985.         mov    fpacc.mantissa[2], ax
  1986.         mov    fpacc.mantissa[0], 0
  1987. TestNrmDiv:     cmp    cx, 16
  1988.         jb    DoNrmDiv8
  1989.         mov      ax, fpacc.mantissa[6]
  1990.         or    ax, ax
  1991.         jz    NrmDiv1
  1992. ;
  1993. ; Normalize by shifting eight bits at a time here.
  1994. ;
  1995. ; See if we can shift the product a whole byte
  1996. ;
  1997. DoNrmDiv8:    cmp    byte ptr fpacc.mantissa[7], 0
  1998.         jnz    DoOneBitsDiv
  1999.         cmp    cx, 8
  2000.         jb    DoOneBitsDiv
  2001.         mov    ax, fpacc.mantissa[5]
  2002.         mov    fpacc.mantissa[6], ax
  2003.         mov    ax, fpacc.mantissa[3]
  2004.         mov    fpacc.mantissa[4], ax
  2005.         mov    ax, fpacc.mantissa[1]
  2006.         mov    fpacc.mantissa[2], ax
  2007.         mov    al, byte ptr fpacc.mantissa[0]
  2008.         mov    byte ptr fpacc.mantissa[1], al
  2009.         mov    byte ptr fpacc.mantissa[0], 0
  2010.         sub    cx, 8
  2011. ;
  2012. DoOneBitsDiv:    mov    ax, fpacc.mantissa[6]
  2013.         mov    bx, fpacc.mantissa[4]
  2014.         mov    dx, fpacc.mantissa[2]
  2015.         mov    si, fpacc.mantissa[0]
  2016.         jmp    short TestOneBitsDiv
  2017. ;
  2018. ; One bit at a time normalization here.
  2019. ;
  2020. OneBitLoopDiv:    shl    si, 1
  2021.         rcl    dx, 1
  2022.         rcl    bx, 1
  2023.         rcl    ax, 1
  2024.         dec    cx
  2025. TestOneBitsDiv:    jcxz    StoreQuo
  2026.         test    ah, 80h
  2027.         jz    OneBitLoopDiv
  2028. ;
  2029. StoreQuo:    mov    fpacc.mantissa[6], ax
  2030.         mov    fpacc.mantissa[4], bx
  2031.         mov    fpacc.mantissa[2], dx
  2032.         mov    fpacc.mantissa[0], si
  2033.         mov    fpacc.exponent, cx
  2034.         or    ax, bx
  2035.         or    ax, dx
  2036.         or    ax, si
  2037.         jnz    FDivDone
  2038. ;
  2039. ; If underflow occurs, set the result to zero.
  2040. ;
  2041.         mov    fpacc.exponent, ax
  2042.         mov    fpacc.sign, al
  2043. ;
  2044. FDivDone:    pop    bp
  2045.         pop    di
  2046.         pop    si
  2047.         pop    dx
  2048.         pop    cx
  2049.         pop    bx
  2050.         pop    ax
  2051.         pop    ds
  2052.         ret
  2053. sl_fdiv        endp
  2054.         assume    ds:nothing
  2055. ;
  2056. ;
  2057. ;
  2058. ;
  2059. ; Div64- Divides the 64-bit fpacc.mantissa by the 64-bit fpop.mantissa.
  2060. ;
  2061. div64        proc    near
  2062.         assume    ds:StdGrp
  2063. ;
  2064. ;
  2065. ; First, normalize fpop if necessary and possible:
  2066. ;
  2067.         mov    ax, fpop.mantissa[6]
  2068.         mov    bx, fpop.mantissa[4]
  2069.         mov    cx, fpop.mantissa[2]
  2070.         mov    dx, fpop.mantissa[0]
  2071.         mov    si, fpacc.exponent
  2072.         jmp    short Div16NrmTest
  2073. ;
  2074. ; The following loop normalizes fpop 16 bits at a time.
  2075. ;
  2076. Div16NrmLp:    mov    ax, bx
  2077.         mov    bx, dx
  2078.         mov    cx, dx
  2079.         xor    dx, dx
  2080.         add    si, 16
  2081. Div16NrmTest:    cmp    si, -16
  2082.         ja    Div16Nrm8        ;Must be unsigned because this
  2083.         or    ax, ax            ; is bias arithmetic, not
  2084.         jz    Div16NrmLp        ; two's complement!
  2085. ;
  2086. ;
  2087. ; The following code checks to see if it can normalize by eight bits at
  2088. ; a time.
  2089. ;
  2090. Div16Nrm8:    cmp    si, -8
  2091.         ja    Div1NrmTest        ;Must be unsigned!
  2092.         cmp    ah, 0
  2093.         jnz    Div1NrmTest
  2094.         mov    ah, al
  2095.         mov    al, bh
  2096.         mov    bh, bl
  2097.         mov    bl, ch
  2098.         mov    ch, cl
  2099.         mov    cl, dh
  2100.         mov    dh, dl
  2101.         mov    dl, 0
  2102.         add    si, 8
  2103.         jmp    short Div1NrmTest
  2104. ;
  2105. ; Down here we're stuck with the slow task of normalizing by a bit
  2106. ; at a time.
  2107. ;
  2108. Div1NrmLp:    shl    dx, 1
  2109.         rcl    cx, 1
  2110.         rcl    bx, 1
  2111.         rcl    ax, 1
  2112.         inc    si
  2113. Div1NrmTest:    cmp    si, -1
  2114.         je    DivOvfl2        ;Can't do it!
  2115.         test    ah, 80h
  2116.         jz    Div1NrmLp
  2117.         jmp    short DoSlowDiv
  2118. ;
  2119. ; If overflow occurs, set FPACC to the maximum possible value and quit.
  2120. ;
  2121. DivOvfl2:    mov    ax, 0ffffh
  2122.         mov    fpacc.exponent, ax
  2123.         mov    fpacc.mantissa[0], ax
  2124.         mov    fpacc.mantissa[2], ax
  2125.         mov    fpacc.mantissa[4], ax
  2126.         mov    fpacc.mantissa[6], ax
  2127.         jmp    QuitDiv
  2128. ;
  2129. ; Oh No! A GawdAwful bit-by-bit division routine.  Terribly slow!
  2130. ; Actually, it was sped up a little by checking to see if it could
  2131. ; shift eight or sixteen bits at a time (because it encounters eight
  2132. ; or sixteen zeros during the division).
  2133. ;
  2134. ; Could possibly speed this up some more by checking for the special
  2135. ; case of n/16 bits.  Haven't tried this idea out though.
  2136. ;
  2137. DoSlowDiv:    mov    fpacc.exponent, si
  2138.         mov    si, ax
  2139.         mov    di, bx
  2140.         mov    fpop.mantissa[2], cx
  2141.         mov    fpop.mantissa[0], dx
  2142.         mov    ax, fpacc.mantissa[6]
  2143.         mov    bx, fpacc.mantissa[4]
  2144.         mov    cx, fpacc.mantissa[2]
  2145.         mov    dx, fpacc.mantissa[0]
  2146.         mov    bp, 64
  2147. DivideLoop:    cmp    bp, 16
  2148.         jb      Test8
  2149.         or    ax, ax
  2150.         jnz    Test8
  2151. ;
  2152. ; Do a shift by 16 bits here:
  2153. ;
  2154.         mov    ax, Quotient[4]
  2155.         mov    Quotient[6], ax
  2156.         mov    ax, Quotient[2]
  2157.         mov    Quotient[4], ax
  2158.         mov    ax, Quotient[0]
  2159.         mov    Quotient[2], ax
  2160.         mov    Quotient[0], 0
  2161.         mov    ax, bx
  2162.         mov    bx, cx
  2163.         mov    cx, dx
  2164.         xor    dx, dx
  2165.         sub    bp, 16
  2166.         jz    FinishDivide
  2167.         jmp    DivideLoop
  2168. ;
  2169. Test8:        cmp    bp, 8
  2170.         jb      Do1
  2171.         cmp    ah, 0
  2172.         jnz    Do1
  2173. ;
  2174. ; Do a shift by 8 bits here:
  2175. ;
  2176.         push    ax
  2177.         mov    ax, Quotient[5]
  2178.         mov    Quotient[6], ax
  2179.         mov    ax, Quotient[3]
  2180.         mov    Quotient[4], ax
  2181.         mov    ax, Quotient[1]
  2182.         mov    Quotient[2], ax
  2183.         mov    al, byte ptr Quotient [0]
  2184.         mov    byte ptr Quotient [1], al
  2185.         mov    byte ptr Quotient[0], 0
  2186.         pop    ax
  2187.         mov    ah, al
  2188.         mov    al, bh
  2189.         mov    bh, bl
  2190.         mov    bl, ch
  2191.         mov    ch, cl
  2192.         mov    cl, dh
  2193.         mov    dh, dl
  2194.         mov    dl, 0
  2195.         sub    bp, 8
  2196.         jz    FinishDivide
  2197.         jmp    DivideLoop
  2198. ;
  2199. Do1:        cmp    ax, si
  2200.         jb    shift0
  2201.         ja    Shift1
  2202.         cmp    bx, di
  2203.         jb    shift0
  2204.         ja    Shift1
  2205.         cmp    cx, fpop.mantissa[2]
  2206.         jb    shift0
  2207.         ja    shift1
  2208.         cmp    dx, fpop.mantissa[0]
  2209.         jb    shift0
  2210. ;
  2211. ; fpacc.mantiss IS greater than fpop.mantissa, shift a one bit into
  2212. ; the result here:
  2213. ;
  2214. Shift1:        stc
  2215.         rcl    Quotient[0], 1
  2216.         rcl    Quotient[2], 1
  2217.         rcl    Quotient[4], 1
  2218.         rcl    Quotient[6], 1
  2219.         sub    dx, fpop.mantissa[0]
  2220.         sbb    cx, fpop.mantissa[2]
  2221.         sbb    bx, di
  2222.         sbb    ax, si
  2223.         shl    dx, 1
  2224.         rcl    cx, 1
  2225.         rcl    bx, 1
  2226.         rcl    ax, 1            ;Never a carry out.
  2227.         dec    bp
  2228.         jnz    jDivideLoop
  2229.         jmp    FinishDivide
  2230. ;
  2231. ; If fpacc.mantissa was less than fpop.mantissa, shift a zero bit into
  2232. ; the quotient.
  2233. ;
  2234. Shift0:        shl    Quotient[0], 1
  2235.         rcl    Quotient[2], 1
  2236.         rcl    Quotient[4], 1
  2237.         rcl    Quotient[6], 1
  2238.         shl    dx, 1
  2239.         rcl    cx, 1
  2240.         rcl    bx, 1
  2241.         rcl    ax, 1
  2242.         jc    Greater
  2243.         dec    bp
  2244.         jnz    jDivideLoop
  2245.         jmp    FinishDivide
  2246. jDivideLoop:    jmp    DivideLoop
  2247. ;
  2248. ; If there was a carry out of the shift, we KNOW that fpacc must be
  2249. ; greater than fpop.  Handle that case down here.
  2250. ;
  2251. Greater:    dec    bp
  2252.         jz    FinishDivide
  2253.         stc
  2254.         rcl    Quotient[0], 1
  2255.         rcl    Quotient[2], 1
  2256.         rcl    Quotient[4], 1
  2257.         rcl    Quotient[6], 1
  2258.         sub    dx, fpop.mantissa[0]
  2259.         sbb    cx, fpop.mantissa[2]
  2260.         sbb    bx, di
  2261.         sbb    ax, si
  2262.         shl    dx, 1
  2263.         rcl    cx, 1
  2264.         rcl    bx, 1
  2265.         rcl    ax, 1
  2266.         jc    Greater
  2267.         dec    bp
  2268.         jz    FinishDivide
  2269.         jmp    DivideLoop
  2270. ;
  2271. ; Okay, clean everything up down here:
  2272. ;
  2273. FinishDivide:    mov    ax, Quotient[0]
  2274.         mov    fpacc.mantissa[0], ax
  2275.         mov    ax, Quotient[2]
  2276.         mov    fpacc.mantissa[2], ax
  2277.         mov    ax, Quotient[4]
  2278.         mov    fpacc.mantissa[4], ax
  2279.         mov    ax, Quotient[6]
  2280.         mov    fpacc.mantissa[6], ax
  2281. ;
  2282. QuitDiv:    ret
  2283.         assume    ds:nothing
  2284. div64        endp
  2285. ;
  2286. ;
  2287. ;
  2288. ;
  2289. ;
  2290. ;---------------------------------------------------------------------------
  2291. ;        Floating Point => TEXT (Output) conversion routines.
  2292. ;---------------------------------------------------------------------------
  2293. ;
  2294. ;
  2295. ;
  2296. ;
  2297. ; Power of ten tables used by the floating point I/O routines.
  2298. ;
  2299. ; Format for each entry (13 bytes):
  2300. ;
  2301. ; 1st through
  2302. ; 11th bytes    Internal FP format for this particular number.
  2303. ;
  2304. ; 12th &
  2305. ; 13th bytes:    Decimal exponent for this value.
  2306. ;
  2307. ;
  2308. ; This first table contains the negative powers of ten as follows:
  2309. ;
  2310. ;   for n:= 0 to 12 do
  2311. ;    entry [12-n] := 10 ** (-2 ** n)
  2312. ;   entry [13] := 1.0
  2313. ;
  2314. PotTbln         dw    9fdeh, 0d2ceh, 4c8h, 0a6ddh, 4ad8h    ; 1e-4096
  2315.         db    0                    ; Sign
  2316.         dw    -4096                    ; Dec Exponent
  2317. ;
  2318.         dw    2de4h, 3436h, 534fh, 0ceaeh, 656bh    ; 1e-2048
  2319.         db    0
  2320.         dw    -2048
  2321. ;
  2322.         dw    0c0beh, 0da57h, 82a5h, 0a2a6h, 72b5h    ; 1e-1024
  2323.         db    0
  2324.         dw    -1024
  2325. ;
  2326.         dw    0d21ch, 0db23h, 0ee32h, 9049h, 795ah    ; 1e-512
  2327.         db    0
  2328.         dw    -512
  2329. ;
  2330.         dw    193ah, 637ah, 4325h, 0c031h, 7cach    ; 1e-256
  2331.         db    0
  2332.         dw    -256
  2333. ;
  2334.         dw    0e4a1h, 64bch, 467ch, 0ddd0h, 7e55h    ; 1e-128
  2335.         db    0
  2336.         dw    -128
  2337. ;
  2338.         dw    0e9a5h, 0a539h, 0ea27h, 0a87fh, 7f2ah    ; 1e-64
  2339.         db    0
  2340.         dw    -64
  2341. ;
  2342.         dw    94bah, 4539h, 1eadh, 0cfb1h, 7f94h    ; 1e-32
  2343.         db    0
  2344.         dw    -32
  2345. ;
  2346.         dw    0e15bh, 0c44dh, 94beh, 0e695h, 7fc9h    ; 1e-16
  2347.         db    0
  2348.         dw    -16
  2349. ;
  2350.         dw    0cefdh, 8461h, 7711h, 0abcch, 7fe4h    ; 1e-8
  2351.         db    0
  2352.         dw    -8
  2353. ;
  2354.         dw    652ch, 0e219h, 1758h, 0d1b7h, 7ff1h    ; 1e-4
  2355.         db    0
  2356.         dw    -4
  2357. ;
  2358.         dw    0d70ah, 70a3h, 0a3dh, 0a3d7h, 7ff8h    ; 1e-2
  2359.         db    0
  2360.         dw    -2
  2361. ;
  2362. Div10Value    dw    0cccdh, 0cccch, 0cccch, 0cccch, 7ffbh    ; 1e-1
  2363.         db    0
  2364.         dw    -1
  2365. ;
  2366.         dw    0, 0, 0, 8000h, 7fffh            ; 1e0
  2367.         db    0
  2368.         dw    0
  2369. ;
  2370. ;
  2371. ; PotTblP- Power of ten table.  Holds powers of ten raised to positive
  2372. ;       powers of two;
  2373. ;
  2374. ;        i.e., x(12-n) = 10 ** (2 ** n) for 0 <= n <= 12.
  2375. ;              x(13) = 1.0
  2376. ;              x(-1) = 10 ** (2 ** -4096)
  2377. ;
  2378. ; There is a -1 entry since it is possible for the algorithm to back up
  2379. ; before the table.
  2380. ;
  2381.         dw    979bh, 8a20h, 5202h, 0c460h, 0b525h    ; 1e+4096
  2382.         db    0
  2383.         dw    4096
  2384. ;
  2385. PotTblP        dw    979bh, 8a20h, 5202h, 0c460h, 0b525h    ; 1e+4096
  2386.         db    0
  2387.         dw    4096
  2388. ;
  2389.         dw    5de5h, 0c53dh, 3b5dh, 9e8bh, 09a92h    ; 1e+2048
  2390.         db    0
  2391.         dw    2048
  2392. ;
  2393.         dw    0c17h, 8175h, 7586h, 0c976h, 08d48h    ; 1e+1024
  2394.         db    0
  2395.         dw    1024
  2396. ;
  2397.         dw    91c7h, 0a60eh, 0a0aeh, 0e319h, 086a3h    ; 1e+512
  2398.         db    0
  2399.         dw    512
  2400. ;
  2401.         dw    0de8eh, 9df9h, 0ebfbh, 0aa7eh, 08351h    ; 1e+256
  2402.         db    0
  2403.         dw    256
  2404. ;
  2405.         dw    8ce0h, 80e9h, 47c9h, 93bah, 081a8h    ; 1e+128
  2406.         db    0
  2407.         dw    128
  2408. ;
  2409.         dw    0a6d5h, 0ffcfh, 1f49h, 0c278h, 080d3h    ; 1e+64
  2410.         db    0
  2411.         dw    64
  2412. ;
  2413.         dw    0b59eh, 2b70h, 0ada8h, 9dc5h, 08069h    ; 1e+32
  2414.         db    0
  2415.         dw    32
  2416. ;
  2417.         dw    0, 400h, 0c9bfh, 8e1bh, 08034h        ; 1e+16
  2418.         db    0
  2419.         dw    16
  2420. ;
  2421.         dw    0, 0, 2000h, 0bebch, 08019h        ; 1e+8
  2422.         db    0
  2423.         dw    8
  2424. ;
  2425.         dw    0, 0, 0, 9c40h, 0800ch            ; 1e+4
  2426.         db    0
  2427.         dw    4
  2428. ;
  2429.         dw    0, 0, 0, 0c800h, 08005h            ; 1e+2
  2430.         db    0
  2431.         dw    2
  2432. ;
  2433.         dw    0, 0, 0, 0a000h, 08002h            ; 1e+1
  2434.         db    0
  2435.         dw    1
  2436. ;
  2437.         dw    0, 0, 0, 8000h, 7fffh            ; 1e0
  2438.         db    0
  2439.         dw    0
  2440. ;
  2441. ;
  2442. ;
  2443. ;
  2444. ;
  2445. ;
  2446. ;
  2447. ; SL_FTOA-    Converts extended precision value in FPACC to a decimal
  2448. ;        string.  AL contains the field width, AH contains the
  2449. ;        number of positions after the decimal point.  The format
  2450. ;        of the converted string is:
  2451. ;
  2452. ;            sd.e
  2453. ;
  2454. ;        where "s" is a single character which is either a space
  2455. ;        or "=", "e" is some number of digits which is equal to
  2456. ;        the value passed in AL, and "d" is the number of digits
  2457. ;        given by  (AL-AH-2).  If the field width is too small,
  2458. ;        this routine creates a string of "#" characters AH long.
  2459. ;
  2460. ;        ES:DI contains the address where we're supposed to put
  2461. ;        the resulting string.  This code assumes that there is
  2462. ;        sufficient memory to hold (AL+1) characters at this address.
  2463. ;
  2464. ;
  2465. ;
  2466.         public    sl_ftoa
  2467. sl_ftoa        proc    far
  2468.         push    di
  2469.         call    far ptr sl_ftoa2
  2470.         pop    di
  2471.         ret
  2472. sl_ftoa        endp
  2473. ;
  2474.         public    sl_ftoa2
  2475. sl_ftoa2    proc    far
  2476.         assume    ds:StdGrp
  2477. ;
  2478.         pushf
  2479.         push    ds
  2480.         push    ax
  2481.         push    bx
  2482.         push    cx
  2483.         push    dx
  2484.         push    si
  2485. ;
  2486.         cld
  2487.         mov    bx, StdGrp
  2488.         mov    ds, bx
  2489. ;
  2490. ; Save fpacc 'cause it gets munged.
  2491. ;
  2492.         push    fpacc.Mantissa [0]
  2493.         push    fpacc.Mantissa [2]
  2494.         push    fpacc.Mantissa [4]
  2495.         push    fpacc.Mantissa [6]
  2496.         push    fpacc.Exponent
  2497.         push    word ptr fpacc.Sign
  2498. ;
  2499.         mov    cx, ax        ;Save field width/dec pts here.
  2500. ;
  2501.         call    fpdigits    ;Convert fpacc to digit string.
  2502. ;
  2503. ; Round the string of digits to the number of significant digits we want to
  2504. ; display for this number:
  2505. ;
  2506.         mov    bx, DecExponent
  2507.         cmp    bx, 18
  2508.         jb    PosRS
  2509.         xor    bx, bx        ;Force to zero if negative or too big.
  2510. ;
  2511. PosRS:        add    bl, ch               ;Compute position where we should start
  2512.         adc    bh, 0        ; the rounding.
  2513.         inc    bx        ;Tweak next digit.
  2514.         cmp    bx, 18        ;Don't bother rounding if we have
  2515.         jae    RoundDone    ; more than 18 digits here.
  2516. ;
  2517. ; Add 5 to the digit after the last digit we want to print.  Then propogate
  2518. ; any overflow through the remaining digits.
  2519. ;
  2520.         mov    al, DecDigits [bx]
  2521.         add    al, 5
  2522.         mov    DecDigits [bx], al
  2523.         cmp    al, "9"
  2524.         jbe     RoundDone
  2525.         sub    DecDigits [bx], 10
  2526. RoundLoop:    dec    bx
  2527.         js    FirstDigit
  2528.         inc    DecDigits[bx]
  2529.         cmp    DecDigits[bx], "9"
  2530.         jbe    RoundDone
  2531.         sub    DecDigits[bx], 10
  2532.         jmp    RoundLoop
  2533. ;
  2534. ; If we hit the first digit in the string, we've got to shift all the
  2535. ; characters down one position and put a "1" in the first character
  2536. ; position.
  2537. ;
  2538. FirstDigit:     mov    bx, DecExponent
  2539.         cmp    bx, 18
  2540.         jb    FDOkay
  2541.         xor    bx, bx
  2542. ;
  2543. FDOkay:        mov    bl, ch
  2544.         mov    bh, 0
  2545.         inc    bx
  2546. FDLp:        mov    al, byte ptr DecDigits[bx-1]
  2547.         mov    DecDigits [bx], al
  2548.         dec    bx
  2549.         jnz    FDLp
  2550.         mov    DecDigits, "1"
  2551.         inc    DecExponent    ;Cause we just added a digit.
  2552. ;
  2553. RoundDone:
  2554. ;
  2555. ; See if we're dealing with values greater than one (abs) or between 0 & 1.
  2556. ;
  2557.         cmp    DecExponent, 0    ;Handle positive/negative exponents
  2558.         jge    PositiveExp    ; separately.
  2559. ;
  2560. ; Handle values between 0 & 1 here (negative powers of ten).
  2561. ;
  2562.         mov    dl, ch        ;Compute #'s width = DecPlaces+3
  2563.         add       dl, 3        ;Make room for "-0."
  2564.         jc    BadFieldWidth
  2565.         cmp    dl, 4
  2566.         jae    LengthOk
  2567.         mov    dl, 4        ;Minimum string is "-0.0"
  2568. LengthOK:    mov    al, ' '
  2569. PutSpcs2:       cmp    dl, cl
  2570.         jae    PS2Done
  2571.         stosb
  2572.         inc    dl
  2573.         jmp    PutSpcs2
  2574. ;
  2575. PS2Done:           mov    al, DecSign
  2576.         stosb
  2577.         mov    al, "0"        ;Output "0." before the number.
  2578.         stosb
  2579.         mov    al, "."
  2580.         stosb
  2581.         mov    ah, 0        ;Used to count output digits
  2582.         lea    bx, stdGrp:DecDigits ;Pointer to number string.
  2583. PutDigits2:    inc    DecExponent
  2584.         jns    PutTheDigit
  2585. ;
  2586. ; If the exponent value is still negative, output zeros because we've yet
  2587. ; to reach the beginning of the number.
  2588. ;
  2589. PutZero2:    mov    al, '0'
  2590.         stosb
  2591.         jmp    TestDone2
  2592. ;
  2593. PutTheDigit:    cmp    ah, 18        ;If more than 18 digits so far, just
  2594.         jae    PutZero2    ; output zeros.
  2595. ;
  2596.         mov    al, [bx]
  2597.         inc    bx
  2598.         stosb
  2599. ;
  2600. TestDone2:    inc    ah
  2601.         dec    ch
  2602.         jnz     PutDigits2
  2603.         mov    byte ptr es:[di], 0
  2604.         jmp    ftoaDone
  2605. ;
  2606. ;
  2607. ; Okay, we've got a positive exponent here.  First, let's adjust the field
  2608. ; width value (in CH) so that it includes the sign and possible decimal point.
  2609. ;
  2610. PositiveExp:    mov    dx, DecExponent    ;Get actual # of digits to left of "."
  2611.         inc    dx        ;Allow for sign and the fact that there
  2612.         inc    dx        ; is always one digit to left of ".".
  2613.         cmp    ch, 0        ;# of chars after "." = 0?
  2614.         je    NoDecPt
  2615.         add    dl, ch        ;Add in number of chars after "."
  2616.         adc    dh, 0
  2617.         inc    dx        ;Make room for "."
  2618. NoDecPt:
  2619. ;
  2620. ;
  2621. ; Make sure the field width is bigger than the number of decimal places to
  2622. ; print.
  2623. ;
  2624.         cmp    cl, ch
  2625.         jb    BadFieldWidth
  2626. ;
  2627. ;
  2628. ; Okay, now see if the user is trying to print a value which is too large
  2629. ; to fit in the given field width:
  2630. ;
  2631.         cmp    dh, 0
  2632.         jne    BadFieldWidth    ;Sorry, no output >= 256 chars.
  2633.         cmp    dl, cl        ;Need field width > specified FW?
  2634.         jbe    GoodFieldWidth
  2635. ;
  2636. ; If we get down here, then we've got a number which will not fit in the
  2637. ; specified field width.  Fill the string with #'s (sorta like FORTRAN).
  2638. ;
  2639. BadFieldWidth:    mov    ch, 0        ;Set CX=field width.
  2640.         mov    al, "#"
  2641.     rep    stosb
  2642.         mov    byte ptr es:[di], 0
  2643.         jmp    ftoaDone
  2644. ;
  2645. ;
  2646. ; Print any necessary spaces in front of the number.
  2647. ;
  2648. GoodFieldWidth:    call    PutSpaces
  2649. ;
  2650. ; Output the sign character (" " or "-"):
  2651. ;
  2652.         mov    al, DecSign
  2653.         stosb
  2654. ;
  2655. ; Okay, output the digits for this number here.
  2656. ;
  2657.         mov    ah, 0        ;Counts off output characters.
  2658.         lea    bx, stdgrp:DecDigits ;Pointer to digit string.
  2659.         mov    cl, ch        ;CX := # of chars after "."
  2660.         mov    ch, 0               ; plus number of characters before
  2661.         add    cx, DecExponent    ; the ".".
  2662.         inc    cx        ;Always at least one digit before "."
  2663. OutputLp:    cmp    ah, 18        ;Exceeded 18 digits?
  2664.         jae    PutZeros
  2665.         mov    al, [bx]
  2666.         inc    bx
  2667.         jmp    PutChar
  2668. ;
  2669. PutZeros:    mov    al, '0'
  2670. PutChar:    stosb
  2671.         cmp    DecExponent, 0
  2672.         jne    DontPutPoint
  2673.         mov    al, '.'
  2674.         stosb
  2675. ;
  2676. DontPutPoint:    dec    DecExponent
  2677.         inc    ah
  2678.         loop    OutputLp
  2679.         mov    byte ptr es:[di], 0     ;Output the zero byte.
  2680. ;
  2681. ftoaDone:    pop    word ptr fpacc.Sign
  2682.         pop    fpacc.Exponent
  2683.         pop    fpacc.Mantissa [6]
  2684.         pop    fpacc.Mantissa [4]
  2685.         pop    fpacc.Mantissa [2]
  2686.         pop    fpacc.Mantissa [0]
  2687.         pop    si
  2688.         pop    dx
  2689.         pop    cx
  2690.         pop    bx
  2691.         pop    ax
  2692.         pop    ds
  2693.         popf
  2694.         ret
  2695. sl_ftoa2    endp
  2696. ;
  2697. ;
  2698. ;
  2699. ;
  2700. ; Okay, now we need to insert any necessary leading spaces.  We need to
  2701. ; put (FieldWidth - ActualWidth) spaces before the string of digits.
  2702. ;
  2703. PutSpaces    proc    near
  2704.         cmp    dl, cl        ;See if print width >= field width
  2705.         jae    NoSpaces
  2706.         mov    ah, cl
  2707.         sub    ah, dl        ;Compute # of spaces to print.
  2708.         mov    al, ' '
  2709. PSLp:        stosb
  2710.         dec    ah
  2711.         jnz    PSLp
  2712. NoSpaces:    ret
  2713. PutSpaces    endp
  2714. ;
  2715. ;
  2716. ;
  2717. ;
  2718. ;
  2719. ;
  2720. ;
  2721. ;
  2722. ;
  2723. ;
  2724. ;
  2725. ;
  2726. ;
  2727. ;
  2728. ; SL_ETOA-    Converts value in FPACC to exponential form.  AL contains
  2729. ;        the number of print positions.  ES:DI points to the array
  2730. ;        which will hold this string (it must be at least AL+1 chars
  2731. ;        long).
  2732. ;
  2733. ;        The output string takes the format:
  2734. ;
  2735. ;        {" "|-} [0-9] "." [0-9]* "E" [+|-] [0-9]{2,4}
  2736. ;
  2737. ;        (The term "[0-9]{2,4}" means either two or four digits)
  2738. ;
  2739. ;        AL must be at least eight or this code outputs #s.
  2740. ;
  2741.         public    sl_etoa
  2742. sl_etoa        proc    far
  2743.         push    di
  2744.         call    far ptr sl_etoa2
  2745.         pop    di
  2746.         ret
  2747. sl_etoa        endp
  2748. ;
  2749. ;
  2750.         public    sl_etoa2
  2751. sl_etoa2    proc    far
  2752.         assume    ds:StdGrp
  2753. ;
  2754.         pushf
  2755.         push    ds
  2756.         push    ax
  2757.         push    bx
  2758.         push    cx
  2759.         push    si
  2760. ;
  2761.         cld
  2762.         mov    bx, StdGrp
  2763.         mov    ds, bx
  2764. ;
  2765.         push    fpacc.Mantissa [0]
  2766.         push    fpacc.Mantissa [2]
  2767.         push    fpacc.Mantissa [4]
  2768.         push    fpacc.Mantissa [6]
  2769.         push    fpacc.Exponent
  2770.         push    word ptr fpacc.Sign
  2771. ;
  2772.         call    fpdigits
  2773. ;
  2774. ; See if we have sufficient room for the number-
  2775. ;
  2776.         mov    ah, 0
  2777.         mov    cx, ax
  2778. ;
  2779. ; Okay, take out spots for sign, ".", "E", sign, and at least four exponent
  2780. ; digits and the exponent's sign:
  2781. ;
  2782. Subtract2:    sub    ax, 8
  2783.         jc    BadEWidth
  2784.         jnz    DoTheRound    ;Make sure at least 1 digit left!
  2785. ;
  2786. BadEWidth:    mov    ch, 0
  2787.         mov    al, "#"
  2788.     rep    stosb
  2789.         mov    al, 0
  2790.         stosb
  2791.         jmp    etoaDone
  2792. ;
  2793. ; Round the number to the specified number of places.
  2794. ;
  2795. DoTheRound:    mov    ch, al        ;# of decimal places is # of posns.
  2796.         mov    bl, ch               ;Compute position where we should start
  2797.         mov    bh, 0        ; the rounding.
  2798.         cmp    bx, 18        ;Don't bother rounding if we have
  2799.         jae    eRoundDone    ; more than 18 digits here.
  2800. ;
  2801. ; Add 5 to the digit after the last digit we want to print.  Then propogate
  2802. ; any overflow through the remaining digits.
  2803. ;
  2804.         mov    al, DecDigits [bx]
  2805.         add    al, 5
  2806.         mov    DecDigits [bx], al
  2807.         cmp    al, "9"
  2808.         jbe     eRoundDone
  2809.         sub    DecDigits [bx], 10
  2810. eRoundLoop:    dec    bx
  2811.         js    eFirstDigit
  2812.         inc    DecDigits[bx]
  2813.         cmp    DecDigits[bx], "9"
  2814.         jbe    eRoundDone
  2815.         sub    DecDigits[bx], 10
  2816.         jmp    eRoundLoop
  2817. ;
  2818. ; If we hit the first digit in the string, we've got to shift all the
  2819. ; characters down one position and put a "1" in the first character
  2820. ; position.
  2821. ;
  2822. eFirstDigit:    mov    bl, ch
  2823.         mov    bh, 0
  2824.         inc    bx
  2825. eFDLp:        mov    al, byte ptr DecDigits[bx-1]
  2826.         mov    DecDigits [bx], al
  2827.         dec    bx
  2828.         jnz    eFDLp
  2829.         mov    DecDigits, "1"
  2830.         inc    DecExponent    ;Cause we just added a digit.
  2831. ;
  2832. eRoundDone:
  2833. ;
  2834. ; Okay, output the value here.
  2835. ;
  2836.         mov    cl, ch        ;Set CX=Number of output chars
  2837.         mov    ch, 0
  2838.         mov    al, DecSign
  2839.         stosb
  2840.         lea    si, stdgrp:DecDigits
  2841.         movsb            ;Output first char.
  2842.         dec    cx        ;See if we're done!
  2843.         jz    PutExponent
  2844. ;
  2845. ; Output the fractional part here
  2846. ;
  2847.         mov    al, "."
  2848.         stosb
  2849.         mov    ah, 17        ;Max # of chars to output.
  2850. PutFractional:    cmp    ah, 0
  2851.         jz    NoMoreDigs
  2852.         movsb
  2853.         dec    ah
  2854.         jmp    NextFraction
  2855. ;
  2856. ; If we've output more than 18 digits, just output zeros.
  2857. ;
  2858. NoMoreDigs:    mov    al, "0"
  2859.         stosb
  2860. ;
  2861. NextFraction:    loop    PutFractional
  2862. PutExponent:    mov    al, "E"
  2863.         stosb
  2864.         mov    al, "+"
  2865.         cmp    DecExponent, 0
  2866.         jge    NoNegExp
  2867.         mov    al, "-"
  2868.         neg    DecExponent
  2869. ;
  2870. NoNegExp:    stosb
  2871.         mov    ax, DecExponent
  2872.         cwd            ;Sets DX := 0.
  2873.         mov    cx, 1000
  2874.         div    cx
  2875.         or    al, "0"
  2876.         stosb            ;Output 1000's digit
  2877.         xchg    ax, dx
  2878.         cwd
  2879.         mov    cx, 100
  2880.         div    cx
  2881.         or    al, "0"        ;Output 100's digit
  2882.         stosb
  2883.         xchg    ax, dx
  2884.         cwd
  2885.         mov    cx, 10
  2886.         div    cx
  2887.         or    al, "0"        ;Output 10's digit
  2888.         stosb
  2889.         xchg    ax, dx
  2890.         or    al, "0"        ;Output 1's digit
  2891.         stosb
  2892.         mov    byte ptr es:[di], 0    ;Output zero byte.
  2893. ;
  2894. etoaDone:    pop    word ptr fpacc.Sign
  2895.         pop    fpacc.Exponent
  2896.         pop    fpacc.Mantissa [6]
  2897.         pop    fpacc.Mantissa [4]
  2898.         pop    fpacc.Mantissa [2]
  2899.         pop    fpacc.Mantissa [0]
  2900.         pop    si
  2901.         pop    cx
  2902.         pop    bx
  2903.         pop    ax
  2904.         pop    ds
  2905.         popf
  2906.         ret
  2907. sl_etoa2    endp
  2908. ;
  2909. ;
  2910. ;
  2911. ;
  2912. ;
  2913. ; FPDigits- Converts the floating point number in FPACC to a string of
  2914. ;        digits (in DecDigits), an integer exponent value (DecExp),
  2915. ;        and a sign character (DecSign).  The decimal point is assumed
  2916. ;        to be between the first and second characters in the string.
  2917. ;
  2918. FPDigits    proc    near
  2919.         assume    ds:StdGrp
  2920.         push    ds
  2921.         push    ax
  2922.         push    bx
  2923.         push    cx
  2924.         push    dx
  2925.         push    di
  2926.         push    si
  2927. ;
  2928.         mov    ax, seg StdGrp
  2929.         mov    ds, ax
  2930. ;
  2931. ; First things first, see if this value is zero:
  2932. ;
  2933.         mov    ax, fpacc.exponent
  2934.         or    ax, fpacc.Mantissa [0]
  2935.         or    ax, fpacc.Mantissa [2]
  2936.         or    ax, fpacc.Mantissa [4]
  2937.         or    ax, fpacc.Mantissa [6]
  2938.         jnz    fpdNotZero
  2939. ;
  2940. ; Well, it's zero.  Handle this as a special case:
  2941. ;
  2942.         mov    ax, 3030h        ;"00"
  2943.         mov    word ptr DecDigits[0], ax
  2944.         mov    word ptr DecDigits[2], ax
  2945.         mov    word ptr DecDigits[4], ax
  2946.         mov    word ptr DecDigits[6], ax
  2947.         mov    word ptr DecDigits[8], ax
  2948.         mov    word ptr DecDigits[10], ax
  2949.         mov    word ptr DecDigits[12], ax
  2950.         mov    word ptr DecDigits[14], ax
  2951.         mov    word ptr DecDigits[16], ax
  2952.         mov    word ptr DecDigits[18], ax
  2953.         mov    word ptr DecDigits[20], ax
  2954.         mov    word ptr DecDigits[22], ax
  2955.         mov    DecExponent, 0
  2956.         mov    DecSign, ' '
  2957.         jmp    fpdDone
  2958. ;
  2959. ; If the number is not zero, first fix up the sign:
  2960. ;
  2961. fpdNotZero:    mov    DecSign, ' '        ;Assume it's postive
  2962.         cmp    fpacc.Sign, 0
  2963.         jns    WasPositive
  2964.         mov    DecSign, '-'
  2965.         mov    fpacc.Sign, 0        ;Take ABS(fpacc).
  2966. ;
  2967. ; This conversion routine is fairly standard.  See Neil Graham's
  2968. ; "Microprocessor Programming for Computer Hobbyists" for the gruesome
  2969. ; details.  Basically, it first gets the number between 1 & 10 by successively
  2970. ; multiplying (or dividing) by ten.  For each multiply by 10 this code
  2971. ; decrements DecExponent by one.  For each division by ten this code
  2972. ; increments DecExponent by one.  Upon getting the value between 1 & 10
  2973. ; DecExponent contains the integer equivalent of the exponent.  The
  2974. ; following code does this.
  2975. ;
  2976. ; Note: if the value falls between 1 & 10, then the exponent portion of
  2977. ;    fpacc will lie between 7fffh and 8002h.
  2978. ;
  2979. WasPositive:    mov    DecExponent, 0        ;Initialize exponent.
  2980. ;
  2981. ; Quick test to see if we're already less than 10.
  2982. ;
  2983. WhlBgrThan10:    cmp    fpacc.Exponent, 8002h    ;See if fpacc > 10
  2984.         jb    WhlLessThan1
  2985.         ja    IsGtrThan10
  2986. ;
  2987. ; If the exponent is equal to 8002h, then we could have a number in the
  2988. ; range 8 <= n < 16.  Let's ignore values less than 10.
  2989. ;
  2990.         cmp    byte ptr fpacc.Mantissa [7], 0a0h
  2991.         jb    WhlLessThan1
  2992. ;
  2993. ; If it's bigger than ten we could perform successive divisions by ten.
  2994. ; This, however, would be slow, inaccurate, and disgusting.  The following
  2995. ; loop skips through the positive powers of ten (PotTblP) until it finds
  2996. ; someone with an exponent *less* than fpacc.  Upon finding such a value,
  2997. ; this code divides fpacc by the corresponding entry in PotTblN.  This is
  2998. ; equivalent to *dividing* by the entry in PotTblP.  Note: this code only
  2999. ; compares exponents.  Therefore, it is quite possible that we will divide
  3000. ; by a number slightly larger than fpacc (since the mantissa of the table
  3001. ; entry could be larger than the mantissa of fpacc while their exponents
  3002. ; are equal).  This will produce a result slightly less than one.  This is
  3003. ; okay in this case because the code which handles values between 0 & 1
  3004. ; follows and will correct this oversight.
  3005. ;
  3006. IsGtrThan10:    mov    bx, -13            ;Index into PotTblP
  3007.         mov    ax, fpacc.Exponent
  3008. WhlBgrLp1:    add    bx, 13
  3009.         cmp    ax, PotTblP [bx] + 8    ;Compare exponent values.
  3010.         jb    WhlBgrLp1        ;Go to next entry if less.
  3011. ;
  3012. ; Okay, we found the first table entry whose exponent is less than or
  3013. ; equal to the fpacc exponent.  Multiply by the corresonding PotTblN
  3014. ; value here (which simulates a divide).
  3015. ;
  3016.         call    nTbl2FPOP
  3017.         mov    ax, PotTblP [bx] + 11    ;Adjust DecExponent
  3018.         add    DecExponent, ax
  3019.         call    sl_fMUL            ;Divide by appropriate power.
  3020.         mov    ax, fpacc.Exponent
  3021.         cmp    ax, 8002h        ;See if fpacc > 10
  3022.         jae    WhlBgrLp1
  3023. ;
  3024. ;
  3025. ; Once we get the number below 10 (or if it was below 10 to begin with,
  3026. ; drop down here and boost it up to the point where it is >= 1.
  3027. ;
  3028. ; This code is similar to the above-  It successively multiplies by 10
  3029. ; (actually, powers of ten) until the number is in the range 1..10.
  3030. ; This code is not as sloppy as the code above because we don't have any
  3031. ; code below this to clean up the sloppiness.  Indeed, this code has to
  3032. ; be careful because it is cleaning up the sloppiness of the code above.
  3033. ;
  3034. ;
  3035. WhlLessThan1:    cmp    fpacc.Exponent, 7fffh    ;See if fpacc < 1
  3036.         jae    NotLessThan1
  3037. ;
  3038.         mov    bx, -13            ;Index into PotTblN
  3039. WhlLessLp2:    mov    ax, fpacc.Exponent
  3040. WhlLessLp1:    add    bx, 13
  3041.         cmp    ax, PotTblN [bx] + 8    ;Compare exponent values.
  3042.         ja    WhlLessLp1        ;Go to next entry if less.
  3043. ;
  3044. ; Okay, we found the first table entry whose exponent is greater than or
  3045. ; equal to the fpacc exponent.  Unlike the code above, we cannot simply
  3046. ; multiply by the corresponding entry in PotTblP at this point.  If the
  3047. ; exponents were equal, we need to compare the mantissas and make sure we're
  3048. ; not multiplying by a table entry which is too large.
  3049. ;
  3050.         jne    OkayToMultiply
  3051. ;
  3052. ; If the exponents are the same, we need to compare the mantissas.  The
  3053. ; table entry cannot be larger than fpacc;  if it is, we'll wind up with
  3054. ; an endless loop oscillating between a couple of values.
  3055. ;
  3056.         mov    ax, fpacc.Mantissa [6]
  3057.         cmp    ax, PotTblN [bx] + 6
  3058.         ja      WhlLessLp2
  3059.         jb    OkayToMultiply
  3060.         mov    ax, fpacc.Mantissa [4]
  3061.         cmp    ax, PotTblN [bx] + 4
  3062.         ja    WhlLessLp2
  3063.         jb    OkayToMultiply
  3064.         mov    ax, fpacc.Mantissa [2]
  3065.         cmp    ax, PotTblN [bx] + 2
  3066.         ja    WhlLessLp2
  3067.         jb    OkayToMultiply
  3068.         mov    ax, fpacc.Mantissa [0]
  3069.         cmp    ax, PotTblN [bx]
  3070.         ja    WhlLessLp2
  3071. ;
  3072. ;
  3073. OkayToMultiply:    call    pTbl2FPOP
  3074.         mov    ax, PotTblN [bx] + 11    ;Adjust DecExponent
  3075.         add    DecExponent, ax
  3076.         call    sl_fMUL            ;Multiply by appropriate power.
  3077.         jmp    WhlLessThan1        ;Repeat till in range 1..10.
  3078. ;
  3079. ;
  3080. ; The above code tries to get fpacc in the range 1 <= n < 10.
  3081. ; However, it doesn't quite accomplish this.  In fact, it gets the value
  3082. ; into the range 1 <= n < 16.  This next section checks to see if the value
  3083. ; is greater than ten.  If it is, it does one more division by ten.
  3084. ;
  3085. NotLessThan1:    cmp    fpacc.Exponent, 8002h    ;10..15 only if exp = 8002h.
  3086.         jb    Not10_15
  3087. ;
  3088. ; For fpacc to be in the range 10..15 the mantissa must be greater than or
  3089. ; equal to 0A000 0000 0000 0000.
  3090. ;
  3091.         cmp    byte ptr fpacc.Mantissa [7], 0a0h
  3092.         jb    Not10_15
  3093. ;
  3094. ; Okay, the mantissa is greater than or equal to ten.  Divide by ten once
  3095. ; more to fix this up.
  3096. ;
  3097.         lea    bx, stdgrp:Div10Value
  3098.         sub    bx, offset stdgrp:PotTblN
  3099.         call    pTbl2FPOP
  3100.         call    sl_fMUL            ;Multiply by appropriate power.
  3101.         inc    DecExponent
  3102. ;
  3103. ; Well, we've managed to compute the decimal exponent value and normalize
  3104. ; the number to the range 1 <= n < 10.
  3105. ;
  3106. ; Make sure the upper four bits contain a BCD value.  This may entail
  3107. ; shifting data to the right.
  3108. ;
  3109. Not10_15:    mov    si, fpacc.Mantissa [0]    ;We'll use these a lot, so
  3110.         mov    di, fpacc.Mantissa [2]    ; put them into registers.
  3111.         mov    cx, fpacc.Mantissa [4]
  3112.         mov    dx, fpacc.Mantissa [6]
  3113. SHRLp:        cmp    fpacc.Exponent, 8002h
  3114.         jae    PossiblyRound
  3115.         shr    dx, 1
  3116.         rcr    cx, 1
  3117.         rcr    di, 1
  3118.         rcr    si, 1
  3119.         inc    fpacc.Exponent
  3120.         jmp     SHRLp
  3121. ;
  3122. ; May have to round the number if we wound up with a value between 10..15.
  3123. ;
  3124. ; Note: 0.5 e -18 is 7fc5 b8xxxxxxxx...   If we adjust this value so that
  3125. ;    the exponent is 7fffh, we keep only the top five bits (10111).  The
  3126. ;    following code adds this value (17h) to the mantiss to round as
  3127. ;    appropriate.
  3128. ;
  3129. PossiblyRound:    add    si, 2h
  3130.         jnc    ChkTooBig
  3131.         inc    di
  3132.         jnz    ChkTooBig
  3133.         inc    cx
  3134.         jnz    ChkTooBig
  3135.         inc    dx
  3136. ;
  3137. ; If we fall through to this point, it's quite possible that we will produce
  3138. ; a value greater than or equal to ten.  Handle that possibility here.
  3139. ;
  3140. ChkTooBig:    cmp    dh, 0a0h
  3141.         jb    NoOvrflw
  3142. ;
  3143. ; Well, overflow occurred, clean it up.
  3144. ;
  3145.         xor    ax, ax
  3146.         mov    si, ax
  3147.         mov    di, ax
  3148.         mov    cx, ax
  3149.         mov    dx, 1000h
  3150.         inc    DecExponent
  3151. ;
  3152. ; Finally!  We're at the point where we can start stripping off the
  3153. ; digits from the number
  3154. ;
  3155. NoOvrflw:    lea    bx, stdgrp:DecDigits
  3156.         xor    ax, ax
  3157. ;
  3158. StripDigits:    mov    al, dh
  3159.         shr    ax, 1
  3160.         shr    ax, 1
  3161.         shr     ax, 1
  3162.         shr    ax, 1
  3163.         or    al, '0'
  3164.         mov    [bx], al
  3165.         inc    bx
  3166.         cmp    bx, offset stdgrp:DecDigits+18
  3167.         jae    fpdDone
  3168. ;
  3169. ; Remove the digit we just stripped:
  3170. ;
  3171.         and    dh, 0fh
  3172. ;
  3173. ; Multiply the mantissa by ten (using shifts and adds):
  3174. ;
  3175.         shl    si, 1
  3176.         rcl    di, 1
  3177.         rcl    cx, 1
  3178.         rcl    dx, 1
  3179.         mov    fpacc.Mantissa [0], si    ;Save *2
  3180.         mov    fpacc.Mantissa [2], di
  3181.         mov    fpacc.Mantissa [4], cx
  3182.         mov    fpacc.Mantissa [6], dx
  3183. ;
  3184.         shl    si, 1            ;*4
  3185.         rcl    di, 1
  3186.         rcl    cx, 1
  3187.         rcl    dx, 1
  3188. ;
  3189.         shl    si, 1            ;*8
  3190.         rcl    di, 1
  3191.         rcl    cx, 1
  3192.         rcl    dx, 1
  3193. ;
  3194.         add    si, fpacc.Mantissa [0]    ;*10
  3195.         adc    di, fpacc.Mantissa [2]
  3196.         adc    cx, fpacc.Mantissa [4]
  3197.         adc    dx, fpacc.Mantissa [6]
  3198.         jmp     StripDigits
  3199. ;
  3200. fpdDone:        pop    si
  3201.         pop    di
  3202.         pop    dx
  3203.         pop    cx
  3204.         pop    bx
  3205.         pop    ax
  3206.         pop    ds
  3207.         ret
  3208. FPDigits    endp
  3209. ;
  3210. ;
  3211. ;
  3212. ; nTbl2FPOP- BX is an index into PotTbln.  This routine fetches the entry
  3213. ;         at that index and copies it into FPOP.
  3214. ;
  3215. nTbl2FPOP    proc    near
  3216.         mov    ax, PotTbln [bx] + 8
  3217.         mov    fpop.Exponent, ax
  3218.         mov    ax, PotTbln [bx]
  3219.         mov    fpop.Mantissa [0], ax
  3220.         mov    ax, PotTbln [bx] + 2
  3221.         mov    fpop.Mantissa [2], ax
  3222.         mov    ax, PotTbln [bx] + 4
  3223.         mov    fpop.Mantissa [4], ax
  3224.         mov    ax, PotTbln [bx] + 6
  3225.         mov    fpop.Mantissa [6], ax
  3226.         mov    fpop.Sign, 0        ;All entries are positive.
  3227.         ret
  3228. nTbl2FPOP    endp
  3229. ;
  3230. ; pTbl2FPOP- Same as above except the data comes from PotTblP.
  3231. ;
  3232. pTbl2FPOP    proc    near
  3233.         mov    ax, PotTblp [bx] + 8
  3234.         cmp    ax, 7fffh
  3235.         jne    DoPTFPOP
  3236.         sub    bx, 13            ;Special case if we hit 1.0
  3237.         mov    ax, PotTblp [bx] + 8
  3238. ;
  3239. DoPTFPOP:    mov    fpop.Exponent, ax
  3240.         mov    ax, PotTblp [bx]
  3241.         mov    fpop.Mantissa [0], ax
  3242.         mov    ax, PotTblp [bx] + 2
  3243.         mov    fpop.Mantissa [2], ax
  3244.         mov    ax, PotTblp [bx] + 4
  3245.         mov    fpop.Mantissa [4], ax
  3246.         mov    ax, PotTblp [bx] + 6
  3247.         mov    fpop.Mantissa [6], ax
  3248.         mov    fpop.Sign, 0        ;All entries are positive.
  3249.         ret
  3250. pTbl2FPOP    endp
  3251. ;
  3252. ;
  3253. ;
  3254. ;
  3255. ;
  3256. ;----------------------------------------------------------------------------
  3257. ;           Text => Floating Point (Input) Conversion Routines
  3258. ;----------------------------------------------------------------------------
  3259. ;
  3260. ;
  3261. ; ATOF-        ES:DI points at a string containing (hopefully) a numeric
  3262. ;        value in floating point format.  This routine converts that
  3263. ;        value to a number and puts the result in fpacc.  Allowable
  3264. ;        strings are described by the following regular expression:
  3265. ;
  3266. ;        {" "}* {+ | -} ( ([0-9]+ {"." [0-9]*}) | ("." [0-9]+)}
  3267. ;                {(e | E) {+ | -} [0-9] {[0-9]*}}
  3268. ;
  3269. ; "{}" denote optional items.
  3270. ; "|"  denotes OR.
  3271. ; "()" groups items together.
  3272. ;
  3273. ;
  3274. shl64        macro
  3275.         shl    bx, 1
  3276.         rcl    cx, 1
  3277.         rcl    dx, 1
  3278.         rcl    si, 1
  3279.         endm
  3280. ;
  3281.         public    sl_ATOF
  3282. sl_ATOF        proc    far
  3283.         assume    ds:StdGrp, es:nothing
  3284. ;
  3285.         push    ds
  3286.         push    ax
  3287.         push    bx
  3288.         push    cx
  3289.         push    dx
  3290.         push    si
  3291.         push    di
  3292.         push    bp
  3293. ;
  3294.         mov    ax, StdGrp
  3295.         mov    ds, ax
  3296. ;
  3297. ;
  3298. ; First, skip any leading spaces:
  3299. ;
  3300.         mov    ah, " "
  3301. SkipBlanks:    mov    al, es:[di]
  3302.         inc    di
  3303.         cmp    al, ah
  3304.         je    SkipBlanks
  3305. ;
  3306. ; Check for + or -.
  3307. ;
  3308.         cmp    al, "-"
  3309.         jne    TryPlusSign
  3310.         mov    fpacc.Sign, 80h
  3311.         jmp    EatSignChar
  3312. ;
  3313. TryPlusSign:    mov    fpacc.Sign, 0        ;If not "-", then positive.
  3314.         cmp    al, "+"
  3315.         jne    NotASign
  3316. EatSignChar:    mov    al, es:[di]        ;Get char beyond sign
  3317.         inc    di
  3318. ;
  3319. ; Init some important local vars:
  3320. ; Note: BP contains the number of significant digits processed thus far.
  3321. ;
  3322. NotASign:    mov    DecExponent, 0
  3323.         xor    bx, bx            ;Init 64 bit result.
  3324.         mov    cx, bx
  3325.         mov    dx, bx
  3326.         mov    si, bx
  3327.         mov    bp, bx
  3328.         mov    ah, bh
  3329. ;
  3330. ; First, eliminate any leading zeros (which do not count as significant
  3331. ; digits):
  3332. ;
  3333. Eliminate0s:    cmp    al, "0"
  3334.         jne    EndOfZeros
  3335.         mov    al, es:[di]
  3336.         inc    di
  3337.         jmp    Eliminate0s
  3338. ;
  3339. ; When we reach the end of the leading zeros, first check for a decimal
  3340. ; point.  If the number is of the form "0---0.0000" we need to get rid
  3341. ; of the zeros after the decimal point and not count them as significant
  3342. ; digits.
  3343. ;
  3344. EndOfZeros:    cmp    al, "."
  3345.         jne    WhileDigits
  3346. ;
  3347. ; Okay, the number is of the form ".xxxxx".  Strip all zeros immediately
  3348. ; after the decimal point.
  3349. ;
  3350. Right0s:    mov    al, es:[di]
  3351.         inc    di
  3352.         cmp    al, "0"
  3353.         jne    FractionPart
  3354.         dec    DecExponent        ;Not significant digit, but
  3355.         jmp    Right0s            ; affects exponent.
  3356. ;
  3357. ;
  3358. ; If the number is of the form "yyy.xxxx" (where y <> 0) then process it
  3359. ; down here.
  3360. ;
  3361. WhileDigits:    sub    al, "0"
  3362.         cmp    al, 10
  3363.         jae    NotADigit
  3364. ;
  3365. ; See if we've processed more than 19 sigificant digits:
  3366. ;
  3367.         cmp    bp, 19            ;Too many significant digits?
  3368.         jae    DontMergeDig
  3369. ;
  3370. ; Multiply value in (si, dx, cx, bx) by ten:
  3371. ;
  3372.         shl64
  3373.         mov    fpacc.Mantissa [0], bx
  3374.         mov    fpacc.Mantissa [2], cx
  3375.         mov    fpacc.Mantissa [4], dx
  3376.         mov    fpacc.Mantissa [6], si
  3377.         shl64
  3378.         shl64
  3379.         add    bx, fpacc.Mantissa [0]
  3380.         adc    cx, fpacc.Mantissa [2]
  3381.         adc    dx, fpacc.Mantissa [4]
  3382.         adc    si, fpacc.Mantissa [6]
  3383. ;
  3384. ; Add in current digit:
  3385. ;
  3386.         add    bx, ax
  3387.         jnc     GetNextDig
  3388.         inc    cx
  3389.         jne    GetNextDig
  3390.         inc    dx
  3391.         jne    GetNextDig
  3392.         inc    si
  3393.         jmp    GetNextDig
  3394. ;
  3395. DontMergeDig:    inc    DecExponent
  3396. GetNextDig:    inc    bp            ;Yet another significant dig.
  3397.         mov    al, es:[di]
  3398.         inc    di
  3399.         jmp    WhileDigits
  3400. ;
  3401. ;
  3402. ; Check to see if there is a decimal point here:
  3403. ;
  3404. NotADigit:    cmp    al, "."-"0"
  3405.         jne    NotADecPt
  3406.         mov    al, es:[di]
  3407.         inc    di
  3408. ;
  3409. ; Okay, process the digits to the right of the decimal point here.
  3410. ;
  3411. FractionPart:    sub    al, "0"
  3412.         cmp    al, 10
  3413.         jae    NotADecPt
  3414. ;
  3415. ; See if we've processed more than 19 sigificant digits:
  3416. ;
  3417.         cmp    bp, 19            ;Too many significant digits?
  3418.         jae    DontMergeDig2
  3419. ;
  3420. ; Multiply value in (si, dx, cx, bx) by ten:
  3421. ;
  3422.         dec    DecExponent        ;Raise by a power of ten.
  3423.         shl64
  3424.         mov    fpacc.Mantissa [0], bx
  3425.         mov    fpacc.Mantissa [2], cx
  3426.         mov    fpacc.Mantissa [4], dx
  3427.         mov    fpacc.Mantissa [6], si
  3428.         shl64
  3429.         shl64
  3430.         add    bx, fpacc.Mantissa [0]
  3431.         adc    cx, fpacc.Mantissa [2]
  3432.         adc    dx, fpacc.Mantissa [4]
  3433.         adc    si, fpacc.Mantissa [6]
  3434. ;
  3435. ; Add in current digit:
  3436. ;
  3437.         add    bx, ax
  3438.         jnc     DontMergeDig2
  3439.         inc    cx
  3440.         jne    DontMergeDig2
  3441.         inc    dx
  3442.         jne    DontMergeDig2
  3443.         inc    si
  3444. ;
  3445. DontMergeDig2:    inc    bp            ;Yet another significant dig.
  3446.         mov    al, es:[di]
  3447.         inc    di
  3448.         jmp    FractionPart
  3449. ;
  3450. ; Process the exponent down here
  3451. ;
  3452. NotADecPt:    cmp    al, "e"-"0"
  3453.         je    IsExponent
  3454.         cmp    al, "E"-"0"
  3455.         jne    NormalizeInput
  3456. ;
  3457. ; Okay, we just saw the "E" character, now read in the exponent value
  3458. ; and add it into DecExponent.
  3459. ;
  3460. IsExponent:    mov    ExpSign, 0        ;Assume positive exponent.
  3461.         mov    al, es:[di]
  3462.         inc    di
  3463.         cmp    al, "+"
  3464.         je    EatExpSign
  3465.         cmp    al, "-"
  3466.         jne    ExpNotNeg
  3467.         mov    ExpSign, 1        ;Exponent is negative.
  3468. EatExpSign:    mov    al, es:[di]
  3469.         inc    di
  3470. ExpNotNeg:    xor    bp, bp
  3471. ExpDigits:      sub    al, '0'
  3472.         cmp    al, 10
  3473.         jae    EndOfExponent
  3474.         shl    bp, 1
  3475.         mov    TempExp, bp
  3476.         shl    bp, 1
  3477.         shl    bp, 1
  3478.         add    bp, TempExp
  3479.         add    bp, ax
  3480.         mov    al, es:[di]
  3481.         inc    di
  3482.         jmp    ExpDigits
  3483. ;
  3484. EndOfExponent:    cmp    ExpSign, 0
  3485.         je    PosExp
  3486.         neg    bp
  3487. PosExp:        add    DecExponent, bp
  3488. ;
  3489. ; Normalize the number here:
  3490. ;
  3491. NormalizeInput:    mov    ax, si            ;See if they entered zero.
  3492.         or    ax, bx
  3493.         or    ax, cx
  3494.         or    ax, dx
  3495.         jnz    ItsNotZero
  3496.         jmp    ItsZero
  3497. ;
  3498. ItsNotZero:    mov    ax, si
  3499.         mov    si, 7fffh+63        ;Exponent if already nrm'd.
  3500. NrmInp16:    or    ax, ax            ;See if we can shift 16 bits.
  3501.         jnz    NrmInp8
  3502.         mov    ax, dx
  3503.         mov    dx, cx
  3504.         mov    cx, bx
  3505.         xor    bx, bx
  3506.         sub    si, 16
  3507.         jmp    NrmInp16
  3508. ;
  3509. NrmInp8:    cmp    ah, 0
  3510.         jne    NrmInp1
  3511.         mov    ah, al
  3512.         mov    al, dh
  3513.         mov    dh, dl
  3514.         mov    dl, ch
  3515.         mov    ch, cl
  3516.         mov    cl, bh
  3517.         mov    bh, bl
  3518.         mov    bl, 0
  3519.         sub    si, 8
  3520. ;
  3521. NrmInp1:    cmp    ah, 80h
  3522.         jae    NrmDone
  3523.         shl    bx, 1
  3524.         rcl    cx, 1
  3525.         rcl    dx, 1
  3526.         rcl    ax, 1
  3527.         dec    si
  3528.         jmp    NrmInp1
  3529. ;
  3530. ; Okay, the number is normalized.  Now multiply by 10 the number of times
  3531. ; specified in DecExponent.  Obviously, this uses the power of ten tables
  3532. ; to speed up this operation (and make it more accurate).
  3533. ;
  3534. NrmDone:    mov    fpacc.Exponent, si    ;Save away the value so far.
  3535.         mov    fpacc.Mantissa [0], bx
  3536.         mov    fpacc.Mantissa [2], cx
  3537.         mov    fpacc.Mantissa [4], dx
  3538.         mov    fpacc.Mantissa [6], ax
  3539. ;
  3540.         mov    bx, -13            ;Index into POT table.
  3541.         mov    si, DecExponent
  3542.         or    si, si            ;See if negative
  3543.         js    NegExpLp
  3544. ;
  3545. ; Okay, the exponent is positive, handle that down here.
  3546. ;
  3547. PosExpLp:    add    bx, 13            ;Find the 1st power of ten
  3548.         cmp    si, PotTblP [bx] + 11    ; in the table which is
  3549.         jb    PosExpLp        ; just less than this guy.
  3550.         cmp    PotTblP [bx] + 8, 7fffh    ;Hit 1.0 yet?
  3551.         je    MulExpDone
  3552. ;
  3553.         sub    si, PotTblP [bx] + 11    ;Fix for the next time through.
  3554.         call    PTbl2FPOP        ;Load up current power of ten.
  3555.         call    sl_FMUL            ;Multiply by this guy.
  3556.         jmp    PosExpLp
  3557. ;
  3558. ;
  3559. ; Okay, the exponent is negative, handle that down here.
  3560. ;
  3561. NegExpLp:    add    bx, 13            ;Find the 1st power of ten
  3562.         cmp    si, PotTblN [bx] + 11    ; in the table which is
  3563.         jg    NegExpLp        ; just less than this guy.
  3564.         cmp    PotTblN [bx] + 8, 7fffh    ;Hit 1.0 yet?
  3565.         je    MulExpDone
  3566. ;
  3567.         sub    si, PotTblN [bx] + 11    ;Fix for the next time through.
  3568.         call    NTbl2FPOP        ;Load up current power of ten.
  3569.         call    sl_FMUL            ;Multiply by this guy.
  3570.         jmp    NegExpLp
  3571. ;
  3572. ; If the user entered zero, drop down here and zero out fpacc.
  3573. ;
  3574. ItsZero:    xor    ax, ax
  3575.         mov    fpacc.Exponent, ax
  3576.         mov    fpacc.Sign, al
  3577.         mov    fpacc.Mantissa [0], ax
  3578.         mov    fpacc.Mantissa [2], ax
  3579.         mov    fpacc.Mantissa [4], ax
  3580.         mov    fpacc.Mantissa [6], ax
  3581. ;
  3582. ; Round the result to produce a *halfway* decent number
  3583. ;
  3584. MulExpDone:     cmp    fpacc.Exponent, 0ffffh        ;Don't round if too big.
  3585.         je    atofDone
  3586.         shl    byte ptr fpacc.Mantissa, 1    ;Use L.O. bits as guard
  3587.         adc    byte ptr fpacc.Mantissa [1], 0    ; bits.
  3588.         jnc    atofDone
  3589.         inc    fpacc.Mantissa[2]
  3590.         jne    atofDone
  3591.         inc    fpacc.Mantissa[4]
  3592.         jne    atofDone
  3593.         inc    fpacc.Mantissa[6]
  3594.         jne    atofDone
  3595.         inc    fpacc.Exponent
  3596. ;
  3597. atofDone:    mov    byte ptr fpacc.Mantissa, 0
  3598.         pop    bp
  3599.         pop    di
  3600.         pop    si
  3601.         pop    dx
  3602.         pop    cx
  3603.         pop    bx
  3604.         pop    ax
  3605.         pop    ds
  3606.         ret
  3607. sl_ATOF        endp
  3608. ;
  3609. ;
  3610. stdlib        ends
  3611.         end
  3612.