;FUNC= MulDiv D0/D1/D2 ;FUNC= UMulDiv D0/D1/D2 ;FUNC= MulShift D0/D1/D2 ;FUNC= UMulShift D0/D1/D2 ; MulDiv (a ,b ,c) 32x32->64 64/32->32 (signed) ; MulShift(a ,b ,n) 32x32->64 64>>n->32 (signed) ; D0,D1,D2 ; ; 32x32->64 64/32->32 ; 32x32->64 64>>n->32 ; ; note: n is a word public _MulDiv public _UMulDiv public _MulShift public _UMulShift ; Various connotations specifying which arguments are ; unsigned (you gain a bit when using unsigned arguments) REGS eqr D2-D7 _UMulDiv movem.l REGS,-(sp) clr.w D7 bra .md10 _MulDiv movem.l REGS,-(sp) clr.w D7 tst.l D0 bpl .md2 neg.l D0 tst.l D1 ; neg bpl .md1 ; neg neg.l D1 tst.l D2 ; neg neg bpl .md10 ; neg neg neg.l D2 bra .md9 ; neg neg neg .md1 tst.l D2 ; neg bpl .md9 ; neg neg.l D2 bra .md10 ; neg neg .md2 tst.l D1 bpl .md3 neg.l D1 tst.l D2 ; neg bpl .md9 ; neg neg.l D2 bra .md10 ; neg neg .md3 tst.l D2 bpl .md10 neg.l D2 bra .md9 _UMulShift movem.l REGS,-(sp) clr.w D7 bra .md6 _MulShift movem.l REGS,-(sp) clr.w D7 tst.l D0 bpl .md4 neg.l D0 tst.l D1 bpl .md5 neg.l D0 bra .md6 .md4 tst.l D1 bpl .md6 neg.l D1 .md5 addq.w #1,D7 .md6 swap D0 swap D1 tst.w D0 beq .md601 bsr .md0huge beq .md602a bra .md603 .md601 tst.w D1 beq .md602 bsr .md1huge beq .md602a bra .md603 .md602 swap D0 swap D1 mulu D1,D0 .md602a lsr.l D2,D0 bra .mddone .md603 subq.w #1,D2 bmi .mddone .md604 lsr.l #1,D3 roxr.l #1,D0 dbf D2,.md604 bra .mddone .md10 swap D0 swap D1 tst.w D0 beq .md101 bsr .md0huge beq .mdsdiv bsr div64 bra .mddone .md101 tst.w D1 beq .md105 bsr .md1huge beq .mdsdiv bsr div64 bra .mddone .md105 swap D0 ; both word sized swap D1 mulu D1,D0 ; D1.WxD0.W -> D0.L .mdsdiv move.l D2,D1 jsr .divu# ; ; .md9 addq.w #1,D7 ; All elements now unsigned, D7.W determines whether to ; negate at end. .mddone btst.l #0,D7 beq .mddone2 neg.l D0 .mddone2 movem.l (sp)+,REGS rts ; NOTE: entered with register halves reversed ; ; D2 not effected ; Test D3 on return .md0huge tst.w D1 beq .md1hugex ; D0.L, D1.W ; D0.L, D1.L (long x long) move.w D0,D4 ; save ah move.w D0,D3 ; ah bh mulu.w D1,D3 swap D0 ; al bh move.w D0,D5 mulu.w D1,D5 swap D1 mulu.w D1,D0 ; al bl mulu.w D4,D1 ; ah bl add.l D1,D5 ; combine blah and bhal bcc .mud1 add.l #$10000,D3 .mud1 swap D0 ; LSB MSB add.w D5,D0 swap D0 clr.w D5 swap D5 addx.l D5,D3 ;64 bit mul result: D3|D0 rts ;Test D3 ; D2 not effected .md1huge exg D0,D1 .md1hugex ; D0.L, D1.W al ah ; bl move.w D0,D3 mulu.w D1,D3 ; D3 = bl x ah swap D0 mulu.w D1,D0 ; D0 = bl x al swap D0 ; add lsb byte of D3 to msb byte of D0 add.w D3,D0 swap D0 clr.w D3 ; doesn't effect X swap D3 ; msb of D3 actually lsb of second longword moveq.l #0,D1 addx D1,D3 ; possible x(carry) from previous addition ; 64 bit mul result: D3|D0 ; Test D3 rts ; DIV64 ; ; 64/32->32 D3|D0 / D2 -> D0 div64: move.l #0,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 blo .mud11 ;if D3 < D1, skip 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. 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 rts