home *** CD-ROM | disk | FTP | other *** search
- ; long arithmetic routines
- ;
- ; written by Kai-Uwe Bloem (I5110401@dbstu1.bitnet).
- ;
- ; Names changed and converted from MIT to Motorola syntax by Dave Gymer for SC
-
- .text
- .even
- .globl lmul,lmulu
- .globl ldiv,ldivu
- .globl lrem,lremu
-
- ldiv:
- move.l d2,a0 ; save registers
- move.l d3,a1
- clr.w -(sp) ; sign flag
- clr.l d0 ; prepare result
- move.l 10(sp),d2 ; get divisor
- beq L9 ; divisor = 0 causes a division trap
- bpl J0 ; divisor < 0 ?
- neg.l d2 ; negate it
- not.w (sp) ; remember sign
- J0: move.l 6(sp),d1 ; get dividend
- bpl J1 ; dividend < 0 ?
- neg.l d1 ; negate it
- not.w (sp) ; remember sign
- J1:
- ;== case 1) divident < divisor
- cmp.l d2,d1 ; is divident smaller then divisor ?
- bcs L8 ; yes, return immediately
- ;== case 2) divisor has <= 16 significant bits
- tst.w 10(sp)
- bne L2 ; divisor has only 16 bits
- move.w d1,d3 ; save dividend
- clr.w d1 ; divide dvd.h by dvs
- swap d1
- beq J2 ; (no division necessary if dividend zero)
- divu d2,d1
- J2: move.w d1,d0 ; save quotient.h
- swap d0
- move.w d3,d1 ; (d0.h = remainder of prev divu)
- divu d2,d1 ; divide dvd.l by dvs
- move.w d1,d0 ; save quotient.l
- clr.w d1 ; get remainder
- swap d1
- bra L8 ; and return
- ;== case 3) divisor > 16 bits (corollary is dividend > 16 bits, see case 1)
- L2:
- moveq #31,d3 ; loop count
- L3:
- add.l d1,d1 ; shift divident ...
- addx.l d0,d0 ; ... into d0
- cmp.l d2,d0 ; compare with divisor
- bcs J3
- sub.l d2,d0 ; big enough, subtract
- add.w #1,d1 ; and note bit into result
- J3:
- dbra d3,L3
- exg d0,d1 ; put quotient and remainder in their registers
- L8:
- tst.w 6(sp) ; must the remainder be corrected ?
- bpl J4
- neg.l d1 ; yes, apply sign
- ; the following line would be correct if modulus is defined as in algebra
- ; add.l 6(sp),d1 ; algebraic correction: modulus can only be >= 0
- J4: tst.w (sp)+ ; result should be negative ?
- bpl J5
- neg.l d0 ; yes, negate it
- J5:
- move.l a1,d3
- move.l a0,d2
- rts
- L9:
- divu d2,d1 ; cause division trap
- bra L8 ; back to user
-
- lrem:
- move.l 8(sp),-(sp) ; push divisor
- move.l 8(sp),-(sp) ; push dividend
- bsr ldiv
- lea 8(sp),sp
- move.l d1,d0 ; return the remainder in d0
- rts
-
- ldivu:
- move.l d2,a0 ; save registers
- move.l d3,a1
- clr.l d0 ; prepare result
- move.l 8(sp),d2 ; get divisor
- beq N9 ; divisor = 0 causes a division trap
- move.l 4(sp),d1 ; get dividend
- ;== case 1) divident < divisor
- cmp.l d2,d1 ; is divident smaller then divisor ?
- bcs N8 ; yes, return immediately
- ;== case 2) divisor has <= 16 significant bits
- tst.w 8(sp)
- bne N2 ; divisor has only 16 bits
- move.w d1,d3 ; save dividend
- clr.w d1 ; divide dvd.h by dvs
- swap d1
- beq K0 ; (no division necessary if dividend zero)
- divu d2,d1
- K0: move.w d1,d0 ; save quotient.h
- swap d0
- move.w d3,d1 ; (d1.h = remainder of prev divu)
- divu d2,d1 ; divide dvd.l by dvs
- move.w d1,d0 ; save quotient.l
- clr.w d1 ; get remainder
- swap d1
- bra N8 ; and return
- ;== case 3) divisor > 16 bits (corollary is dividend > 16 bits, see case 1)
- N2:
- moveq #31,d3 ; loop count
- N3:
- add.l d1,d1 ; shift divident ...
- addx.l d0,d0 ; ... into d0
- cmp.l d2,d0 ; compare with divisor
- bcs K1
- sub.l d2,d0 ; big enough, subtract
- add.w #1,d1 ; and note bit in result
- K1:
- dbra d3,N3
- exg d0,d1 ; put quotient and remainder in their registers
- N8:
- move.l a1,d3
- move.l a0,d2
- rts
- N9:
- divu d2,d1 ; cause division trap
- bra N8 ; back to user
-
- lremu:
- move.l 8(sp),-(sp) ; push divisor
- move.l 8(sp),-(sp) ; push dividend
- bsr ldivu
- lea 8(sp),sp
- move.l d1,d0 ; return the remainder in d0
- rts
-
- lmul:
- move.l d2,a0 ; save registers
- move.l d3,a1
- movem.w 4(sp),d0-d3 ; get the two longs. u = d0-d1, v = d2-d3
- move.w d0,-(sp) ; sign flag
- bpl J6 ; is u negative ?
- neg.w d1 ; yes, force it positive
- negx.w d0
- J6: tst.w d2 ; is v negative ?
- bpl J7
- neg.w d3 ; yes, force it positive ...
- negx.w d2
- not.w (sp) ; ... and modify flag word
- J7:
- ext.l d0 ; u.h <> 0 ?
- beq M1
- mulu d3,d0 ; r = v.l * u.h
- M1: tst.w d2 ; v.h <> 0 ?
- beq M2
- mulu d1,d2 ; r += v.h * u.l
- add.w d2,d0
- M2: swap d0
- clr.w d0
- mulu d3,d1 ; r += v.l * u.l
- add.l d1,d0
- move.l a1,d3
- move.l a0,d2
- tst.w (sp)+ ; should the result be negated ?
- bpl M3 ; no, just return
- neg.l d0 ; else r = -r
- M3: rts
-
- lmulu:
- move.l d2,a0 ; save registers
- move.l d3,a1
- movem.w 4(sp),d0-d3 ; get the two longs. u = d0-d1, v = d2-d3
- ext.l d0 ; u.h <> 0 ?
- beq O1
- mulu d3,d0 ; r = v.l * u.h
- O1: tst.w d2 ; v.h <> 0 ?
- beq O2
- mulu d1,d2 ; r += v.h * u.l
- add.w d2,d0
- O2: swap d0
- clr.w d0
- mulu d3,d1 ; r += v.l * u.l
- add.l d1,d0
- move.l a1,d3
- move.l a0,d2
- rts
-