/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:strcpy.s 12.0$ */
/* $ACIS:strcpy.s 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/libc/ca/gen/RCS/strcpy.s,v $ */

	.data
rcsid:	.asciz	"$Header:strcpy.s 12.0$"
	.text

#include "LINKG.h"

 #
 # version of strcpy written in assembler for better performance
 #	strcpy(s1,s2) char *s1,*s2;
 #
ENTRY(strcpy)
	mr	r0,r2		# save starting location of s1
	nilz	r5,r3,0x03	# round string addr down to word boundary
	jeq	Levenword	# short circuit - already on word boundary
	s	r3,r5		# more of the rounding
	sli	r5,4		# calc offset into following switch statement
	get	r4,$1f-16	# get address of beginning of switch statement
	a	r4,r5		# add displacement of the case
	brx	r4		# branch to calculated case and
	ls	r4,0(r3)	# get first word (possibly rounded down).
 # At this point:
 # r3 points to string or the nearest word boundary before string
 # if string is not on a word boundary.
 # r4 contains 4 bytes as pointed to by r3.
 # The following is a switch statement. Initially, control jumps to one of
 # the labels 0, 1, 2 or 3 depending on the location of string's first byte.
 # 

 # code at 1f, 2f must be exactly 16 bytes long to match switch above
 # The switch:

1:
	niuz	r5,r4,0x00ff	# get byte 1 from r4		(4)
	beq	Ldone		# branch if byte 1 is null	(4)
	sri16	r5,0		#				(2)
	stc	r5,0(r2)	#				(4)
	inc	r2,1		#				(2)

2:
	nilz	r5,r4,0xff00	# get byte 2 from r4
	beq	Ldone		# branch if byte 2 is null
	sri	r5,8
	stc	r5,0(r2)
	inc	r2,1

3:
	nilz	r5,r4,0x00ff	# get byte 3 from r4
	jeq	Ldone
	stcs	r5,0(r2)
	inc	r2,1

 # At this point r3 is word aligned on s2.
 # Determine alignment of r2: branch to one of two algorithms
 # depending on whether r2 is word, half-word or odd aligned.
 # If 1/2 word aligned, to 1/2 word puts into s1.
 # if odd, do 1 byte-1/2 word-1 byte puts.
	inc	r3,4
Levenword:
	nilz	r5,r2,0x01	# high bit on?
	bnex	Lodd		# Branch to odd/even and
	ls	r4,0(r3)	# get next word via r3.
Leven:
	niuz	r5,r4,0xff00	# get byte 0 from r4
	jeq	0f
	niuz	r5,r4,0x00ff	# get byte 1 from r4
	jeq	1f
	srpi16	r4,0		# get byte 0 and 1 into r5
	putha	r5,0(r2)

	nilz	r5,r4,0xff00	# get byte 2 from r4
	jeq	2f		# branch if byte 2 is null
	nilz	r5,r4,0x00ff	# get byte 3 from r4
	jeq	3f
	putha	r4,2(r2)
	inc	r2,4
	inc	r3,4
	bx	Leven		# null not found in byte 3, try next word and
	 ls	r4,0(r3)	# get next s2 word.

 # r4 has A 0 X X; r2 is halfword aligned
1:
	srpi16	r4,0		# get byte 0 and 1 into r5
	putha	r5,0(r2)
	brx	r15		# return and
	mr	r2,r0		# return base of s1
	
 # r4 has A B C 0; we've stored A B now do C 0
3:	putha	r4,2(r2)
	brx	r15
	mr	r2,r0		# return base of s1.

2:	inc	r2,2
0:	get	r5,$0
	stcs	r5,0(r2)
	brx	r15		# return and
	mr	r2,r0		# Return base of s1.

Lodd:
	niuz	r5,r4,0xff00	# get byte 0 from r4
	jeq	Ldone		# 

	sri16	r5,8
	stcs	r5,0(r2)
	
	niuz	r5,r4,0x00ff
	jeq	1f
	nilz	r5,r4,0xff00
	jeq	2f

	srpi	r4,8		# get the two middle bytes into r5
	sth	r5,1(r2)

	nilz	r5,r4,0x00ff
	stcs	r5,3(r2)
	jeq	Lreturn
	inc	r2,4		# s1 += 4
	inc	r3,4		# s2 += 4
	bx	Lodd
	get	r4,0(r3)

2:
	srpi	r4,8		# get the two middle bytes into r5
	sth	r5,1(r2)
	brx	r15
	mr	r2,r0		# Return base of s1.

1:	inc	r2,1
Ldone:				# add null terminator and return
	get	r5,$0
	stcs	r5,0(r2)
Lreturn:			# null terminator in place, return
	brx	r15
	mr	r2,r0		# Return base of s1.


	TTNOFRM
