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

#include <chips/ARM/func.h>

#define	N(x)	(8*(x))
#define	M(x)	(32-N(x))

/*
*	Copy forward with a non-zero offset.
*	The parameter n is the offset (1, 2 or 3)
*/

	.macro	COPY n
0:
	ldr		r12,[r1],#4				// Load 4 bytes
	orr		r3,r3,r12,lsl #N(\n)	// Build a word
	str		r3,[r0],#4				// Store it
	mov		r3,r12,lsr #M(\n)		// Get the new residual
offs\n:
	subs	r2,r2,#4				// 4 more bytes left ?
	bpl		0b
	adds	r2,r2,#8				// Bytes left, flags set
	mov		r12,#\n					// Number of residual bytes buffered
	b		final
	.endm

	afunc	memcpy_fast
	cmp		r0,r1					// Identical pointers?
	cmpne	r2,#0					// Or zero copy length?
	bxeq	lr						// If either is yes, return
	str		r0,[sp,#-4]!			// Save R0
0:
	cmp		r2,#4					// At least 4 bytes remaining?
	blo		1f						// If not, keep copying bytes
	tst		r0,#3					// Is the destination aligned?
	beq		0f						// If yes, we're in business
1:
	subs	r2,r2,#1				// Otherwise, any more bytes left?
	bmi		done					// If not, just return
	ldrb	r12,[r1],#1				// If yes, fetch the next byte
	strb	r12,[r0],#1				// then store it and
	b		0b						// go to test the alignment again
0:
	tst		r1,#3					// Is the source aligned?
	beq		offs0					// If yes, just copy
	sub		r2,r2,#4				// Assure that we don't read beyond the end
	ldrb	r3,[r1],#1				// Not yet, fetch a byte
	tst		r1,#3					// Is it aligned now?
	beq		offs1					// If yes, copy with offs. 1
	ldrb	r12,[r1],#1				// If not, get the next byte
	orr		r3,r3,r12,lsl #8		// and build the residual
	tst		r1,#3					// Is it aligned now?
	beq		offs2					// If yes, copy with offs. 2
	ldrb	r12,[r1],#1				// If not, get the next byte
	orr		r3,r3,r12,lsl #16		// and build the residual
	b		offs3

	// Copy, both addresses are aligned

0:
	ldmia	r1!,{r3,r12}			// Get 8 bytes
	stmia	r0!,{r3,r12}			// Store them
offs0:
	subs	r2,r2,#8				// 8 more bytes left?
	bpl		0b						// If yes, do it again
	adds	r2,r2,#4				// At least a word left?
	ldrpl	r3,[r1],#4				// If yes, then load a word
	strpl	r3,[r0],#4				// and then store it
	addmis	r2,r2,#4				// Number of bytes left, flags set
	mov		r12,#0					// No residual is buffered
	b		final

	// Store the residual bytes

0:
	subs	r12,r12,#1				// Number of residuals down
	ldrmib	r3,[r1],#1				// If there were none, fetch a byte
	strb	r3,[r0],#1				// Store the next byte
	mov		r3,r3,lsr #8			// Get the next residual byte
	subs	r2,r2,#1
final:
	bne		0b
done:
	ldr		r0,[sp],#4
	bx		lr

	// Copy with an offset

	COPY	1
	COPY	2
	COPY	3

