home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / MISC / REC.ZIP / ATH86F.ASM next >
Encoding:
Assembly Source File  |  1986-02-07  |  23.1 KB  |  880 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. ;            ATH - Copyright (c) 1984
  18. ;            Universidad Autonoma de Puebla
  19. ;             All Rights Reserved
  20. ;
  21. ;            [Gerardo Cisneros, 25 April 1984]
  22. ;
  23. ;    ==================================================================
  24. ;    15 Aug 1984 - Entry point for ^^ - GCS
  25. ;    29 Jul 1985 - Fix for % and sumd0 - GCS
  26. ;    ===============================================================
  27.  
  28. ;    (+) Add top two arguments on PDL: <a, b, +> leaves (a+b).
  29. ;    If arguments are of different length, the smaller one gets
  30. ;    promoted to the type of the larger one.  A null string is
  31. ;    treated as a zero.
  32. ;        arg size          result
  33. ;          0            null string
  34. ;          1             a <or> b
  35. ;          2              (a+b)mod(65536)
  36. ;          4              (a+b)mod(2**32)
  37. ;         5,8              (a+b)
  38.  
  39. sum:    call    twchk        ;fetch top into arg1, pointers of next
  40.     jcxz    sum0
  41. sum00:    mov    al,NSIZ
  42.     test    al,al
  43.     jnz    sum1
  44.     ret            ;top arg null, PDL has result
  45. sum0:    jmp    xfb        ;lower arg null, give arg1 as result
  46.  
  47. sum1:    cmp    al,cl        ;compare with size of lower arg
  48.     jz    sum2
  49.     call    cnv        ;promote smaller if different
  50. sum2:    cmp    al,1        ;is size 1?
  51.     jnz    suma
  52.     mov    al,ARG1H    ;yes, do logical or
  53.     or    al,[bx]
  54.     mov    [bx],al
  55.     ret
  56.  
  57. suma:    cmp    al,5        ;FP arguments?
  58.     jnc    sumb
  59.     mov    ax,0713H    ;no, set up integer sum (adc ax,[bx])
  60. suma0:    mov    cs:word ptr suma2,ax
  61.     mov    bp,bx        ;low byte of arg left on PDL
  62.     mov    bx,(offset ARGHH)    ;next to high byte of top arg
  63.     sub    bx,cx        ;minus length gives pointer to LSbyte
  64.     shr    cx,1        ;compute by words
  65.     clc
  66. suma1:    mov    ax,ds:[bp]    ;get word from low arg
  67. suma2    dw    0000        ;add/subtract word from top arg
  68.     mov    ds:[bp],ax    ;replace on PDL
  69.     inc    bp        ;continue to next word
  70.     inc    bp
  71.     inc    bx        ;on both arguments
  72.     inc    bx
  73.     loop    suma1        ;until done
  74.     ret
  75.  
  76. sumb:    mov    di,(offset arg2)    ;clear arg2
  77.     call    zarg
  78.     mov    cl,NSIZ        ;reload size into count reg.
  79.     mov    si,dx        ;PY to source index
  80.     call    mduc        ;move lower arg to arg2
  81.     call    unpak        ;unpack arg1
  82.     jc    sumb0a
  83.     ret            ;done if top=0, result is on PDL
  84. sumb0a: mov    al,DXSG        ;save top's sign before unpacking arg2
  85.     mov    byte ptr DCXPT,al
  86.     mov    word ptr BINXPT,dx    ;save arg1's exponent too
  87.     mov    bx,(offset arg2h)    ;point to arg2's high byte
  88.     call    unpk1        ;use unpak's alternate entry
  89.     pushf
  90.     mov    al,byte ptr DCXPT    ;retrieve sgn(top)
  91.     rcl    al,1        ;put signs together
  92.     mov    al,DXSG
  93.     rcr    al,1        ;[sgn(top), sgn(next)]
  94.     and    al,0C0H        ;mask rest off
  95.     mov    DXSG,al
  96.     mov    word ptr DCXPT,0000    ;clear dec. expt. before proceeding
  97.     popf            ;get flags back
  98.     jnc    sumd        ;pack arg1 up as result if arg2=0
  99.     mov    ax,word ptr BINXPT
  100.     sub    ax,dx        ;expt(top)-expt(next)
  101.     pushf
  102.     push    ax
  103.     js    sumb0b
  104.     call    xarg        ;put arg with smaller expt in arg1
  105. sumb0b: pop    ax
  106.     popf
  107.     jns    sumb1
  108.     mov    word ptr BINXPT,dx    ;larger of exponents for result
  109.     neg    ax        ;get abs(expt. difference)
  110. sumb1:    cmp    byte ptr NSIZ,8
  111.     jz    sumc
  112.     cmp    ax,32        ;31 bits max shifts to align points
  113.     jmp    short sumb0
  114. sumc:    cmp    ax,52        ;51 max shifts for DP
  115. sumb0:    jnc    sumd0        ;if more required, we're done
  116.     mov    dl,al        ;shift count to DL
  117.     call    shrc        ;else shift right smaller (DL) bits
  118.     mov    al,DXSG        ;decide whether to add or subtract
  119.     test    al,al
  120.     jpo    subt        ;signs different means subtract
  121.     call    add8        ;otherwise add
  122.     jnc    sumd        ;done if no carry from the addition
  123.     call    halve        ;else shift one down
  124.     add    byte ptr ARG1H,80H    ;and set the bit from the carry
  125.     inc    word ptr BINXPT    ;reflect the shift in the exponent
  126.     jmp    short sumd        ;pack it up
  127.  
  128. subt:    call    xarg        ;exchange args, indicate sign of (next)
  129.     call    sub8        ;get difference of mantissas
  130.     jnc    subt0        ;wrap it up if no leftmost borrow
  131.     call    cop        ;else result will have opposite sign
  132.     call    zarg1
  133.     call    sub8        ;subtract arg1 from 0
  134.     not    byte ptr DXSG    ;and invert sign
  135. subt0:    call    zach        ;check if arg1=0
  136.     jnz    sumd        ;pack it up if non-null
  137.     jmp    xfb        ;return NSIZ null bytes if null 
  138.  
  139. sumd0:    mov    si,(offset arg2)    ;move arg2 to arg1
  140.     mov    di,(offset arg1)
  141.     mov    cx,8
  142.     call    xf1
  143.     sal    byte ptr DXSG,1        ;move its sign, too
  144. sumd:    mov    dx,word ptr BINXPT    ;pack arg1 up
  145.     jmp    peb2
  146.  
  147. ;    (-) Subtract top from next: <a, b, -> leaves (a-b).
  148. ;    Reverse subtraction can be accomplished by exchanging
  149. ;    arguments: write <a, b, &, -> to get (b-a).
  150. ;    If arguments are of different length, the smaller one gets
  151. ;    promoted to the type of the larger one.  A null string is
  152. ;    treated as a zero.
  153. ;        arg size          result
  154. ;          0            null string
  155. ;          1             a <xor> b
  156. ;          2              (a-b)mod(65536)
  157. ;          4              (a-b)mod(2**32)
  158. ;         5,8               (a-b)
  159.  
  160. dif:    call    twchk    ;put top arg in arg1, get pointers to lower arg
  161.     test    cl,cl
  162.     jnz    difa    ;is lower arg 0?
  163.     call    xfb    ;yes, leave top arg as result,
  164.     cmp    byte ptr NSIZ,1
  165.     jbe    dif0
  166.     jmp    comp    ;but in negated form if size 2 bytes or longer
  167. dif0:    ret
  168.  
  169. difa:    mov    al,NSIZ        ;is top arg null?
  170.     test    al,al
  171.     jnz    difa0
  172.     ret            ;yes, leave lower one as result
  173. difa0:    cmp    al,cl        ;no, compare its size with the lower one's
  174.     jz    difa1
  175.     call    cnv        ;and make them of equal type if needed
  176. difa1:    cmp    al,1        ;if size is one
  177.     jnz    difb
  178.     mov    al,arg1h    ;do logical xor
  179.     xor    al,[bx]
  180.     mov    [bx],al
  181.     ret
  182.  
  183. difb:    cmp    al,5        ;FP args?
  184.     jnc    difb0
  185.     mov    ax,071BH    ;prepare for integers (sbb ax,[bx])
  186.     jmp    suma0        ;no, use loop at sum for integers
  187.  
  188. difb0:    mov    bx,word ptr arg1b    ;yes, invert sign of top operand
  189.     test    bx,bx        ;if it isn't 0
  190.     jnz    difb1
  191.     ret            ;(return if top is zero)
  192. difb1:    xor    byte ptr ARG1H,80H    ;invert high bit of high byte
  193.     jmp    sumb        ;and use code at sum
  194.  
  195. ;    (*) Multiply top two arguments on PDL: <a, b, *> leaves (a*b).
  196. ;    If arguments are of different lengths, the smaller one gets
  197. ;    promoted to the type of the larger one. A null string is treated
  198. ;    as a 0.
  199. ;            arg size          result
  200. ;            0            null string
  201. ;            1             a <and> b
  202. ;            2              (a*b)mod(2**16)
  203. ;            4              (a*b)mod(2**32)
  204. ;            5,8               (a*b)
  205.  
  206. mpy:    call    twchk    ;get top and pointers to next
  207.     jcxz    mpy0
  208.     mov    al,NSIZ
  209.     test    al,al
  210.     jnz    mpy1
  211.     jmp    zres1    ;return a 0 if top is the null string
  212. mpy1:    cmp    al,cl
  213.     jz    mpy2
  214.     call    cnv    ;promote smaller if not same size
  215. mpy2:    cmp    al,1
  216.     jnz    mpya
  217.     mov    al,arg1h    ;do logical op if size is 1
  218.     and    al,[bx]
  219.     mov    [bx],al
  220.     ret
  221. mpy0:    jmp    zres0    ;return a 0 if lower is the null string
  222.  
  223. mpya:    cmp    al,4
  224.     jnc    mpyb
  225.     mov    ax,word ptr ARG1B    ;2-byte integer prod here
  226.     mul    word ptr [bx]
  227.     mov    [bx],ax
  228.     ret
  229.  
  230. mpyb:    cmp    al,5
  231.     jnc    mpyc
  232.     mov    si,(offset ARG1M)    ;4-byte integers done here
  233.     mov    di,(offset ARG2)    ;move factor to lower 4 of arg2 
  234.     mov    cx,4
  235.     call    xf1        ;4-byte integers done here
  236.     call    zarg1        ;factor in arg2, zero in arg1
  237.     mov    dx,20H        ;32 shifts needed
  238. pr3:    mov    cx,2        ;number of words
  239.     call    twi0    ;shift arg1 left
  240.     mov    cx,2
  241.     mov    bx,PX
  242.     call    twi1    ;shift lower factor left
  243.     jnc    pr3a
  244.     mov    cx,2
  245.     call    adda        ;add top factor to arg1 if bit shifted out
  246. pr3a:    dec    dx
  247.     jnz    pr3
  248.     mov    si,(offset ARG1M)
  249.     jmp    xfb1        ;get number back from arg1 when done
  250.  
  251. mpyc:    mov    di,(offset arg2)    ;floating point products done here
  252.     call    zarg
  253.     call    unpak        ;unpack top
  254.     jc    mpyc1
  255.     jmp    zres0        ;leave 0 if top is zero
  256. mpyc1:    call    mpdv        ;else unpack other and add exponents
  257.     mov    si,PX        ;low byte of unpacked other
  258.     inc    si        ;was shifted once by unpk1
  259.     mov    al,NSIZ
  260.     dec    al        ;number of mantissa bytes
  261.     mov    dl,al        ;into DL
  262. pr4:    cld
  263.     lodsb            ;examine next byte of factor on PDL
  264.     test    al,al
  265.     jnz    pr5
  266.     call    shrby        ;shift partial product a full byte if zero
  267.     jmp    short pr7
  268. pr5:    mov    cx,8        ;else shift and add according to 1s in A
  269. pr6:    push    cx
  270.     rcr    al,1
  271.     mov    dh,al        ;save A in C
  272.     jnc    pr6a
  273.     call    add8        ;add other factor if there was a 1
  274. pr6a:    mov    bx,(offset arg1h)
  275.     call    halvc        ;shift partial prod down one bit with carry
  276.     mov    al,dh        ;retrieve A
  277.     pop    cx        ;retrieve counters
  278.     loop    pr6
  279. pr7:    dec    dl        ;count mantissa bytes
  280.     jnz    pr4
  281.     jmp    sumd        ;go pack up result
  282.  
  283. ;    (/)  Divide top: <a,b,/> leaves rem(a/b), int(a/b).
  284. ;    Reverse division is possible by exchanging arguments;
  285. ;    thus <b,a,&,/> leaves rem(b/a), int(b/a).  If just
  286. ;    the remainder is required, write <a,b,/,L>, while if
  287. ;    only the quotient is desired, write <a,b,/,&,L>, and
  288. ;    finally, if the order of the remainder and quotient is
  289. ;    not satisfactory, they can be exchanged.  The division
  290. ;    is unsigned integer division.  It can also be used to
  291. ;    split a two-byte word into two parts through division
  292. ;    by the corresponding power of two.
  293. ;    Floating point divisions leave only the quotient.
  294.  
  295. dvd:    call    twchk        ;check top two args
  296.     test    cl,cl
  297.     jnz    dvd0        ;leave two zeros if lower is null
  298.     call    zres0
  299.     mov    cx,PY
  300.     sub    cx,PX
  301.     cmp    cl,5        ;only one zero if dividend is F.P.
  302.     jc    dvd0a
  303.     ret
  304. dvd0a:    call    narg
  305.     mov    al,cl
  306.     jmp    zres0
  307.  
  308. dvd0:    mov    al,NSIZ
  309.     cmp    al,cl
  310.     jz    dvd1
  311.     call    cnv        ;else make sure both are same length
  312. dvd1:    cmp    al,1
  313.     jnz    dvda
  314.     call    ip        ;promote one byte arg to 2 bytes
  315.     mov    bx,(offset arg1h)    ;shift down byte at arg1
  316.     mov    ah,[bx]
  317.     xor    al,al
  318.     mov    [bx],al        ;and make the upper byte zero
  319.     dec    bx
  320.     mov    [bx],ah
  321.     mov    bx,PX        ;run into dvda with appropriate A and HL
  322. dvda:    cmp    al,4
  323.     jnc    dvdb
  324.     cmp    word ptr ARG1B,0000    ;divisor
  325.     jz    der
  326.     mov    ax,[bx]
  327.     mov    dx,0000        ;32-byte dividend
  328.     div    word ptr ARG1B
  329.     mov    [bx],dx        ;remainder
  330.     mov    bp,ax
  331.     mov    cx,0002
  332.     call    narg        ;close argument, open new
  333.     mov    [bx],bp        ;quotient
  334.     add    bx,cx
  335.     mov    PY,bx
  336.     ret
  337. der:    call    RER
  338.  
  339. dvdb:    cmp    al,5
  340.     jc    dvdba
  341.     jmp    dvdc
  342. dvdba:    mov    al,ARG1H    ;save sign of divisor
  343.     mov    DXSG,al
  344.     test    al,al        ;and complement if negative
  345.     jns    dvdb0
  346.     mov    bx,(offset ARG1M)
  347.     mov    cx,4
  348.     call    ngn1
  349. dvdb0:    call    cop    ;copy divisor to arg2
  350.     call    zarg1    ;clear arg1
  351.     mov    cx,2
  352.     mov    bx,(offset arg2)
  353.     mov    bp,(offset arg2m)
  354.     call    subc    ;subtract divisor from 0 (high end)
  355.     mov    bx,PY
  356.     mov    al,-1[bx]        ;save sign of dividend
  357.     mov    byte ptr DCXPT,al    ;separately to give sign of remainder
  358.     xor    DXSG,al        ;and combined with sign of divisor
  359.     mov    si,bx        ;prepare pointer for transfer
  360.     test    al,al
  361.     jns    dvdb1
  362.     mov    bx,PX
  363.     mov    cx,4
  364.     call    ngn1    ;and complement dividend if negative
  365. dvdb1:    mov    di,(offset arg1m)    ;point to middle of arg1
  366.     mov    cx,4    ;set counter for mduc
  367.     call    mduc    ;and copy numerator to lower half of arg1
  368.     mov    dh,20H    ;32 shifts at most
  369. qn4:    call    twice    ;shift arg1 left
  370.     mov    bx,(offset arg1m)
  371.     mov    cx,2
  372.     call    addb    ;add arg2 to arg1 (high 4)
  373.     jnc    qn5    ;undo if denominator didn't fit
  374.     inc    (byte ptr ARG1)        ;else add one at LSbit of quotient
  375.     jmp    short qn6
  376. qn5:    mov    bx,(offset arg1m) 
  377.     mov    bp,(offset arg2m)    ;positive copy of divisor
  378.     mov    cx,2
  379.     call    addc    ;undo previous subtraction
  380. qn6:    dec    dh    ;shift count
  381.     jnz    qn4
  382.     mov    di,PY    ;arg1 will be split into 2 4-byte values
  383.     mov    si,(offset arghh)
  384.     mov    cx,4
  385.     call    mduc    ;move remainder to the PDL
  386.     mov    al,byte ptr DCXPT    ;get sign of numerator
  387.     test    al,al
  388.     jns    dvdb2
  389.     call    comp    ;and complement remainder if numerator was <0
  390. dvdb2:    call    rarg    ;redo pointers
  391.     mov    cx,4
  392.     add    bx,cx    ;add 4 to HL, which contains px
  393.     mov    PY,bx
  394.     mov    di,bx
  395.     mov    si,(offset ARG1M)    ;point to middle of arg1
  396.     call    mduc    ;put quotient on the PDL
  397.     mov    al,DXSG    ;get sign of quotient
  398.     test    al,al
  399.     jns    dvdb3
  400.     call    comp    ;and complement if necessary
  401. dvdb3:    ret
  402.  
  403. overf:    call    ovf    ;make a large number at arg1
  404.     call    peb3    ;and move it to the PDL
  405.     call    rer    ;but record error also
  406.  
  407. dvdc:    mov    di,(offset arg2)    ;floating point division starts here
  408.     call    zarg    ;by clearing arg2
  409.     call    unpak    ;unpack divisor at arg1
  410.     jnc    overf    ;and return largest value if divisor=0
  411.     neg    dx    ;else negate the divisor's exponent
  412.     inc    dx    ;and add1 to align points
  413.     call    mpdv    ;move divisor to arg2, 0 to arg1, unpack num
  414.     mov    bx,PX
  415.     cmp    byte ptr NSIZ,5
  416.     jnz    dvdc1
  417.     inc    bx
  418. dvdc1:    mov    cs:numr,bx
  419.     mov    cs:numr0,bx
  420.     mov    cs:numr1,bx
  421.     mov    al,8
  422.     sub    al,(byte ptr NSIZ)    ;offset of mantissa from arg1 or arg2
  423.     mov    ah,0
  424.     jz    dvdc2
  425.     inc    ax
  426. dvdc2:    mov    bx,(offset arg1)
  427.     add    bx,ax
  428.     mov    cs:quot,bx
  429.     mov    bx,(offset arg2)    ;and start of the divisor's mantissa
  430.     add    bx,ax
  431.     mov    cs:denr,bx
  432.     mov    cs:denr0,bx
  433.     mov    cl,NSIZ        ;compute number of mantissa words
  434.     mov    ch,0
  435.     shr    cx,1
  436.     mov    dh,ch
  437. qn7:    mov    dl,cl    ;and save in DL
  438.     dw    1E8DH    ;(lea bx,)
  439. numr    dw    0000
  440.     dw    2E8DH    ;(lea bp,)
  441. denr    dw    0000    ;space for start of divisor mantissa
  442.     call    subc    ;do a trial subtraction
  443.     mov    al,[bx]
  444.     sbb    al,ch
  445.     cmc
  446.     jc    qn8    ;do we have to undo the subtraction?
  447.     dw    1E8DH    ;(lea bx,)
  448. numr0    dw    0000    
  449.     dw    2E8DH    ;(lea bp,)
  450. denr0    dw    0000
  451.     mov    cl,dl    ;get a copy of mantissa byte count
  452.     call    addc    ;add divisor back
  453.     clc
  454.     jmp    short qn9
  455. qn8:    mov    [bx],al
  456.     inc    dh    ;indicate succesful subtraction in C
  457. qn9:    mov    al,arg1h    ;have we shifted a one into the MSbit?
  458.     inc    al
  459.     dec    al
  460.     jns    qn10    ;yes, we're done
  461.     jmp    sumd
  462. qn10:    nop
  463.     dw    1E8DH    ;(lea bx,) no, shift and loop
  464. quot    dw    0000
  465.     mov    cl,dl
  466.     call    tw1    ;shift the quotient left one bit
  467.     dw    1E8DH
  468. numr1    dw    0
  469.     mov    cl,dl
  470.     call    tw1    ;shift the dividend left one bit
  471.     rcl    byte ptr [bx],1    ;shift also into the next byte up
  472.     mov    cl,dl    ;get counters ready for next iteration
  473.     test    dh,dh
  474.     jnz    qn7
  475.     dec    word ptr BINXPT    ;adjust expt if we shifted w/ no subtraction
  476.     jmp    short qn7
  477.  
  478. ;    Routine to unpack second argument and add exponents
  479. ;    in floating point multiplication and division
  480.  
  481. mpdv:    mov    word ptr BINXPT,dx    ;save exponent of multiplier/divisor
  482.     mov    al,DXSG    ;save sign before
  483.     mov    byte ptr DCXPT,al    ;unpacking lower arg
  484.     call    xarg    ;move multiplier/divisor to arg2 and 0 to arg1
  485.     mov    bx,PY    ;pointer
  486.     mov    (byte ptr[bx]),ch    ;clear high byte +1 of numerator
  487.     dec    bx        ; to high byte of multiplicand/dividend
  488.     call    unpk1        ;which we proceed to unpack
  489.     jc    mpdv0
  490.     pop    bp        ;remove return address
  491.     jmp    zres0        ;in case we have 0 mult/dividend
  492. mpdv0:    add    dx,word ptr BINXPT        ;add exponents together
  493.     mov    word ptr BINXPT,dx    ;save them
  494.     mov    bx,(offset DCXPT)
  495.     xor    al,al        ;clear DCXPT
  496.     mov    cl,[bx]        ;but not before retrieving saved sign
  497.     mov    [bx],al
  498.     inc    bx
  499.     mov    [bx],al
  500.     inc    bx        ;now we're pointing at DXSG
  501.     xor    [bx],cl        ;into which we combine the other sign
  502.     ret            ;and we're done here
  503.  
  504. ;    (N) Numerical comparison of top two elements on PDL. <a,b,N>
  505. ;    is true if a .LE. b; both arguments are erased irrespective
  506. ;    of the result.  Assuming numerical arguments means they are
  507. ;    two byte integers in the machine representation of addresses.
  508. ;    In the case of single byte arguments, their logical AND is
  509. ;    calculated, but they are both popped from the pushdown list.
  510. ;    N is FALSE if the AND is zero, meaning that if the bit tested
  511. ;    in one argument by using the other as a mask was zero, then
  512. ;    N failed.
  513.  
  514. ucn:    call    twchk    ;verify size of args
  515.     mov    al,NSIZ
  516.     cmp    al,cl
  517.     jz    ucn0
  518.     call    cnv    ;make sizes equal
  519. ucn0:    test    al,al
  520.     jz    un0    ;TRUE if both null
  521. ucn1:    cmp    al,01    ;TEST one-byte arguments
  522.     jnz    un2
  523. un1:    mov    al,ARG1H    ;TEST
  524.     and    al,[bx]
  525.     jnz    un0
  526.     jmp    ucl        ;false
  527. un0:    jmp    cucl        ;true
  528.  
  529. un2:    cmp    al,4
  530.     jnc    un3
  531.     mov    ax,word ptr ARG1B    ;low byte of argument at arg1
  532.     sub    ax,[bx]
  533.     jnc    un2a
  534.     jmp    ucl        ;false, pdl.gt.arg1 
  535. un2a:    jmp    cucl        ;true, pdl.le.arg1
  536.  
  537. un3:    call    difb
  538.     mov    bx,PY
  539.     dec    bx
  540.     dec    bx
  541.     mov    ax,[bx]        ;test hi bytes
  542.     test    ax,ax
  543.     js    un4
  544.     dec    bx
  545.     dec    bx
  546.     or    ax,[bx]        ;get next two lower bytes
  547.     jz    un4
  548.     jmp    ucl        ;lift and FALSE if strictly positive
  549. un4:    jmp    cucl        ;lift and TRUE if minus or zero
  550.  
  551. ;    (^) Increment the top of the PDL. A null string causes a
  552. ;    noop.  Other arguments cause a '+' operation to be performed
  553. ;    with a 1 of the proper size
  554.  
  555. intw:    call    incr        ;Entry point for ^^
  556.  
  557. incr:    call    numchk
  558.     test    cl,cl
  559.     jnz    incr0
  560.     ret        ;leave null strings alone
  561. incr0:    call    uno    ;put a one in arg1
  562.     jmp    sum00    ;add it to the top
  563.  
  564. ;    (d) False and lift if zero, otherwise decrement and exit true.
  565. ;    Always false on null strings; a one of the proper type is
  566. ;    subtracted in all other cases
  567.  
  568. decr:    call    numchk
  569.     test    cl,cl
  570.     jnz    dec0
  571.     jmp    ucl    ;Lift and exit FALSE if null
  572. dec0:    mov    dl,cl    ;save size of operand
  573.     xor    al,al
  574.     mov    ch,al
  575. dec1:    or    al,(byte ptr[bx])    ;jam operand bytes into A
  576.     inc    bx
  577.     loop    dec1
  578.     or    al,al
  579.     jnz    dec2
  580.     jmp    ucl    ;Lift and exit false if zero
  581. dec2:    mov    cl,dl    ;else restore size
  582.     call    uno    ;make a one in arg1
  583.     call    difa    ;subtract it
  584.     jmp    skp    ;and take the TRUE exit
  585.  
  586. ;    Make a one in arg1
  587.  
  588. uno:    mov    NSIZ,cl
  589.     mov    dl,cl
  590.     call    zarg1
  591.     cmp    dl,5
  592.     jnc    unof
  593.     xor    dh,dh    ;compute address of byte
  594.     neg    dx    ;to receive the integer 1
  595.     mov    bx,(offset arghh)
  596.     add    bx,dx
  597.     mov    (byte ptr[bx]),1    ;store it
  598.     jmp    short uno2
  599.  
  600. unof:    jnz    unod    ;decide whether SP or DP
  601.     mov    bx,03F80H
  602.     jmp    short uno1
  603. unod:    mov    bx,03FF0H
  604. uno1:    mov    word ptr arg1b,bx    ;upper two bytes of arg1
  605. uno2:    mov    bx,PX        ;redo pointers to top of PDL
  606.     mov    cx,PY
  607.     mov    dx,cx
  608.     sub    cx,bx
  609.     ret
  610.  
  611. ;    (%) Convert numeric argument to next smaller type. DP=>SP may
  612. ;    produce overflow or underflow. SP=>4-byte integer is done by
  613. ;    dropping the fraction, truncating the integer part modulo (2**32)
  614. ;    and negating if the original was less than 0.  4-byte=>2-byte and
  615. ;    2-byte=>1-byte are done by truncating mod(2**16) and mod(2**8)
  616. ;    respectively.  The null string produces a noop.
  617.  
  618. pe:    call    numchk    ;verify that argument is indeed numeric
  619.     jz    peflt    ;distinguish FP argument
  620.     test    cl,cl
  621.     jnz    pe0a
  622.     ret        ;leave null strings in peace
  623. pe0a:    shr    cl,1    ;else an integer, leave half of original
  624.     add    bx,cx    ;add to px
  625.     mov    py,bx    ;store as new limit of argument
  626.     ret
  627.  
  628. peflt:    mov    NSIZ,cl    ;save current size
  629.     call    dsinit    ;clear number buffers
  630.     mov    si,dx
  631.     mov    di,(offset arghh)    ;set dest. addr
  632.     mov    cl,NSIZ    ;restore byte count
  633.     call    mduc    ;transfer from PDL to arg1
  634.     call    unpak    ;separate sign, exponent and mantissa
  635.     jc    pea    ;jump if argument is non-null
  636. pe0:    mov    al,NSIZ    ;produce 4-byte zero
  637.     dec    al
  638.     cmp    al,4    ;if not 4, its a 7 and we want 5
  639.     jnz    pe0b
  640.     jmp    zres
  641. pe0b:    sub    al,2
  642.     jmp    zres
  643.  
  644. pea:    cmp    byte ptr NSIZ,8
  645.     jz    peb    ;jump if DP=>SP
  646.     dec    dx    ;reduce exponent by one
  647.     js    pe0    ;no integer part if result negative
  648.     inc    dx    ;restored
  649.     sub    dx,32    ;integer overflow if expt ge 32
  650.     js    per    ;shift right if less than 32
  651.  
  652.     mov    ax,0FFFFH    ;set largest long integer (2**31 - 1)
  653.     mov    word ptr ARG1M,ax
  654.     shr    ax,1
  655.     mov    word ptr ARG1B,ax
  656.     jmp    short pesgn
  657.  
  658. per:    neg    dx    ;right shift
  659.     call    shrc    ;and shift right arg1 by count
  660.  
  661. pesgn:    mov    al,4    ;set size
  662.     mov    NSIZ,al
  663.     call    xfb    ;put operand on PDL
  664. pesg1:    mov    al,DXSG    ;check sign of original
  665.     test    al,al
  666.     jns    pesg2
  667.     jmp    comp    ;negate if original was negative
  668. pesg2:    ret
  669.  
  670. peb:    mov    al,5    ;size of final number
  671. peb1:    mov    NSIZ,al    ;saved
  672. peb2:    mov    cx,03FEH    ;add a bias
  673.     add    dx,cx    ;to the unpacked exponent
  674.     call    dnd3    ;repack it as SP or DP number
  675. peb3:    mov    al,NSIZ    ;compute source address + 1
  676.     mov    cl,al    ;since dnd3 leaves result
  677.     mov    ch,0    ;at low end of arg1
  678.     mov    si,(offset arg1)
  679.     add    si,cx
  680.     call    xfb2    ;transfer from low end of arg1
  681.     jmp    pesg1    ;set the proper sign
  682.  
  683. ;    (\) Convert a numeric argument to the next higher type
  684.  
  685. ip:    call    numchk    ;ensure arg has size of a numeric type
  686.     jz    ipflt    ;go to ipflt if arg is FP
  687.     cmp    cl,4
  688.     jz    iplf    ;int to FP conv reqd for long integers
  689.     add    cl,cl    ;determine new size for 1 or 2-byte args
  690.     jnz    ip0
  691.     mov    (byte ptr[bx]),cl    ;clear a byte if arg was null string
  692.     inc    cl
  693. ip0:    call    OARG    ;check that space is available
  694.     mov    dx,bx    ;new py to DE
  695.     mov    bx,PY    ;old py to HL
  696.     clc
  697.     rcr    cl,1    ;bytes to clear
  698.     jc    ip2    ;done if new arg has size 1
  699. ip1:    mov    (byte ptr[bx]),0
  700.     inc    bx
  701.     loop    ip1
  702. ip2:    mov    PY,dx    ;and save
  703.     ret
  704.  
  705. iplf:    inc    cl    ;make size 5
  706.     mov    NSIZ,cl
  707.     mov    frst,cl    ;preclude possibility of '-' in frst
  708.     call    dsinit    ;clear number buffers
  709.     xchg    bx,dx
  710.     mov    al,-1[bx]    ;get high byte
  711.     or    al,al    ;ascertain sign
  712.     jns    iplf1
  713.     call    comp    ;complement if negative and
  714.     mov    al,'-'    ;indicate a minus sign
  715.     mov    frst,al
  716. iplf1:    mov    cl,4    ;and reset number of bytes to move
  717.     mov    di,(offset arg1m)
  718.     mov    si,bx
  719.     call    mduc    ;transfer from PDL into low end of arg1
  720.     mov    cl,NSIZ    ;put size in BC
  721.     call    oarg    ;ane check that space is available
  722.     call    dsend    ;invoke assembly of FP numbers
  723.     mov    si,(offset arg1x)
  724.     jmp    xfb1    ;transfer from low end of arg1
  725.  
  726. ipflt:    cmp    cl,8
  727.     jnz    ipfl0
  728.     ret        ;leave DP arg in peace
  729. ipfl0:    mov    NSIZ,cl    ;record size
  730.     call    dsinit    ;clear number buffers
  731.     mov    di,(offset arghh)    ;set dest addr + 1
  732.     mov    si,dx
  733.     mov    cl,5    ;bytes to move
  734.     call    mduc    ;transfer from PDL
  735.     call    unpak    ;unpack sign, exponent and mantissa
  736.     mov    al,8    ;in case we go to zres
  737.     jnc    zres    ;go to zres if it was zero
  738.     jmp    peb1    ;else repack it as DP
  739.  
  740. ;    ---------------------------------------------------------------
  741. ;    Service routines for the preceding operators
  742. ;    ---------------------------------------------------------------
  743.  
  744. ;    Get top arg into arg1 and poinuers to lower arg into registers
  745. ;    Check also that both args are numeric
  746. ;    If succesful, numchk returns px in HL, py in DE, py-px in
  747. ;    BC and in A and zero flag on if arg is FP
  748.  
  749. twchk:    call    zarg1    ;clear number buffer
  750.     pop    ax    ;remove return address from stack
  751.     call    numchk    ;check top arg
  752.     mov    NSIZ,cl    ;save its size
  753.     mov    si,dx    ;PY as source pointer
  754.     mov    di,(offset arghh)    ;dest+1 to di
  755.     call    mduc    ;move by decrement until count
  756.     call    ucl    ;lift it from the PDL
  757.     call    numchk    ;check top arg
  758.     jmp    ax
  759.  
  760. ;    Transfer arg1 back on the PDL
  761.  
  762. xfb:    mov    si,(offset arghh)    ;source address + 1
  763. xfb1:    mov    al,NSIZ    ;get size
  764.     mov    cl,al    ;put it in BC
  765.     mov    ch,0
  766. xfb2:    mov    di,px    ;compute dest address + 1
  767.     add    di,cx
  768.     mov    py,di    ;and save it as end of argument
  769.     call    mduc    ;move by decrement until count
  770.     ret
  771.  
  772. ;    Return a zero of the proper size
  773.  
  774. zres0:    mov    cl,NSIZ
  775. zres1:    mov    al,cl
  776. zres:    mov    cl,al
  777.     mov    di,px
  778.     mov    ch,0    ;clear upper byte of count
  779.     jcxz    znul    ;done if nothing to move
  780.     call    zar1
  781. znul:    mov    py,di    ;keep py updated
  782.     ret
  783.  
  784. ;    Shift arg1 right one byte
  785.  
  786. shrby:    mov    bx,(offset arg1)
  787.     mov    bp,bx
  788.     inc    bp
  789.     mov    cx,7
  790. shrb1:    mov    al,ds:[bp]
  791.     mov    [bx],al
  792.     inc    bp
  793.     inc    bx
  794.     loop    shrb1
  795.     mov    [bx],ch    ;clear high byte
  796.     ret
  797.  
  798. ;    Convert to type of longer argument
  799.  
  800. cnv:    lahf
  801.     push    ax    ;save size and result of comparison
  802.     inc    dx    ;rebuild!top px and py
  803.     inc    dx
  804.     mov    px,dx    ;top px
  805.     mov    al,NSIZ    ;size of top
  806.     mov    cl,al
  807.     add    dx,cx
  808.     mov    py,dx    ;top py
  809.     pop    ax
  810.     sahf
  811.     pushf        ;retrieve but save again comparison flag
  812.     jc    cnv0
  813.     call    exch    ;exchange if lower smaller than upper
  814. cnv0:    call    ip    ;convert top to next bigger type
  815.     popf
  816.     jc    cnv1
  817.     call    exch    ;exchange back if necessary
  818. cnv1:    call    twchk    ;see if same size
  819.     mov    al,NSIZ
  820.     cmp    al,cl
  821.     jnz    cnv    ;repeat if not same size yet    
  822.     ret
  823.  
  824. ;    Subtract arg2 from arg1; leave result in arg1
  825.  
  826. sub8:    mov    cx,4
  827. subb:    mov    bp,(offset arg2)
  828.     mov    bx,(offset arg1)
  829. subc:    clc
  830. sb1:    mov    ax,[bx]
  831.     sbb    ax,ds:[bp]
  832.     mov    [bx],ax
  833.     inc    bx
  834.     inc    bx
  835.     inc    bp
  836.     inc    bp
  837.     loop    sb1
  838.     ret
  839.  
  840. ;    Exchange arg1 and arg2; exchange high bits of DXSG
  841.  
  842. xarg:    mov    bx,(offset arg1)
  843.     mov    bp,(offset arg2)
  844.     mov    cx,4
  845. xr1:    mov    ax,[bx]
  846.     xchg    ds:[bp],ax
  847.     mov    [bx],ax
  848.     inc    bx
  849.     inc    bx
  850.     inc    bp
  851.     inc    bp
  852.     loop    xr1
  853.     mov    al,DXSG
  854.     mov    cl,al
  855.     rcl    al,1
  856.     rcl    al,1
  857.     mov    al,cl
  858.     rcr    al,1
  859.     and    al,0C0H
  860.     mov    DXSG,al
  861.     ret
  862.  
  863. ;    Shift right arg1 by count in DL
  864.  
  865. shrc:    test    dl,dl
  866.     jnz    per0
  867.     ret        ;return immediately if count=0  
  868. per0:    mov    cl,dl
  869.     sub    dl,8
  870.     js    per0a    ;less than one byte to shift
  871.     call    shrby    ;no, shift a byte
  872.     jmp    short shrc
  873. per0a:    mov    dl,cl
  874. per1:    call    halve    ;shift right one bit
  875.     dec    dl
  876.     jnz    per1
  877.     ret
  878.  
  879. ;    end
  880.