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