home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MISC / REC.ZIP / ATH87.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-02-13  |  15.5 KB  |  716 lines

  1. ;    ===============================================================
  2. ;
  3. ;    REC module for the arithmetic operators.  These comprise:
  4. ;
  5. ;        + :    sum/logical or
  6. ;        - :    difference/exclusive or
  7. ;        * :    product/logical and
  8. ;        / :    remainder, quotient
  9. ;        ^ :    increment
  10. ;        d :    decrement, false on zero
  11. ;        N :    comparison, false if top greater
  12. ;        % :    convert to next smaller type
  13. ;        \ :    convert to next larger type
  14. ;
  15. ;    ---------------------------------------------------------------
  16. ;
  17. ;            ATH87 - Copyright (c) 1986
  18. ;            Universidad Autonoma de Puebla
  19. ;             All Rights Reserved
  20. ;
  21. ;            [Gerardo Cisneros, 25 April 1984]
  22. ;            [G. Cisneros, 6 February 1986]
  23. ;
  24. ;    ==================================================================
  25. ;    15 Aug 1984 - Entry point for ^^ - GCS
  26. ;    29 Jul 1985 - Fix for % and sumd0 - GCS
  27. ;    6 Feb 1986 - 8087 support - GCS
  28. ;    ===============================================================
  29.  
  30. ;    (+) Add top two arguments on PDL: <a, b, +> leaves (a+b).
  31. ;    If arguments are of different length, the smaller one gets
  32. ;    promoted to the type of the larger one.  A null string is
  33. ;    treated as a zero.
  34. ;        arg size          result
  35. ;          0            null string
  36. ;          1             a <or> b
  37. ;          2              (a+b)mod(65536)
  38. ;          4              (a+b)mod(2**32)
  39. ;         5,8              (a+b)
  40.  
  41. sum:    call    twchk        ;fetch top into arg1, pointers of next
  42.     jcxz    sum0
  43. sum00:    test    al,al
  44.     jnz    sum1
  45.     ret            ;top arg null, PDL has result
  46. sum0:    jmp    rtop        ;lower arg null, give arg1 as result
  47.  
  48. sum1:    cmp    al,cl        ;compare with size of lower arg
  49.     jz    sum2
  50.     call    cnv        ;promote smaller if different
  51. sum2:    cmp    al,2        ;is size 1?
  52.     jae    suma
  53.     mov    al,[si]        ;yes, do logical or
  54.     or    [bx],al
  55.     ret
  56.  
  57. suma:    ja    suml
  58.     mov    ax,[si]        ;no, add word integers
  59.     add    [bx],ax
  60.     ret
  61.  
  62. suml:    cmp    al,5
  63.     jae    sumf        ;keep going if F.P.
  64.     mov    ax,[si]
  65.     add    [bx],ax
  66.     mov    ax,2[si]
  67.     adc    2[bx],ax
  68.     ret
  69.  
  70. sumf:    ja    sumd
  71.     inc    si
  72.     inc    bx
  73. ;    fld    dword ptr [si]    ;load top
  74.     esc    08H,[si]
  75.     wait
  76. ;    fadd    dword ptr [bx]    ;add lower
  77.     esc    00H,[bx]
  78.     wait
  79. ;    fstp    dword ptr [bx]    ;store on PDL, pop 87 stack
  80.     esc    0BH,[bx]
  81.     wait
  82.     ret    
  83.  
  84. sumd:
  85. ;    fld    qword ptr [si]    ;load top
  86.     esc    28H,[si]
  87.     wait
  88. ;    fadd    qword ptr [bx]    ;add lower
  89.     esc    20H,[bx]
  90.     wait
  91. ;    fstp    qword ptr [bx]    ;store on PDL, pop 87 stack
  92.     esc    2BH,[bx]
  93.     wait
  94.     ret    
  95.  
  96. ;    (-) Subtract top from next: <a, b, -> leaves (a-b).
  97. ;    Reverse subtraction can be accomplished by exchanging
  98. ;    arguments: write <a, b, &, -> to get (b-a).
  99. ;    If arguments are of different length, the smaller one gets
  100. ;    promoted to the type of the larger one.  A null string is
  101. ;    treated as a zero.
  102. ;        arg size          result
  103. ;          0            null string
  104. ;          1             a <xor> b
  105. ;          2              (a-b)mod(65536)
  106. ;          4              (a-b)mod(2**32)
  107. ;         5,8               (a-b)
  108.  
  109. dif:    call    twchk    ;get pointers
  110.     jcxz    difa    ;is lower arg null?
  111.     test    al,al    ;no, is top null?
  112.     jnz    difa0
  113.     ret        ;yes, leave lower
  114.  
  115. difa:    call    rtop    ;lower null: leave top arg as result,
  116.     cmp    al,1
  117.     jbe    dif0
  118.     jmp    comp    ;but in negated form if size 2 bytes or longer
  119. dif0:    ret
  120.  
  121. difa0:    cmp    al,cl        ;no, compare its size with the lower one's
  122.     jz    difa1
  123.     call    cnv        ;and make them of equal type if needed
  124. difa1:    cmp    al,2        ;is size 1?
  125.     jae    difb
  126.     mov    al,[si]        ;yes, do logical xor
  127.     xor    [bx],al
  128.     ret
  129.  
  130. difb:    ja    difl
  131.     mov    ax,[si]        ;no, subtract word integers
  132.     sub    [bx],ax
  133.     ret
  134.  
  135. difl:    cmp    al,5
  136.     jae    diff        ;keep going if F.P.
  137. subc:    mov    ax,[si]        ;subtract dword at [si] from [bx]
  138.     sub    [bx],ax
  139.     mov    ax,2[si]
  140.     sbb    2[bx],ax
  141.     ret
  142.  
  143. diff:    ja    difd
  144.     inc    si
  145.     inc    bx
  146. ;    fld    dword ptr [bx]    ;load lower
  147.     esc    08H,[bx]
  148.     wait
  149. ;    fsub    dword ptr [si]    ;subtract top
  150.     esc    04H,[si]
  151.     wait
  152. ;    fstp    dword ptr [bx]    ;store on PDL, pop 87 stack
  153.     esc    0BH,[bx]
  154.     wait
  155.     ret    
  156.  
  157. difd:
  158. ;    fld    qword ptr [bx]    ;load lower
  159.     esc    28H,[bx]
  160.     wait
  161. ;    fsub    qword ptr [si]    ;subtract top
  162.     esc    24H,[si]
  163.     wait
  164. ;    fstp    qword ptr [bx]    ;store on PDL, pop 87 stack
  165.     esc    2BH,[bx]
  166.     wait
  167.     ret    
  168.  
  169. ;    (*) Multiply top two arguments on PDL: <a, b, *> leaves (a*b).
  170. ;    If arguments are of different lengths, the smaller one gets
  171. ;    promoted to the type of the larger one. A null string is treated
  172. ;    as a 0.
  173. ;            arg size          result
  174. ;            0            null string
  175. ;            1             a <and> b
  176. ;            2              (a*b)mod(2**16)
  177. ;            4              (a*b)mod(2**32)
  178. ;            5,8               (a*b)
  179.  
  180. mpy:    call    twchk    ;get top and pointers to next
  181.     jcxz    mpy0
  182.     test    al,al
  183.     jnz    mpy1
  184.     jmp    zres1    ;return a 0 if top is the null string
  185.  
  186. mpy0:    jmp    zres    ;return a 0 if lower is the null string
  187.  
  188. mpy1:    cmp    al,cl
  189.     jz    mpy2
  190.     call    cnv    ;promote smaller if not same size
  191. mpy2:    cmp    al,2
  192.     jae    mpya
  193.     mov    al,[si]    ;do logical op if size is 1
  194.     and    [bx],al
  195.     ret
  196.  
  197. mpya:    ja    mpyb
  198.     mov    ax,[si]    ;2-byte integer prod here
  199.     mul    word ptr [bx]
  200.     mov    [bx],ax
  201.     ret
  202.  
  203. mpyb:    cmp    al,5
  204.     jae    mpyc
  205.     mov    di,(offset ARG2)    ;move factor to lower 4 of arg2 
  206.     mov    cx,4
  207.     call    xf1        ;4-byte integers done here
  208.     call    zarg1        ;factor in arg2, zero in arg1
  209.     mov    dx,20H        ;32 shifts needed
  210. pr3:    mov    cx,2        ;number of words
  211.     call    twi0    ;shift arg1 left
  212.     mov    cx,2
  213.     mov    bx,PX
  214.     call    twi1    ;shift lower factor left
  215.     jnc    pr3a
  216.     mov    cx,2
  217.     call    adda        ;add top factor to arg1 if bit shifted out
  218. pr3a:    dec    dx
  219.     jnz    pr3
  220.     mov    si,(offset ARG1M)    ;back on the PDL
  221.     mov    cx,4
  222.     mov    di,py
  223.     mov    py,di
  224.     call    mduc
  225.     ret
  226.  
  227.  
  228. mpyc:    ja    mpyd
  229.     inc    bx
  230.     inc    si
  231. ;    fld    dword ptr [si]    ;load top
  232.     esc    08H,[si]
  233.     wait
  234. ;    fmul    dword ptr [bx]    ;multiply lower
  235.     esc    01H,[bx]
  236.     wait
  237. ;    fstp    dword ptr [bx]    ;store on PDL, pop 87 stack
  238.     esc    0BH,[bx]
  239.     wait
  240.     ret    
  241.  
  242. mpyd:
  243. ;    fld    qword ptr [si]    ;load top
  244.     esc    28H,[si]
  245.     wait
  246. ;    fmul    qword ptr [bx]    ;multiply lower
  247.     esc    21H,[bx]
  248.     wait
  249. ;    fstp    qword ptr [bx]    ;store on PDL, pop 87 stack
  250.     esc    2BH,[bx]
  251.     wait
  252.     ret    
  253.  
  254. ;    (/)  Divide top: <a,b,/> leaves rem(a/b), int(a/b).
  255. ;    Reverse division is possible by exchanging arguments;
  256. ;    thus <b,a,&,/> leaves rem(b/a), int(b/a).  If just
  257. ;    the remainder is required, write <a,b,/,L>, while if
  258. ;    only the quotient is desired, write <a,b,/,&,L>, and
  259. ;    finally, if the order of the remainder and quotient is
  260. ;    not satisfactory, they can be exchanged.  The division
  261. ;    is unsigned integer division.  It can also be used to
  262. ;    split a two-byte word into two parts through division
  263. ;    by the corresponding power of two.
  264. ;    Floating point divisions leave only the quotient.
  265.  
  266. dvd:    call    twchk        ;check top two args
  267.     test    cl,cl
  268.     jnz    dvd0        ;leave two zeros if lower is null
  269.     call    zres
  270.     mov    cx,PY
  271.     sub    cx,PX
  272.     cmp    cl,5        ;only one zero if dividend is F.P.
  273.     jc    dvd0a
  274.     ret
  275. dvd0a:    call    narg
  276.     jmp    zres1
  277.  
  278. dvd0:    cmp    al,cl
  279.     jz    dvd1
  280.     call    cnv        ;else make sure both are same length
  281. dvd1:    cmp    al,1
  282.     jnz    dvda
  283.     mov    1[si],ah    ;make upper bytes of both arguments zero
  284.     mov    1[bx],ah
  285.     inc    PY        ;update py and run into word-divide
  286. dvda:    cmp    al,4
  287.     jnc    dvdb
  288.     cmp    word ptr [si],0000    ;divisor
  289.     jz    der
  290.     mov    ax,[bx]
  291.     mov    dx,0000        ;32-byte dividend
  292.     div    word ptr [si]
  293.     mov    [bx],dx        ;remainder
  294.     mov    bp,ax
  295.     mov    cx,0002
  296.     call    narg        ;close argument, open new
  297.     mov    [bx],bp        ;quotient
  298.     add    bx,cx
  299.     mov    PY,bx
  300.     ret
  301. der:    call    RER
  302.  
  303. dvdb:    cmp    al,5
  304.     jb    dvdc
  305.     ja    divd
  306.     inc    si
  307.     inc    bx
  308. ;    fld    dword ptr [bx]    ;load lower
  309.     esc    08H,[bx]
  310.     wait
  311. ;    fdiv    dword ptr [si]    ;divide by top
  312.     esc    06H,[si]
  313.     wait
  314. ;    fstp    dword ptr [bx]    ;store on PDL, pop 87 stack
  315.     esc    0BH,[bx]
  316.     wait
  317.     ret    
  318.  
  319. divd:
  320. ;    fld    qword ptr [bx]    ;load lower
  321.     esc    28H,[bx]
  322.     wait
  323. ;    fdiv    qword ptr [si]    ;dividy by top
  324.     esc    26H,[si]
  325.     wait
  326. ;    fstp    qword ptr [bx]    ;store on PDL, pop 87 stack
  327.     esc    2BH,[bx]
  328.     wait
  329.     ret    
  330.  
  331. dvdc:    mov    al,[si]        ;save sign of divisor
  332.     mov    DXSG,al
  333.     test    al,al        ;and complement if negative
  334.     jns    dvdb0
  335.     mov    bx,si
  336.     mov    cx,4
  337.     call    ngn1
  338. dvdb0:    mov    di,(offset arg2m)
  339.     mov    cx,4
  340.     call    xf1
  341.     call    zarg1    ;clear arg1
  342.     mov    bx,(offset arg2)
  343.     mov    [bx],ax    ;clear high arg2
  344.     mov    2[bx],ax
  345.     mov    si,(offset arg2m)
  346.     call    subc    ;subtract divisor from 0 (high end)
  347.     mov    bx,PY
  348.     mov    al,-1[bx]        ;save sign of dividend
  349.     mov    byte ptr DCXPT,al    ;separately to give sign of remainder
  350.     xor    DXSG,al        ;and combined with sign of divisor
  351.     mov    si,bx        ;prepare pointer for transfer
  352.     test    al,al
  353.     jns    dvdb1
  354.     mov    bx,PX
  355.     mov    cx,4
  356.     call    ngn1    ;and complement dividend if negative
  357. dvdb1:    mov    di,(offset arg1m)    ;point to middle of arg1
  358.     mov    cx,4    ;set counter for mduc
  359.     call    mduc    ;and copy numerator to lower half of arg1
  360.     mov    dh,20H    ;32 shifts at most
  361. qn4:    call    twice    ;shift arg1 left
  362.     mov    bx,(offset arg1m)
  363.     mov    cx,2
  364.     call    addb    ;add arg2 to arg1 (high 4)
  365.     jnc    qn5    ;undo if denominator didn't fit
  366.     inc    (byte ptr ARG1)        ;else add one at LSbit of quotient
  367.     jmp    short qn6
  368. qn5:    mov    bx,(offset arg1m) 
  369.     mov    bp,(offset arg2m)    ;positive copy of divisor
  370.     mov    cx,2
  371.     call    addc    ;undo previous subtraction
  372. qn6:    dec    dh    ;shift count
  373.     jnz    qn4
  374.     mov    di,PY    ;arg1 will be split into 2 4-byte values
  375.     mov    si,(offset arghh)
  376.     mov    cx,4
  377.     call    mduc    ;move remainder to the PDL
  378.     mov    al,byte ptr DCXPT    ;get sign of numerator
  379.     test    al,al
  380.     jns    dvdb2
  381.     call    comp    ;and complement remainder if numerator was <0
  382. dvdb2:    call    rarg    ;redo pointers
  383.     mov    cx,4
  384.     add    bx,cx    ;add 4 to HL, which contains px
  385.     mov    PY,bx
  386.     mov    di,bx
  387.     mov    si,(offset ARG1M)    ;point to middle of arg1
  388.     call    mduc    ;put quotient on the PDL
  389.     mov    al,DXSG    ;get sign of quotient
  390.     test    al,al
  391.     jns    dvdb3
  392.     call    comp    ;and complement if necessary
  393. dvdb3:    ret
  394.  
  395.  
  396. ;    (N) Numerical comparison of top two elements on PDL. <a,b,N>
  397. ;    is true if a .LE. b; both arguments are erased irrespective
  398. ;    of the result.  Assuming numerical arguments means they are
  399. ;    two byte integers in the machine representation of addresses.
  400. ;    In the case of single byte arguments, their logical AND is
  401. ;    calculated, but they are both popped from the pushdown list.
  402. ;    N is FALSE if the AND is zero, meaning that if the bit tested
  403. ;    in one argument by using the other as a mask was zero, then
  404. ;    N failed.
  405.  
  406. ucn:    call    twchk    ;verify size of args
  407.     cmp    al,cl
  408.     jz    ucn0
  409.     call    cnv    ;make sizes equal
  410. ucn0:    test    al,al
  411.     jnz    ucn1
  412.     jmp    skp    ;TRUE if both null
  413. ucn1:    cmp    al,2    ;TEST one-byte arguments
  414.     jae    un2
  415. un1:    mov    al,[si]    ;TEST
  416.     and    al,[bx]
  417.     jnz    un0
  418.     jmp    ucl        ;false
  419. un0:    jmp    cucl        ;true
  420.  
  421. un2:    ja    un3
  422.     mov    ax,[si]
  423.     cmp    ax,[bx]
  424.     jnc    un2a
  425.     jmp    ucl        ;false, lower.gt.top
  426. un2a:    jmp    cucl        ;true, lower.le.top
  427.  
  428. un3:    call    difl
  429.     mov    bx,PY
  430.     dec    bx
  431.     dec    bx
  432.     mov    ax,[bx]        ;test hi bytes
  433.     test    ax,ax
  434.     js    un4
  435.     dec    bx
  436.     dec    bx
  437.     or    ax,[bx]        ;get next two lower bytes
  438.     jz    un4
  439.     jmp    ucl        ;lift and FALSE if strictly positive
  440. un4:    jmp    cucl        ;lift and TRUE if minus or zero
  441.  
  442. ;    (^) Increment the top of the PDL. A null string causes a
  443. ;    noop.  Other arguments cause a '+' operation to be performed
  444. ;    with a 1 of the proper size
  445.  
  446. intw:    call    incr        ;Entry point for ^^
  447.  
  448. incr:    call    numchk
  449.     cmp    cl,1
  450.     jae    incr0
  451.     ret        ;leave null strings alone
  452.  
  453. incr0:    ja    incr2
  454.     or    byte ptr [bx],1
  455.     ret
  456.  
  457. incr2:    cmp    cl,4
  458.     jae    incr3
  459.     inc    word ptr [bx]
  460.     ret
  461.  
  462. incr3:    ja    incr4
  463.     mov    cl,1
  464.     add    [bx],cx
  465.     mov    cl,0
  466.     adc    2[bx],cx
  467.     ret
  468.  
  469. incr4:
  470. ;    fld1
  471.     db    0D9H,0E8H
  472.     cmp    cl,5
  473.     wait
  474.     ja    incr5
  475.     inc    bx
  476. ;    fadd    dword ptr [bx]
  477.     esc    00H,[bx]
  478.     wait
  479. ;    fstp    dword ptr [bx]
  480.     esc    0BH,[bx]
  481.     wait
  482.     ret
  483.  
  484. incr5:
  485. ;    fadd    qword ptr [bx]
  486.     esc    20H,[bx]
  487.     wait
  488. ;    fstp    qword ptr [bx]    
  489.     esc    2BH,[bx]
  490.     wait
  491.     ret
  492.  
  493. ;    (d) False and lift if zero, otherwise decrement and exit true.
  494. ;    Always false on null strings; a one of the proper type is
  495. ;    subtracted in all other cases
  496.  
  497. decr:    call    numchk
  498.     test    cl,cl
  499.     jnz    dec0
  500.     jmp    ucl    ;Lift and exit FALSE if null
  501. dec0:    mov    dl,cl    ;save size of operand
  502.     xor    al,al
  503.     mov    ch,al
  504.     mov    si,bx
  505.     cmp    cl,5
  506.     jnz    dec1
  507.     inc    si
  508.     inc    bx
  509.     dec    cx
  510. dec1:    or    al,byte ptr[si]    ;jam operand bytes into A
  511.     inc    si
  512.     loop    dec1
  513.     or    al,al
  514.     jnz    dec2
  515.     jmp    ucl    ;Lift and exit false if zero
  516.  
  517. dec2:    mov    cl,dl    ;else restore size
  518.     cmp    cl,2
  519.     jae    decr2
  520.     xor    byte ptr [bx],1
  521.     jmp    skp
  522.  
  523. decr2:    ja    decr3
  524.     dec    word ptr [bx]
  525.     jmp    skp
  526.  
  527. decr3:    cmp    cl,5
  528.     jae    decr4
  529.     mov    cl,1
  530.     sub    [bx],cx
  531.     mov    cl,0
  532.     sbb    2[bx],cx
  533.     jmp    skp
  534.  
  535. decr4:
  536. ;    fld1
  537.     db    0D9H,0E8H
  538.     wait
  539.     ja    decr5
  540. ;    fsubr    dword ptr [bx]
  541.     esc    05H,[bx]
  542.     wait
  543. ;    fstp    dword ptr [bx]
  544.     esc    0BH,[bx]
  545.     wait
  546.     jmp    skp
  547.  
  548. decr5:
  549. ;    fsubr    qword ptr [bx]
  550.     esc    25H,[bx]
  551.     wait
  552. ;    fstp    qword ptr [bx]    
  553.     esc    2BH,[bx]
  554.     wait
  555.     jmp    skp
  556.  
  557. ;    (%) Convert numeric argument to next smaller type. DP=>SP may
  558. ;    produce overflow or underflow. SP=>4-byte integer is done by
  559. ;    dropping the fraction, truncating the integer part modulo (2**32)
  560. ;    and negating if the original was less than 0.  4-byte=>2-byte and
  561. ;    2-byte=>1-byte are done by truncating mod(2**16) and mod(2**8)
  562. ;    respectively.  The null string produces a noop.
  563.  
  564. pe:    call    numchk    ;verify that argument is indeed numeric
  565.     jz    peflt    ;distinguish FP argument
  566.     test    cl,cl
  567.     jnz    pe0a
  568.     ret        ;leave null strings in peace
  569. pe0a:    shr    cl,1    ;else an integer, leave half of original
  570.     add    bx,cx    ;add to px
  571.     mov    py,bx    ;store as new limit of argument
  572.     ret
  573.  
  574. peflt:    cmp    cl,5
  575.     ja    pe0
  576.     dec    PY
  577.     mov    si,offset ARG1
  578. ;    fstcw    [si]    ;copy current control word
  579.     esc    0FH,[si]
  580.     wait
  581. ;    fld    dword ptr 1[bx]
  582.     esc    08H,1[bx]
  583.     or    word ptr [si],0C00H
  584.     wait
  585. ;    fldcw    [si]    ;set chopping
  586.     esc    0DH,[si]
  587.     wait
  588. ;    fistp    dword ptr [bx]
  589.     esc    1BH,[bx]
  590.     and    word ptr [si],0F3FFH
  591.     wait
  592. ;    fldcw    [si]    ;set rounding to nearest
  593.     esc    0DH,[si]
  594.     wait
  595.     ret
  596.  
  597. pe0:
  598. ;    fld    qword ptr [bx]
  599.     esc    28H,[bx]
  600.     wait
  601.     inc    bx
  602. ;    fstp    dword ptr [bx]
  603.     esc    0BH,[bx]
  604.     mov    cl,4
  605.     add    bx,cx
  606.     mov    py,bx
  607.     wait
  608.     ret
  609.  
  610. ;    (\) Convert a numeric argument to the next higher type
  611.  
  612. ip:    call    numchk    ;ensure arg has size of a numeric type
  613.     jz    ipflt    ;go to ipflt if arg is FP
  614.     cmp    cl,4
  615.     jz    iplf    ;int to FP conv reqd for long integers
  616.     add    cl,cl    ;determine new size for 1 or 2-byte args
  617.     jnz    ip0
  618.     mov    (byte ptr[bx]),cl    ;clear a byte if arg was null string
  619.     inc    cl
  620. ip0:    call    OARG    ;check that space is available
  621.     mov    dx,bx    ;new py to DE
  622.     mov    bx,PY    ;old py to HL
  623.     clc
  624.     rcr    cl,1    ;bytes to clear
  625.     jc    ip2    ;done if new arg has size 1
  626. ip1:    mov    (byte ptr[bx]),0
  627.     inc    bx
  628.     loop    ip1
  629. ip2:    mov    PY,dx    ;and save
  630.     ret
  631.  
  632. iplf:
  633. ;    fild    dword ptr [bx]
  634.     esc    18H,[bx]
  635.     wait
  636.     inc    bx
  637. ;    fstp    dword ptr [bx]
  638.     esc    0BH,[bx]
  639.     inc    py    ;make size 5
  640.     wait
  641.     ret
  642.  
  643. ipflt:    cmp    cl,8
  644.     jnz    ipfl0
  645.     ret        ;leave DP arg in peace
  646. ipfl0:
  647. ;    fld    dword ptr 1[bx]
  648.     esc    08H,1[bx]
  649.     wait
  650. ;    fstp    qword ptr [bx]
  651.     esc    2BH,[bx]
  652.     mov    cl,8
  653.     add    bx,cx
  654.     mov    py,bx
  655.     wait
  656.     ret
  657.  
  658. ;    ---------------------------------------------------------------
  659. ;    Service routines for the preceding operators
  660. ;    ---------------------------------------------------------------
  661.  
  662. ;    Get top arg into arg1 and poinuers to lower arg into registers
  663. ;    Check also that both args are numeric
  664. ;    If succesful, numchk returns px in HL, py in DE, py-px in
  665. ;    BC and in A and zero flag on if arg is FP
  666.  
  667. twchk:    pop    bp    ;remove return address from stack
  668.     call    numchk    ;check top arg
  669.     mov    ax,cx    ;save its size
  670.     mov    si,bx    ;PX as source pointer
  671.     call    ucl    ;lift it from the PDL
  672.     call    numchk    ;check top arg
  673.     jmp    bp
  674.  
  675. ;    Return old top
  676.  
  677. rtop:    mov    PX,si    ;rebuild pointers
  678.     add    si,ax
  679.     mov    PY,si
  680.     jmp    XLFT
  681.  
  682. ;    Return a zero of the proper size
  683.  
  684. zres1:    mov    al,cl
  685. zres:    mov    cl,al
  686.     mov    di,px
  687.     mov    ch,0    ;clear upper byte of count
  688.     jcxz    znul    ;done if nothing to move
  689.     call    zar1
  690. znul:    mov    py,di    ;keep py updated
  691.     ret
  692.  
  693. ;    Convert to type of longer argument
  694.  
  695. cnv:    mov    cx,ax    ;size of old top
  696.     lahf
  697.     push    ax    ;save size and result of comparison
  698.     mov    px,si    ;top px
  699.     add    si,cx
  700.     mov    py,si    ;top py
  701.     pop    ax
  702.     sahf
  703.     pushf        ;retrieve but save again comparison flag
  704.     jc    cnv0
  705.     call    exch    ;exchange if lower smaller than upper
  706. cnv0:    call    ip    ;convert top to next bigger type
  707.     popf
  708.     jc    cnv1
  709.     call    exch    ;exchange back if necessary
  710. cnv1:    call    twchk    ;see if same size
  711.     cmp    al,cl
  712.     jnz    cnv    ;repeat if not same size yet    
  713.     ret
  714.  
  715. ;    end
  716.