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 >
Wrap
Assembly Source File
|
1991-08-16
|
3KB
|
118 lines
; 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 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