; long division and modulus routines
;
; written by Kai-Uwe Bloem (I5110401@dbstu1.bitnet).
;
;
; Revision 1.1, kub 03-90
; first version, replaces the appropriate routine from fixnum.s.
; Should be faster in more common cases. Division is done by 68000 divu
; operations if divisor is only 16 bits wide. Otherwise the normal division
; algorithm as described in various papers takes place. The division routine
; delivers the quotient in d0 and the remainder in d1, thus the implementation
; of the modulo operation is trivial. We gain some extra speed by inlining
; the division code here instead of calling __udivsi3.

	text
	even
	xdef	__CXD22

__CXD22:
	movem.l	d0-d3,-(sp)
	subq.w	#4,sp
	clr.w	-(sp)		; sign flag
	clr.l	d0		; prepare result
	move.l	10(sp),d2	; get divisor
	beq.s	10$		; divisor = 0 causes a division trap
	bpl.s	1$		; divisor < 0 ?
	neg.l	d2		; negate it
	not.w	(sp)		; remember sign
1$:	move.l	6(sp),d1	; get dividend
	bpl.s	2$		; dividend < 0 ?
	neg.l	d1		; negate it
	not.w	(sp)		; remember sign
2$:
;== case 1) divident < divisor
	cmp.l	d2,d1		; is divident smaller then divisor ?
	bcs.s	7$		; yes, return immediately
;== case 2) divisor has <= 16 significant bits
	tst.w	10(sp)
	bne.s	4$		; divisor has only 16 bits
	move.w	d1,d3		; save dividend
	clr.w	d1		; divide dvd.h by dvs
	swap	d1
	beq.s	3$		; (no division necessary if dividend zero)
	divu.w	d2,d1
3$:	move.w	d1,d0		; save quotient.h

	swap	d0
	move.w	d3,d1		; (d0.h = remainder of prev divu)
	divu.w	d2,d1		; divide dvd.l by dvs
	move.w	d1,d0		; save quotient.l
	clr.w	d1		; get remainder
	swap	d1
	bra.s	7$		; and return
;== case 3) divisor > 16 bits (corollary is dividend > 16 bits, see case 1)
4$:
	moveq.l	#31,d3		; loop count
5$:
	add.l	d1,d1		; shift divident ...
	addx.l	d0,d0		;  ... into d0
	cmp.l	d2,d0		; compare with divisor
	bcs.s	6$
	sub.l	d2,d0		; big enough, subtract
	add.w	#1,d1		; and note bit into result
6$:
	dbra	d3,5$
	exg	d0,d1		; put quotient and remainder in their registers
7$:
	tst.w	6(sp)		; must the remainder be corrected ?
	bpl.s	8$
	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
8$:	tst.w	(sp)+		; result should be negative ?
	bpl.s	9$
	neg.l	d0		; yes, negate it
9$:
	lea	12(sp),sp
	movem.l	(sp)+,d2-d3
	rts
10$:
	divu	d2,d1		; cause division trap
	bra	7$		; back to user
	end
