/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

/*
*	Register definitions. Leave them alone.
*/

#define	N		r0					// Numerator
#define	D		r1					// Denominator
#define	Q		r2					// Quotient
#define	E		r3					// Denominator shift count

/*
*	Unsigned 32-bit division core
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	It divides r0 by r1 and returns the remainder in r1 and the
*	quotient in r0.
*
*	The function uses the classical subtract and restore algorithm,
*	nothing fancy, really, just the proc is fast.
*
*	IMPORTANT:	Normal C calling conventions permit the use of the
*				r12 register. This function, however, MUST NOT clobber
*				that register because the functions calling this one
*				assume that it is preserved. In fact, r12 contains the
*				return address of the function that called this one.
*/
	.text
	.align	2
	.code	32
	.globl	_bgs_udiv32
	.func	_bgs_udiv32
_bgs_udiv32:
	tst		D,D						// Check for division by 0, in which
	beq		__trap_div0				// case we go to the handler
	cmp		N,D						// If the numer is less than the denom,
	movcc	D,N						// then the remainder is the numerator
	movcc	N,#0					// and the quotient is 0
	bxcc	lr						// and we're done

	// Normalise the denumerator.

	mov		Q,N
	mov		E,#0
	cmp		D,Q,lsr #16
	movls	Q,Q,lsr #16
	addls	E,E,#16
	cmp		D,Q,lsr #8
	movls	Q,Q,lsr #8
	addls	E,E,#8
	cmp		D,Q,lsr #4
	movls	Q,Q,lsr #4
	addls	E,E,#4
	cmp		D,Q,lsr #2
	movls	Q,Q,lsr #2
	addls	E,E,#2
	cmp		D,Q,lsr #1
	addls	E,E,#1
	mov		D,D,lsl E

	// At this point we know that the numerator is larger than or equal
	// to the denominator but it is less than twice the denominator.
	// E now contains the number of times we had to shift the denominator
	// to the left to achieve this.

	mov		Q,#0				// Prepare the quotient
	add		E,E,#1				// Loop count is shift count + 1

	// This is the first 24 steps of the division.
	// A single step of the algorithm consist of a subtract and restore,
	// testing the numerator for 0, shifting the denumerator, and decrementing
	// the loop count. The subtract-restore is 3 clocks and the rest can be
	// done in an other 4 clocks. However, we do it in blocks of 8, where
	// we always do 8 subtract-restores but do the test, shift, decrement only
	// once. The normal way would cost 7*8 instructions, the block based way
	// is only 8*3+5 clocks. That is, we save 27 clocks (and 108 bytes) doing
	// it in blocks. The snag is that if the numerator becomes 0 after the
	// first step, we will execute the next 7 steps unnecessarily, burning
	// 21 clocks for nothing. Now the maximum loss we can have is 22 clocks
	// in total and the maximum gain is 81 clocks (and 324 bytes!), so overall
	// it is worth doing it in blocks.

	.rept	3
	subs	E,E,#8				// Do we have at lest 8 iterations?
	bmi		unblock				// If not, leave the block thing at once
	.set	S,0					// Initial shift count is 0
	.rept	8
	.ifeq	S
	subs	N,N,D				// Just to keep old gas versions happy,
	addcc	N,N,D				// they don't like 0 shift amount. See below.
	.else
	subs	N,N,D,lsr #S		// Subtract the denominator from the numerator
	addcc	N,N,D,lsr #S		// If we failed, restore the numerator
	.endif
	adc		Q,Q,Q				// Shift the result in
	.set	S,S+1				// Increment the shift count
	.endr
	tst		N,N					// Is the numerator zero?
	beq		final				// If yes, abort
	mov		D,D,lsr #8			// Adjust the denominator
	.endr

	// The block processing finished. If it finished because there were
	// at least 24 steps to be taken, then those steps are taken now and
	// E is positive. If it finished because there were less than 24 steps
	// initially, then E is negative and E+8 is the remaining shift count,
	// obviously between 0 and 7.

unblock:
	tst		E,E					// Check E
	addmis	E,E,#8				// If negative, we have to restore it

	// Now E contains the number of remaining number of shifts.
	// It is between 0 and 7, inclusive. The Z bit is set iff E is 0.

	beq		final				// If no more steps, go to the end
	.set	S,6					// For the last step, we'll omit 3 insns
	.rept	7
	subs	N,N,D				// Subtract the denominator from the numerator
	addcc	N,N,D				// If we failed, restore the numerator
	adc		Q,Q,Q				// Shift the result in
	sub		E,E,#1				// Adjust the loop count
	.ifne	S
	tstne	E,E					// If the mantissa is not 0, test the count
	beq		final				// If the mantissa or the count is 0, abort
	mov		D,D,lsr #1			// Adjust the denominator
	.endif
	.set	S,S-1				// Maintain the step counter
	.endr

	// At this point the division is finished. If we aborted the process
	// because the numerator became 0, then the remaining loop count
	// tells us how many bits we have to shift the quotient up. In any case,
	// we also have to move the quotient into the denominator's place.
	// The remainder is also shifted up due to our normalisation so we
	// have to shift it down to its correct place.

final:
	mov		D,N					// Put the remainder into place
	mov		N,Q,lsl E			// Fix up the quotient
	bx		lr					// and return
	.endfunc

