home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / sources.exe / SOURCES / ASM / BIGMATH.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-12-22  |  15.8 KB  |  611 lines

  1. ;* BIGMATH.ASM
  2. ;************************************************************************
  3. ;*                                    *
  4. ;*        PC Scheme/Geneva 4.00 Borland TASM code            *
  5. ;*                                    *
  6. ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT        *
  7. ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva    *
  8. ;*                                    *
  9. ;*----------------------------------------------------------------------*
  10. ;*                                    *
  11. ;*        Bignum mathematical support                *
  12. ;*                                    *
  13. ;*----------------------------------------------------------------------*
  14. ;*                                    *
  15. ;* Created by: John Jensen        Date: 1985            *
  16. ;* Revision history:                            *
  17. ;* - 18 Jun 92:    Renaissance (Borland Compilers, ...)            *
  18. ;*                                    *
  19. ;*                    ``In nomine omnipotentii dei''    *
  20. ;************************************************************************
  21. IDEAL
  22. %PAGESIZE    60, 132
  23. MODEL    medium
  24. LOCALS    @@
  25.  
  26.     INCLUDE    "scheme.ash"
  27.  
  28. CODESEG
  29.  
  30. ;************************************************************************
  31. ;*            Convert a bignum to a flonum            *
  32. ;* Calling sequence: big2flo(bigptr,floptr)                *
  33. ;* Where bigptr:pointer to bignum workspace                *
  34. ;*    floptr:    pointer to flonum                    *
  35. ;************************************************************************
  36. P8087
  37. PROC C    big2flo USES si di, @@bignum, @@flonum
  38.     LOCAL    @@temp:QWORD, @@exponent:WORD
  39.     push    ds            ; assume es = ds
  40.     pop    es
  41.     cld
  42.     mov    si, [@@bignum]        ; Point ds:si to working bignum
  43.     mov    bx, [(BIGDATA si).len]
  44.     lea    si, [(BIGDATA si).lsw]
  45.     cmp    bx, 3
  46.     ja    @@atleast64bits
  47.     mov    cx, 4            ; to fill in gaps
  48.     lea    di, [@@temp]
  49.     movsw                ; get least sig. word in dx
  50.     dec    cx
  51.     dec    bx
  52.     jz    @@smalllong
  53.     movsw                ; get next least sig. word in di
  54.     dec    cx
  55.     dec    bx
  56.     jz    @@smalllong
  57.     movsw                ; Get 3rd least sig. word in bx
  58.     dec    cx
  59. @@smalllong:
  60.     xor    ax, ax
  61.     rep    stosw            ; wipe out the rest
  62.     fild    [@@temp]
  63.     jmp    @@storeback
  64.  
  65. @@atleast64bits:
  66.     shl    bx, 1            ; Point si to 4th most sig. word
  67.     sub    bx, TYPE QWORD        ; now bx is the size of what we discarded
  68.     add    si, bx
  69.     shl    bx, 1            ; get lost size in bits
  70.     shl    bx, 1
  71.     shl    bx, 1
  72.     test    [BYTE si+(TYPE QWORD)-1], 80h ; is most significant bit set ?
  73.     jz    @@noadjust        ; if so, shift in a couple a 0s
  74.     add    bx, 8            ; compensate for the 'filling' byte
  75.     inc    si
  76.     lea    di, [@@temp]
  77.     mov    cx, 7
  78.     rep    movsb
  79.     mov    [BYTE di], 0        ; clear most significant byte
  80.     lea    si, [@@temp]
  81. @@noadjust:
  82.     mov    [@@exponent], bx
  83.     fild    [@@exponent]        ; load the exponent
  84.     fild    [QWORD si]
  85.     fscale                ; 'idiosyncracy'
  86.     fstp    st(1)
  87. @@storeback:
  88.     mov    si, [@@bignum]
  89.     test    [(BIGDATA si).sign], 1
  90.     jz    @@positive
  91.     fchs
  92. @@positive:
  93.     mov    di, [@@flonum]
  94.     fstp    [QWORD di]
  95.     xor    ax, ax            ; Return 0: all well
  96.     ret
  97. ENDP    big2flo
  98.  
  99. ;************************************************************************
  100. ;*            Convert fixnum to bignum            *
  101. ;* Calling sequence: fix2big(fixnum,bigptr)                *
  102. ;* Where fixnum:Integer of small absolute value                *
  103. ;*    bigptr:    Pointer to bignum space                    *
  104. ;************************************************************************
  105. PROC C    fix2big USES si di, @@fixnum, @@bignum
  106.     mov    di, [@@bignum]
  107.     mov    [(BIGDATA di).len], 1
  108.     mov    ax, [@@fixnum]
  109.     xor    bx, bx
  110.     or    ax, ax
  111.     jns    @@positive
  112.     neg    ax
  113.     inc    bx
  114. @@positive:
  115.     mov    [(BIGDATA di).lsw], ax
  116.     mov    [(BIGDATA di).sign], bl
  117.     ret
  118. ENDP    fix2big
  119.  
  120. ;************************************************************************
  121. ;*            Compare magnitudes of two bignums        *
  122. ;* Calling sequence: data = magcomp(big1,big2)                *
  123. ;* Where big1,big2:pointers to bignum buffers                *
  124. ;*    data:    a positive integer as follows:                *
  125. ;*         Bit 0 set iff |BIG1| < |BIG2|                *
  126. ;*         Bit 1 set iff |BIG1| > |BIG2|                *
  127. ;*         Bit 2 set iff BIG1 < BIG2                *
  128. ;*         Bit 3 set iff BIG1 > BIG2                *
  129. ;*         Bit 4 set iff BIG1,BIG2 have same sign            *
  130. ;************************************************************************
  131. PROC C    magcomp USES si di, @@bignum1, @@bignum2
  132.     push    ds            ; assume es = ds
  133.     pop    es
  134.     xor    al, al            ; this is the result
  135.     xor    dx, dx
  136.     mov    si, [@@bignum1]
  137.     mov    di, [@@bignum2]
  138.     mov    ah, [(BIGDATA si).sign]
  139.     mov    dh, [(BIGDATA di).sign]
  140.     xor    dh, ah            ; Put XOR of signs into carry
  141.     shr    dh, 1
  142.     jc    @@signskip
  143.     or    al, 10h
  144. @@signskip:
  145.     rcl    ah, 1
  146.     mov    cx, [(BIGDATA si).len]
  147.     mov    dx, [(BIGDATA di).len]
  148.     cld
  149.     cmpsw
  150.     jb    @@bigger2
  151.     ja    @@bigger1
  152. @@samelength:
  153.     call    msw1            ; If same size, point si,di to last words
  154.     call    msw2            ; (most significant)
  155.     std
  156.     repe    cmpsw
  157.     jb    @@really2
  158.     ja    @@really1
  159.     test    ah, 1            ; Signs same?
  160.     jz    @@done
  161. @@differentsigns:
  162.     test    ah, 2            ; Is BIG1 positive?
  163.     jnz    @@greater2
  164.     jz    @@greater1
  165. @@bigger1:
  166.     call    msw1
  167.     cmp    [WORD si], 0        ; check high word
  168.     jne    @@really1
  169.     mov    si, [@@bignum1]        ; restore si
  170.     inc    si
  171.     inc    si
  172.     dec    cx            ; high order word is empty
  173.     cmp    cx, dx            ; compare length's again
  174.     je    @@samelength
  175.     jmp    @@bigger1
  176.  
  177. @@really1:
  178.     or    al, 2            ; Set the |BIG1|>|BIG2| bit
  179.     test    ah, 1            ; Signs same?
  180.     jnz    @@differentsigns
  181.     test    ah, 2            ; Both positive?
  182.     jnz    @@greater2
  183. @@greater1:
  184.     or    al, 8            ; Set the BIG1>BIG2 bit
  185.     jmp    @@done
  186.  
  187. @@bigger2:
  188.     push    cx
  189.     mov    cx, dx            ; swap cx and dx
  190.     pop    dx
  191.     call    msw2
  192.     cmp    [WORD di], 0        ; check high word
  193.     jne    @@really2
  194.     mov    di, [@@bignum2]        ; restore di
  195.     inc    di
  196.     inc    di
  197.     dec    cx            ; high order word is empty
  198.     cmp    dx, cx            ; compare length's again
  199.     je    @@samelength
  200.     jmp    @@bigger2
  201.  
  202. @@really2:
  203.     or    al, 1            ; Set the |BIG1|<|BIG2| bit
  204.     test    ah, 1            ; Signs same?
  205.     jnz    @@differentsigns
  206.     test    ah, 2            ; Both positive?
  207.     jnz    @@greater1
  208. @@greater2:
  209.     or    al, 4            ; Set the BIG1<BIG2 bit
  210. @@done:
  211.     cld                ; Set direction forward (JCJ-12/6/84)
  212.     ret
  213.  
  214. ; set up big1's index for comparison, used with magcomp
  215. PROC NOLANGUAGE    msw1    NEAR
  216.     shl    cx, 1
  217.     dec    si
  218.     add    si, cx
  219.     shr    cx, 1
  220.     ret
  221. ENDP    msw1
  222.  
  223. ; set up big2's index for comparison, used with magcomp
  224. PROC NOLANGUAGE    msw2    NEAR
  225.     shl    cx, 1
  226.     dec    di
  227.     add    di, cx
  228.     shr    cx, 1
  229.     ret
  230. ENDP    msw2
  231. ENDP    magcomp
  232.  
  233. ;************************************************************************
  234. ;*            Add magnitudes of bignums            *
  235. ;* Calling sequence: bigadd(big1,big2)                    *
  236. ;* Where big1:    bignum of lesser magnitude                *
  237. ;*    big2:    bignum of greater magnitude                *
  238. ;* When done, BIG2 will hold the sum                    *
  239. ;************************************************************************
  240. PROC C    bigadd USES si di, @@bignum1, @@bignum2
  241.     mov    si, [@@bignum1]
  242.     mov    di, [@@bignum2]
  243.     cld
  244.     lodsw                ; Get length of smaller bignum
  245.     mov    cx, ax            ; Save length
  246.     sub    ax, [(BIGDATA di).len]
  247.     neg    ax
  248.     push    ax
  249.     inc    si            ; Point si,di to bignums proper
  250.     lea    di, [(BIGDATA di).lsw]
  251.     clc                ; Prepare to add
  252. @@loop:
  253.     lodsw
  254.     adc    [WORD di], ax        ; Add to destination addend
  255.     inc    di            ; use INC to preserve carry !
  256.     inc    di            ; Point di to next word
  257.     loop    @@loop
  258.     pop    cx            ; Fetch length difference (CF unchanged)
  259.     jnc    @@done
  260.     mov    si, [@@bignum2]
  261.     jcxz    @@samelength
  262. @@carryloop:
  263.     inc    [WORD di]        ; Otherwise, add carry
  264.     jnz    @@done            ; Jump if no resultant carry
  265.     add    di, 2            ; Point di to next word
  266.     loop    @@carryloop
  267. @@samelength:
  268.     mov    [WORD di], 1        ; Store last carry
  269.     inc    [(BIGDATA si).len]
  270. @@done:
  271.     ret
  272. ENDP    bigadd
  273.  
  274. ;************************************************************************
  275. ;*            Subtract magnitudes of bignums            *
  276. ;* Calling sequence: bigsub(big1,big2)                    *
  277. ;* Where big1:    bignum of lesser magnitude                *
  278. ;*    big2 ---- bignum of greater magnitude                *
  279. ;* When done, BIG2 will hold the difference                *
  280. ;************************************************************************
  281. PROC C    bigsub USES si di, @@bignum1, @@bignum2
  282.     push    ds            ; assume es = ds
  283.     pop    es
  284.     mov    si, [@@bignum1]
  285.     mov    di, [@@bignum2]
  286.     cld
  287.     lodsw                ; Get length of smaller bignum
  288.     mov    cx, ax
  289.     inc    si            ; Point si,di to bignums proper
  290.     lea    di, [(BIGDATA di).lsw]
  291.     clc                ; Prepare to subtract
  292. @@loop:
  293.     lodsw
  294.     sbb    [WORD di], ax
  295.     inc    di            ; use INC to preserve carry !
  296.     inc    di            ; Point di to next word
  297.     loop    @@loop
  298.     jnc    @@pack
  299. @@borrowloop:
  300.     mov    ax, [WORD di]        ; Fetch word
  301.     sub    ax, 1            ; Decrement and store
  302.     stosw
  303.     jc    @@borrowloop
  304. @@pack:
  305.     mov    di, [@@bignum2]
  306.     mov    si, di            ; Save pointer in si
  307.     mov    ax, [(BIGDATA si).len]
  308.     mov    cx, ax            ; Save (length-1) in cx
  309.     dec    cx
  310.     shl    ax, 1            ; Point di to last word of bignum
  311.     inc    ax
  312.     add    di, ax
  313.     std                ; Direction backward
  314.     xor    ax, ax            ; Find number of leading 0-words
  315.     repz    scasw            ; (not counting least sig. word)
  316.     jz    @@smallskip
  317.     inc    cx            ; at least 2 non-0 words
  318. @@smallskip:
  319.     inc    cx            ; Form (length - # of leading 0-words)
  320.     mov    [(BIGDATA si).len], cx
  321.     cld                ; Clear the direction flag
  322.     ret
  323. ENDP    bigsub
  324.  
  325. ;************************************************************************
  326. ;*                Multiply two bignums            *
  327. ;* Calling sequence: bigmul(big1,big2,big3)                *
  328. ;* Where big1,big2:factors                        *
  329. ;*    big3:    destination of product                    *
  330. ;************************************************************************
  331. PROC C    bigmul USES si di, @@bignum1, @@bignum2, @@result
  332.     push    ds            ; assume es = ds
  333.     pop    es
  334.     cld
  335.     mov    si, [@@bignum1]
  336.     mov    di, [@@bignum2]
  337.     lodsw                ; Fetch BIG1's length
  338.     mov    cx, ax            ; Put sum of lengths in cx
  339.     add    cx, [(BIGDATA di).len]
  340.     scasw                ; Which has greater magnitude?
  341.     jnb    @@theyrokay
  342.     xchg    di, si
  343. @@theyrokay:
  344.     lodsb                ; Fetch one factor's sign
  345.     xor    al, [BYTE di]        ; XOR with the other factor's sign
  346.     inc    di            ; Point di to bignum proper
  347.     mov    bx, di
  348.     mov    di, [@@result]        ; Store length into product
  349.     xchg    ax, cx
  350.     stosw
  351.     push    ax            ; Save total length of product
  352.     xchg    ax, cx            ; Store sign byte into product
  353.     stosb
  354.     push    di            ; Set product to 0 over whole length
  355.     xor    ax, ax
  356.     rep    stosw
  357.     pop    di
  358.     xchg    di, bx            ; Restore bx and di
  359.     mov    cx, [di-3]        ; Fetch length of BIG2
  360.     sub    bx, si            ; Point [bx+si-2] to product
  361.     dec    bx
  362.     dec    bx
  363.     mov    [@@bignum1], si
  364. @@outer:
  365.     push    cx            ; Save counter of BIG2 words
  366. ; Add (BIG1*part of BIG2) to current product
  367.     mov    si, [@@bignum1]
  368.     mov    cx, [si-3]        ; Get number of words in bignum
  369.     push    bp
  370.     xor    bp, bp            ; our carry
  371. @@inner:
  372.     lodsw                ; Get factor part from BIG1
  373.     mul    [WORD di]
  374.     add    ax, bp
  375.     adc    dx, 0
  376.     add    [bx+si], ax        ; Add product part into BIG3
  377.     adc    dx, 0            ; Adjust and store carry
  378.     mov    bp, dx
  379.     loop    @@inner            ; Continue for all BIG1
  380.     pop    bp
  381.     mov    [bx+si+2], dx        ; Store carry remaining
  382.  
  383.     pop    cx            ; Restore BIG2 counter
  384.     inc    di            ; Point di to next word in BIG2
  385.     inc    di
  386.     inc    bx            ; Point bx to next word in BIG3
  387.     inc    bx
  388.     loop    @@outer            ; Continue for all BIG2
  389.  
  390.     mov    bx, [@@result]
  391.     pop    si            ; Point si to last word of product
  392.     shl    si, 1
  393.     cmp    [WORD si+bx+1], 0    ; Test last word for zero
  394.     jnz    @@done
  395.     dec    [(BIGDATA bx).len]
  396. @@done:
  397.     ret
  398. ENDP    bigmul
  399.  
  400. ;************************************************************************
  401. ;*            Divide one bignum by another            *
  402. ;* Calling sequence: bigdiv(dvdnd,dvsr,quot)                *
  403. ;* Where dvdnd:    dividend                        *
  404. ;*    dvsr:    divisor                            *
  405. ;*    quot:    quotient                        *
  406. ;************************************************************************
  407. PROC C    bigdiv USES si di, $$dividend, @@divisor, @@quotient
  408.     LOCAL    $$divisorend, $$align, @@bitcount, $$divisorsize
  409.  
  410.     push    ds            ; assume es = ds
  411.     pop    es
  412.     mov    di, [@@quotient]    ; Get pointers to arguments
  413.     mov    si, [$$dividend]
  414.     mov    bx, [@@divisor]
  415.     cld
  416.     lodsw                ; Get dividend length
  417.     mov    cx, [(BIGDATA bx).len]
  418.     cmp    cx, 1            ; Check divisor for 0
  419.     jne    @@longdiv
  420.  
  421.     mov    dx, [(BIGDATA bx).lsw]
  422.     or    dx, dx
  423.     jnz    @@divisorok
  424.     mov    ax, 1
  425.     jmp    @@ret
  426. @@divisorok:
  427.     mov    cl, [(BIGDATA bx).sign]
  428.     push    ax            ; save the dividend'd size
  429.     mov    bx, ax
  430.     dec    bx
  431.     shl    bx, 1
  432.     cmp    [((BIGDATA si+bx).lsw)-2], dx ; will result be smaller ?
  433.     sbb    ax, 0
  434.     stosw                ; write back the quotient's size
  435.     lodsb                ; get dividend's sign
  436.     xor    al, cl
  437.     stosb
  438.     add    si, bx            ; make si point to the divisor's end
  439.     add    di, bx            ; and di to the quotient's end
  440.     mov    bx, dx            ; bx is the divisor
  441.     xor    dx, dx            ; clear the carry
  442.     std                ; start at most significant digit
  443.     pop    cx
  444. @@fastloop:
  445.     lodsw
  446.     div    bx
  447.     stosw
  448.     loop    @@fastloop
  449.  
  450.     mov    [((BIGDATA si).len)-1], 1
  451.     mov    [((BIGDATA si).lsw)-1], dx ; store remainder
  452.     jmp    @@retok
  453.  
  454. @@longdiv:
  455.     inc    bx            ; my, that's ugly ! remember bx has been
  456.                     ; incremented... it shortens the code
  457.     mov    dx, cx            ; Find & store pointer to last divisor word
  458.     shl    dx, 1
  459.     add    dx, bx
  460.     mov    [$$divisorend], dx
  461.     sub    ax, cx            ; Find dividend-divisor length difference
  462.     mov    dx, ax            ; Save in dx for now
  463.     inc    ax            ; Store maximum quotient length (words)
  464.     stosw
  465.     inc    cx            ; Save length of working divisor (overwrite size!)
  466.     mov    [$$divisorsize], cx
  467.     dec    ax            ; Find and store quotient bit count
  468.     shl    ax, 1
  469.     shl    ax, 1
  470.     shl    ax, 1
  471.     shl    ax, 1
  472.     inc    ax
  473.     mov    [@@bitcount], ax
  474.     lodsb                ; Get dividend sign
  475.     xor    al, [((BIGDATA bx).sign)-1]
  476.     stosb
  477.     mov    [$$dividend], si    ; save proper pointers
  478.     mov    [@@quotient], di
  479.     xor    ax, ax            ; Zero first two words of quotient
  480.     stosw
  481.     std
  482.     stosw
  483.     dec    dx            ; Account for extra divisor word
  484.     shl    dx, 1            ; Store divisor-dividend alignment
  485.     add    dx, si
  486.     mov    [$$align], dx
  487.     mov    [WORD bx], 0        ; Put 0-word at start of divisor
  488.     mov    [@@divisor], bx        ; Save pointer to working divisor
  489. @@findwork:
  490.     call    divcmp            ; Dividend less than aligned divisor?
  491.     jb    @@dividebit0
  492.     test    [WORD bx], 8000h    ; Can divisor be shifted left?
  493.     jnz    @@dividebit1
  494.     mov    si, [@@divisor]        ; Otherwise, shift entire divisor left
  495.     mov    cx, [$$divisorsize]
  496.     clc                ; Start by shifting in 0
  497. @@shiftleft:
  498.     rcl    [WORD si], 1        ; Shift through divisor word
  499.     inc    si            ; Point si to next word
  500.     inc    si            ; (preserving carry)
  501.     loop    @@shiftleft
  502.     inc    [@@bitcount]
  503.     jmp    @@findwork        ;See if divisor is big enough yet
  504.  
  505. @@divide:
  506.     call    divcmp            ; Dividend less than aligned divisor?
  507.     cld                ; (Direction forward)
  508.     jb    @@dividebit0
  509.     mov    si, [$$align]        ; Otherwise, subtract divisor
  510.     mov    di, si
  511.     mov    bx, [@@divisor]
  512.     sub    bx, si
  513.     dec    bx
  514.     dec    bx
  515.     mov    cx, [$$divisorsize]
  516.     clc                ; No carry in
  517. @@inner:
  518.     lodsw
  519.     sbb    ax, [si+bx]
  520.     stosw
  521.     loop    @@inner
  522. @@dividebit1:
  523.     clc                ; Clear carry (to rotate 1 in)
  524. @@dividebit0:
  525.     cmc
  526.     mov    si, [@@quotient]    ; Fetch pointer to quotient
  527.     mov    cx, [si-3]        ; Fetch quotient length
  528. @@quotientloop:
  529.     rcl    [WORD si], 1        ; Rotate bit in
  530.     inc    si            ; preserving carry
  531.     inc    si
  532.     loop    @@quotientloop
  533.     dec    [@@bitcount]
  534.     jz    @@done
  535.     mov    si, [$$divisorend]    ; realign divisor (shr)
  536.     mov    cx, [$$divisorsize]
  537.     std
  538.     cmp    [WORD si], 0        ; Time to shift divisor words?
  539.     jnz    @@skipwordshift
  540.     mov    bx, si            ; Save last word pointer
  541.     mov    dx, cx            ; Save word count
  542.     mov    di, si            ; Destination = source+2
  543.     dec    si
  544.     dec    si
  545.     dec    cx            ; Shift significant divisor words
  546.     rep    movsw
  547.     xor    ax, ax            ; Clear least significant word
  548.     stosw
  549.     mov    si, bx            ; Restore last word pointer
  550.     mov    cx, dx            ; Restore count
  551.     sub    [$$align], 2        ; Reset divisor alignment
  552. @@skipwordshift:
  553.     clc                ; Shift 0 in
  554. @@shiftright:
  555.     rcr    [WORD si], 1
  556.     dec    si
  557.     dec    si
  558.     loop    @@shiftright
  559.     jmp    @@divide
  560.  
  561. @@done:
  562.     mov    bx, [$$dividend]    ; Fetch dividend pointer
  563.     mov    di, [bx-3]        ; Fetch former length of dividend
  564.     dec    di            ; Put length-1 in cx
  565.     mov    cx, di
  566.     shl    di, 1            ; Point di to last dividend word
  567.     add    di, bx
  568.     std
  569.     xor    ax, ax            ; Pack as in BIGSUB
  570.     repe    scasw
  571.     jz    @@skipsmall
  572.     inc    cx
  573. @@skipsmall:
  574.     inc    cx
  575.     mov    [bx-3], cx        ; Save in bignum size field
  576.     mov    bx, [@@quotient]    ; Fetch quotient pointer
  577.     mov    di, [bx-3]        ; Point bx+di to last quotient word
  578.     shl    di, 1
  579.     cmp    [WORD bx+di-2], 0    ; If last word is 0, decrease length
  580.     jnz    @@retok
  581.     dec    [WORD bx-3]
  582. @@retok:
  583.     xor    ax, ax            ; success
  584. @@ret:
  585.     cld
  586.     ret
  587.  
  588. ; Compare working divisor to dividend
  589. PROC NOLANGUAGE    divcmp    NEAR
  590.     mov    di, [$$divisorend]    ; Get pointer to last divisor word
  591.     mov    cx, [$$divisorsize]    ; Fetch number of compares to do
  592.     mov    si, [$$align]        ; Get dividend pointer
  593.     mov    ax, cx
  594.     cmp    si, [$$dividend]    ; Dividend longer than divisor?
  595.     jae    @@skipadjust
  596.     dec    cx            ; Don't compare first divisor word
  597. @@skipadjust:
  598.     dec    ax            ; Adjust pointer into dividend
  599.     shl    ax, 1
  600.     add    si, ax
  601.     mov    bx, di            ; Save pointer to last divisor byte
  602.     std
  603.     repe    cmpsw
  604.     ret
  605. ENDP    divcmp
  606.  
  607. ENDP    bigdiv
  608.  
  609. END
  610.  
  611.