/* 
 * Mach Operating System
 * Copyright (c) 1993 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 * HISTORY
 * $Log:	bcopy.s,v $
 * Revision 2.2  93/08/10  15:20:32  mrt
 * 	Created.
 * 	[93/06/18            cmaeda]
 * 
 */	
/*
 *	File:	mips_bcopy.s
 *	Author:	Chris Maeda
 *	Date:	June 1993
 *
 *	Fast copy routine.  Derived from aligned_block_copy.
 */	

#include <mach/mips/asm.h>

/*
 *	bcopy(caddr_t src, caddr_t dst, unsigned int len)
 *
 *	a0 	src address
 *	a1	dst address
 *	a2	length
 */

	.set	noat
	.set	noreorder
LEAF(bcopy)
	/*
	 *	Make sure we can copy forwards.
	 */
	sltu	t0,a0,a1	# t0 == a0 < a1
	addu	a3,a0,a2	# a3 == end of source
	sltu	t1,a1,a3	# t1 == a1 < a0+a2
	and	t2,t0,t1	# overlap -- copy backwards
	bne	t2,zero,backcopy

	/*
	 * 	There are four alignment cases (with frequency)
	 *	(Based on measurements taken with a DECstation 5000/200
	 *	 inside a Mach kernel.)
	 *
	 * 	aligned   -> aligned		(mostly)
	 * 	unaligned -> aligned		(sometimes)
	 * 	aligned,unaligned -> unaligned	(almost never)
	 *
	 *	Note that we could add another case that checks if
	 *	the destination and source are unaligned but the 
	 *	copy is alignable.  eg if src and dest are both
	 *	on a halfword boundary.
	 */
	andi	t1,a1,3		# get last 3 bits of dest
	bne	t1,zero,bytecopy
	andi	t0,a0,3		# get last 3 bits of src
	bne	t0,zero,destaligned

	/*
	 *	Forward aligned->aligned copy, 8*4 bytes at a time.
	 */
	li	AT,-32
	and	t0,a2,AT	/* count truncated to multiple of 32 */
	addu	a3,a0,t0	/* run fast loop up to this address */
	sltu	AT,a0,a3	/* any work to do? */
	beq	AT,zero,wordcopy
	subu	a2,t0

	/*
	 *	loop body
	 */
cp:
	lw	v0,0(a0)
	lw	v1,4(a0)
	lw	t0,8(a0)
	lw	t1,12(a0)
	addu	a0,32
	sw	v0,0(a1)
	sw	v1,4(a1)
	sw	t0,8(a1)
	sw	t1,12(a1)
	lw	t1,-4(a0)
	lw	t0,-8(a0)
	lw	v1,-12(a0)
	lw	v0,-16(a0)
	addu	a1,32
	sw	t1,-4(a1)
	sw	t0,-8(a1)
	sw	v1,-12(a1)
	bne	a0,a3,cp
	sw	v0,-16(a1)

	/*
	 *	Copy a word at a time, no loop unrolling.
	 */
wordcopy:
	andi	t2,a2,3		# get byte count / 4
	subu	t2,a2,t2	# t2 = number of words to copy * 4
	beq	t2,zero,bytecopy
	addu	t0,a0,t2	# stop at t0
	subu	a2,a2,t2
1:
	lw	v0,0(a0)
	addu	a0,4
	sw	v0,0(a1)
	bne	a0,t0,1b
	addu	a1,4

bytecopy:
	beq	a2,zero,copydone	# nothing left to do?
	nop
2:
	lb	v0,0(a0)
	addu	a0,1
	sb	v0,0(a1)
	subu	a2,1
	bgtz	a2,2b
	addu	a1,1

copydone:
	j	ra
	nop

	/*
	 *	Copy from unaligned source to aligned dest.
	 */
destaligned:
	andi	t0,a2,3		# t0 = bytecount mod 4
	subu	a3,a2,t0	# number of words to transfer
	beq	a3,zero,bytecopy
	nop
	move	a2,t0		# this many to do after we are done
	addu	a3,a0,a3	# stop point

3:
#if MIPSEL	/* little-endian */
	lwr	v0,0(a0)
	lwl	v0,3(a0)
#else		/* big-endian */
	lwl	v0,0(a0)
	lwr	v0,3(a0)
#endif
	addi	a0,4
	sw	v0,0(a1)
	bne	a0,a3,3b
	addi	a1,4

	j	bytecopy
	nop

	/*
	 *	Copy by bytes backwards.
	 */
backcopy:
	blez	a2,copydone	# nothing left to do?
	addu	t0,a0,a2	# end of source
	addu	t1,a1,a2	# end of destination
4:
	lb	v0,-1(t0)	
	subu	t0,1
	sb	v0,-1(t1)
	bne	t0,a0,4b
	subu	t1,1
	j	ra
	nop
	
	END(bcopy)
	.set	reorder
	.set	at
