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

	afunc	strncpy_fast
	tst		r2,r2					// Max length 0?
	bxeq	lr						// If yes, forget it
	stmdb	sp!,{r0,r4}				// Save the return value and a reg

	// Loop to align the destination
0:
	tst		r0,#3					// Destination aligned?
	beq		0f						// If yes, we're done here
	ldrb	r3,[r1],#1				// Fetch a byte from source
	strb	r3,[r0],#1				// Store at destination
	subs	r2,r2,#1				// Decrement the length
	tstne	r3,r3					// Test the moved byte
	bne		0b						// If we can keep going, keep going
2:
	ldmia	sp!,{r0,r4}				// Otherwise leave
	bx		lr

	// Test the alignment of the source
0:
	tst		r1,#3					// Check if the source is aligned
	beq		3f						// If yes, then it's easy
	mov		r12,#0					// Shift count
	mov		r4,#0					// Prepare the residual

	// Loop to align the source and build the residual

0:
	ldrb	r4,[r1],#1				// Fetch a byte
	orr		r3,r3,r4,lsl r12		// Place it to the residual
	add		r12,r12,#8				// Adjust the shift amount
	subs	r2,r2,#1				// Was it the last byte?
	tstne	r4,#0xff				// Or, was it a 0 byte?
	beq		2f						// If yes, terminate
	tst		r1,#3					// Is the source now aligned?
	bne		0b						// If not, keep going
	b		1f						// If yes, start the word fetch

	// Loop to move 4 misaligned bytes
0:
	orr		r4,r4,r3,lsl r12		// Create a new full word
	str		r4,[r0],#4				// Store it
	rsb		r4,r12,#32				// Work out the shift amount
	mov		r4,r3,lsr r4			// Create the new residual
1:
	ldr		r3,[r1],#4				// Fetch the next word
	subs	r2,r2,#4				// Do we still have 4 bytes to fetch?
	ble		1f						// If not, we abort the loop
	tst		r3,#0xff				// Check if it has a 0 byte
	tstne	r3,#0xff00
	tstne	r3,#0xff0000
	tstne	r3,#0xff000000
	bne		0b						// No terminator, keep going

	// Empty the residual

1:
	add		r2,r2,#4				// Restore the byte count

0:
	strb	r4,[r0],#1				// Store the next byte of the residual
	mov		r4,r4,lsr #8			// Adjust the residual
	subs	r12,r12,#8				// Decrement the shift count
	bne		0b						// If the residual is not empty, keep going

	// Store bytes from the prefetch word until 0 or limit is found

0:
	subs	r2,r2,#1				// Decrement the remaining count
	ble		2b						// If we're done, leave
	ands	r4,r3,#0xff				// Test the byte we'll store
	strb	r4,[r0],#1				// Then store it
	mov		r3,r3,lsr #8			// Prepare the next byte
	bne		0b						// If the stored one wasn't 0, keep going
	b		2b						// otherwise return

	// Premature end of loading the residual (a 0 was found before completion)

2:
	rsb		r12,r12,#32				// Shift amount to align partial residual
	mov		r3,r4,lsr r12			// Move aligned residual to the word reg
	b		0b						// Then go to the store loop

	// Source and destination are both aligned

3:
	ldr		r3,[r1],#4				// Fetch a source word
	subs	r2,r2,#4				// Can we still move 4 bytes ?
	bmi		1f
	tst		r3,#0xff				// Check if it has a 0 byte
	tstne	r3,#0xff00
	tstne	r3,#0xff0000
	tstne	r3,#0xff000000
	strne	r3,[r0],#4				// Store the word
	bne		3b						// Go for the next word
1:
	add		r2,r2,#4				// Restore R2
	beq		0b						// Go to store if yes

