home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / suplib.lzh / SUPLIB / SRC / MULDIV.ASM < prev    next >
Assembly Source File  |  1991-08-16  |  3KB  |  118 lines

  1.  
  2.         ;    r = MulDiv(a,b,c)   long a,b,c;
  3.         ;    r = MulDivU(a,b,c)  unsigned long a,b,c;
  4.         ;
  5.         ;    result.32 = a.32 * b.32 / c.32
  6.         ;
  7.         ;    32x32->64 64/32->32 multiply-divide combination
  8.  
  9.         section CODE
  10.  
  11.         xdef    _MulDiv
  12.         xdef    _MulDivU
  13.  
  14. _MulDiv:
  15.         movem.l D2-D4,-(sp) ; save D2/D3 (generic compiler compatibility)
  16.         moveq.l #0,D4    ; clear negate flag
  17.         lea     16(sp),A0   ; address of 'a'
  18.         move.l  A0,A1    ; save A1 for muldivu call
  19.         tst.l   (A0)        ; test a
  20.         bpl     .mp
  21.         neg.l   (A0)+       ; n--
  22.         tst.l   (A0)        ; test b
  23.         bpl     .mnp
  24.         neg.l   (A0)+       ; nn-
  25.         tst.l   (A0)        ; test c
  26.         bpl     muldivu    ; nnp CALL, RESULT POSITIVE
  27. .mppn        neg.l   (A0)        ; nnn
  28. .mpnp
  29. .mnpp        moveq.l #1,D4    ; set negate flag
  30.         bra     muldivu
  31.  
  32. .mp        addq.l  #4,A0    ; p--
  33.         tst.l   (A0)        ; test b
  34.         bpl     .mpp
  35.         neg.l   (A0)+       ; pn-
  36.         tst.l   (A0)        ; test c
  37.         bpl     .mpnp
  38.         neg.l   (A0)        ; pnn
  39.         bra     muldivu    ; jmp to routine
  40.  
  41. .mpp        addq.l  #4,A0    ; pp-
  42.         tst.l   (A0)
  43.         bpl     muldivu    ; ppp RESULT POSITIVE
  44.         bra     .mppn    ; RESULT NEGATIVE (negate (A0) befor call)
  45.  
  46. .mnp        addq.l  #4,A0    ; np-
  47.         tst.l   (A0)        ; test c
  48.         bpl     .mnpp    ; RESULT NEGATIVE
  49.         neg.l   (A0)        ; npn
  50.         bra     muldivu    ; RESULT POSITIVE
  51.  
  52.         ;    MulDivU(a,b,c)          AH 4(sp) AL 6(sp) BH 8(sp) BL 10(sp)
  53.         ;    unsigned long a   @4(sp)
  54.         ;    unsigned long b   @8(sp)
  55.         ;    unsigned long c   @12(sp)
  56.  
  57. _MulDivU:
  58.         movem.l D2-D4,-(sp) ; save D2-D4
  59.         moveq.l #0,D4    ; clear negate flag
  60.         lea     16(sp),A1   ; address of 'a'
  61. muldivu
  62.         lea     4(A1),A0
  63.  
  64.         move.w  (A0)+,D3    ; bh ah     8(sp)  A0 8->10
  65.         mulu.w  (A1)+,D3    ;           4(sp)  A1 4->6
  66.         move.w  (A0),D0     ; bl al    10(sp)  A0 10
  67.         mulu    (A1),D0     ;           6(sp)  A1 6
  68.         move.w  (A0),D1     ; bl ah    10(sp)  A0 10
  69.         mulu.w  -(A1),D1    ;           4(sp)  A1 now 4
  70.         move.w  -(A0),D2    ; bh al     8(sp)  A0 now 8
  71.         mulu.w  -(A0),D2    ;           6(sp)  A0 now 6
  72.         add.l   D1,D2    ; combine blah and bhal
  73.         bcc     .mud1
  74.         add.l   #$10000,D3
  75. .mud1        swap    D0        ; LSB MSB
  76.         add.w   D2,D0
  77.         swap    D0
  78.         swap    D2
  79.         and.l   #$FFFF,D2
  80.         addx.l  D2,D3    ;64 bit mul result: D3|D0
  81.  
  82.                 ;64 bit by 32 bit division.  32 bit result.
  83.  
  84.         move.l  6(A0),D1    ;D1 = c           A0 WAS 6
  85.         beq     .mdfail
  86.  
  87.         sub.l   A0,A0    ;Divide!    D1 into D3|D0, D2 = cntr, A0 = rslt
  88.         move.w  #31,D2    ;(no initial compare).  31 + 1 iterations
  89. .mud10        adda.l  A0,A0    ;shift result left
  90.         asl.l   #1,D0    ;Shift left
  91.         roxl.l  #1,D3
  92.         cmp.l   D1,D3
  93.         bcs     .mud11    ;if D3    < D1, skip  (blo)
  94.         sub.l   D1,D3    ;   D3 >= D1
  95.         addq.l  #1,A0    ;result = result | 1
  96. .mud11        dbf     D2,.mud10
  97.  
  98.         ;;     If remainder (D3) larger than 1/2 C (D1 >> 1), then
  99.         ;;     round up result.    REMOVED
  100.         ;
  101.         ;lsr.l   #1,D1
  102.         ;cmp.l   D1,D3
  103.         ;blo     .mud12     ; skip if remainder < 1/2C
  104.         ;addq.l  #1,A0
  105. .mud12
  106.         move.l  A0,D0    ;return result
  107.         tst.l   D4        ;D4 non-zero means negate result
  108.         beq     .mud13
  109.         neg.l   D0
  110. .mud13        movem.l (sp)+,D2-D4 ;restore D2-D4
  111.         rts
  112.  
  113. .mdfail     moveq.l #-1,D0
  114.         bra     .mud13
  115.  
  116.         END
  117.  
  118.