home *** CD-ROM | disk | FTP | other *** search
-
- ; r = MulDiv(a,b,c) long a,b,c;
- ; r = MulDivU(a,b,c) unsigned long a,b,c;
- ;
- ; result.32 = a.32 * b.32 / c.32
- ;
- ; 32x32->64 64/32->32 multiply-divide combination
-
- section text,CODE
-
- xdef _MulDiv
- xdef _MulDivU
-
- _MulDiv:
- movem.l D2-D4,-(sp) ; save D2/D3 (generic compiler compatibility)
- moveq.l #0,D4 ; clear negate flag
- lea 16(sp),A0 ; address of 'a'
- move.l A0,A1 ; save A1 for muldivu call
- tst.l (A0) ; test a
- bpl mp
- neg.l (A0)+ ; n--
- tst.l (A0) ; test b
- bpl mnp
- neg.l (A0)+ ; nn-
- tst.l (A0) ; test c
- bpl muldivu ; nnp CALL, RESULT POSITIVE
- mppn neg.l (A0) ; nnn
- mpnp
- mnpp moveq.l #1,D4 ; set negate flag
- bra muldivu
-
- mp addq.l #4,A0 ; p--
- tst.l (A0) ; test b
- bpl mpp
- neg.l (A0)+ ; pn-
- tst.l (A0) ; test c
- bpl mpnp
- neg.l (A0) ; pnn
- bra muldivu ; jmp to routine
-
- mpp addq.l #4,A0 ; pp-
- tst.l (A0)
- bpl muldivu ; ppp RESULT POSITIVE
- bra mppn ; RESULT NEGATIVE (negate (A0) befor call)
-
- mnp addq.l #4,A0 ; np-
- tst.l (A0) ; test c
- bpl mnpp ; RESULT NEGATIVE
- neg.l (A0) ; npn
- bra muldivu ; RESULT POSITIVE
-
- ; MulDivU(a,b,c) AH 4(sp) AL 6(sp) BH 8(sp) BL 10(sp)
- ; unsigned long a @4(sp)
- ; unsigned long b @8(sp)
- ; unsigned long c @12(sp)
-
- _MulDivU:
- movem.l D2-D4,-(sp) ; save D2-D4
- moveq.l #0,D4 ; clear negate flag
- lea 16(sp),A1 ; address of 'a'
- muldivu
- lea 4(A1),A0
-
- move.w (A0)+,D3 ; bh ah 8(sp) A0 8->10
- mulu.w (A1)+,D3 ; 4(sp) A1 4->6
- move.w (A0),D0 ; bl al 10(sp) A0 10
- mulu (A1),D0 ; 6(sp) A1 6
- move.w (A0),D1 ; bl ah 10(sp) A0 10
- mulu.w -(A1),D1 ; 4(sp) A1 now 4
- move.w -(A0),D2 ; bh al 8(sp) A0 now 8
- mulu.w -(A0),D2 ; 6(sp) A0 now 6
- add.l D1,D2 ; combine blah and bhal
- bcc mud1
- add.l #$10000,D3
- mud1 swap D0 ; LSB MSB
- add.w D2,D0
- swap D0
- swap D2
- and.l #$FFFF,D2
- addx.l D2,D3 ;64 bit mul result: D3|D0
-
- ;64 bit by 32 bit division. 32 bit result.
-
- move.l 6(A0),D1 ;D1 = c A0 WAS 6
- beq mdfail
-
- sub.l A0,A0 ;Divide! D1 into D3|D0, D2 = cntr, A0 = rslt
- move.w #31,D2 ;(no initial compare). 31 + 1 iterations
- mud10 adda.l A0,A0 ;shift result left
- asl.l #1,D0 ;Shift left
- roxl.l #1,D3
- cmp.l D1,D3
- bcs mud11 ;if D3 < D1, skip (blo)
- sub.l D1,D3 ; D3 >= D1
- addq.l #1,A0 ;result = result | 1
- mud11 dbf D2,mud10
-
- ;; If remainder (D3) larger than 1/2 C (D1 >> 1), then
- ;; round up result. REMOVED
- ;
- ;lsr.l #1,D1
- ;cmp.l D1,D3
- ;blo mud12 ; skip if remainder < 1/2C
- ;addq.l #1,A0
- mud12
- move.l A0,D0 ;return result
- tst.l D4 ;D4 non-zero means negate result
- beq mud13
- neg.l D0
- mud13 movem.l (sp)+,D2-D4 ;restore D2-D4
- rts
-
- mdfail moveq.l #-1,D0
- bra mud13
-
- END
-
-