/****************************************************************************/
/*	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 or 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.																	*/
/****************************************************************************/

#define	ASSEMBLY_SOURCE
#include <nanu-nanu.h>
#include <chips/ARM/func.h>

#if NANU_ASM_SUB

	// _bc_NanuMulu

	afunc	_bc_NanuMulu
	stmdb	sp!,{r4,r5}
	mov		r4,#0
	mov		r5,#0
	b		1f
0:
	ldr		r12,[r0]
	adds	r4,r4,r12
	adc		r5,r5,#0
	ldr		r12,[r1],#4
	umlal	r4,r5,r12,r2
	str		r4,[r0],#4
	mov		r4,r5
	mov		r5,#0
1:
	subs	r3,r3,#1
	bpl		0b
	mov		r0,r4
	ldmia	sp!,{r4,r5}
	bx		lr
	.endfunc

	// _bc_NanuMulm

	afunc	_bc_NanuMulm
	mov		r12,sp
	stmdb	sp!,{r4-r11,r14}		// r0: R, r1: A, r2: M,  r3: t
	ldmia	r12,{r4-r7}					// r4: b, r5: f, r6: al, r7:ml

	// r8:r9 = q
	// r10:r11 = p
	// r12: c
	// r14: tmp

	ldr		r12,[r1],#4
	sub		r6,r6,#1
	umull	r10,r11,r12,r4			// p = ...
	ldr		r12,[r2],#4
	umull	r8,r9,r12,r3			// q = ...
	ldr		r12,[r0]				// R[0]
	adds	r8,r8,r12
	adc		r9,r9,#0				// q += *R
	adds	r10,r10,r8				// p += q(lo)
	adc		r11,r11,#0
	adds	r10,r11,r9
	mov		r11,#0
	adc		r14,r11,r11				// p = q(hi)+q(hi), c = p(hi), p(hi)=0
0:
	subs	r6,r6,#1
	ldrpl	r12,[r1],#4
	umlalpl	r10,r11,r12,r4			// if (al-- >= 0 ) p += *A++ * b
	ldr		r8,[r0,#4]
	mov		r9,#0					// q = R[1]
	ldr		r12,[r2],#4
	umlal	r8,r9,r12,r3			// q += *M++ * t
	adds	r8,r8,r10
	adc		r9,r9,#0				// q ++ p(lo)
	adds	r10,r11,r9
	mov		r11,#0
	adc		r11,r11,r11
	adds	r10,r10,r14
	adc		r14,r11,#0				// p = p(hi) + q(hi) + c, c = p(hi), p = p(lo)
	mov		r11,#0
	str		r8,[r0],#4				// *R++ = q(lo)
	subs	r7,r7,#1				// l--
	bne		0b
	adds	r10,r10,r5
	str		r10,[r0]
	adc		r0,r11,r14
	ldmia	sp!,{r4-r11,r14}
	bx		lr
	.endfunc

	afunc	_bc_NanuMuls

	// r0	R
	// r1	M
	// r2	q
	// r3	l

	stmdb	sp!,{r4,r5}
	subs	r5,r5,r5
	mov		r4,r5
0:
	ldr		r12,[r1],#4
	umlal	r4,r5,r12,r2
	ldr		r12,[r0]
	sbcs	r12,r12,r4
	str		r12,[r0],#4
	mov		r4,r5
	mov		r5,#0
1:
	sub		r3,r3,#1
	tst		r3,r3
	bpl		0b
	rsc		r0,r4,#0
	rsc		r1,r5,#0
	ldmia	sp!,{r4,r5}
	bx		lr
	.endfunc

/*
*	Calculates R = ( R << 32 ) + Y * x where R is 'l' long and Y is 's' long.
*	Only the lower 'l' words of the result are stored, the up to 33 most
*	significant bits are returned.
*/

#if 0
unsigned long long _bc_NanuMulr( unsigned *R, unsigned *Y, unsigned x,
								 unsigned s, unsigned l )
{
unsigned long long t;
unsigned i;
unsigned w;

	for ( t = 0, i = 0 ; i < l ; i++ ) {

		if ( i < s ) t += Y[ i ] * (unsigned long long) x;
		w  = t;
		t >>= 32;
		t  += R[ i ];
		R[ i ] = w;
	}

	return( t );
}

#endif

	// R	r0
	// Y	r1
	// x	r2
	// s	r3
	// l	r12

	afunc	_bc_NanuMulr
	ldr		r12,[sp]
	stmdb	sp!,{r4-r7}
	mov		r4,#0		// i
	mov		r5,#0		// t hi
	mov		r6,#0		// t lo
	b		1f
0:
	cmp		r4,r3
	ldrlt	r7,[r1,r4,lsl #2]
	umlallt	r6,r5,r7,r2
	add		r7,r0,r4,lsl #2
	swp		r6,r6,[r7]
	adds	r6,r6,r5
	mov		r5,#0
	adc		r5,r5,r5
	add		r4,r4,#1
1:
	cmp		r4,r12
	blt		0b
	mov		r0,r6
	mov		r1,r5
	ldmia	sp!,{r4-r7}
	bx		lr
#endif

