1/*******************************************************************************
2 *
3 * Copyright (c) 1993 Intel Corporation
4 *
5 * Intel hereby grants you permission to copy, modify, and distribute this
6 * software and its documentation.  Intel grants this permission provided
7 * that the above copyright notice appears in all copies and that both the
8 * copyright notice and this permission notice appear in supporting
9 * documentation.  In addition, Intel grants this permission provided that
10 * you prominently mark as "not part of the original" any modifications
11 * made to this software or documentation, and that the name of Intel
12 * Corporation not be used in advertising or publicity pertaining to
13 * distribution of the software or the documentation without specific,
14 * written prior permission.
15 *
16 * Intel Corporation provides this AS IS, WITHOUT ANY WARRANTY, EXPRESS OR
17 * IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY
18 * OR FITNESS FOR A PARTICULAR PURPOSE.  Intel makes no guarantee or
19 * representations regarding the use of, or the results of the use of,
20 * the software and documentation in terms of correctness, accuracy,
21 * reliability, currentness, or otherwise; and you rely on the software,
22 * documentation and results solely at your own risk.
23 *
24 * IN NO EVENT SHALL INTEL BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
25 * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
26 * OF ANY KIND.  IN NO EVENT SHALL INTEL'S TOTAL LIABILITY EXCEED THE SUM
27 * PAID TO INTEL FOR THE PRODUCT LICENSED HEREUNDER.
28 *
29 ******************************************************************************/
30
31	.file "strncat.s"
32#ifdef	__PIC
33	.pic
34#endif
35#ifdef	__PID
36	.pid
37#endif
38/*
39 * (c) copyright 1988,1993 Intel Corp., all rights reserved
40 */
41/*
42	procedure strncat  (optimized assembler version for the 80960K Series)
43
44	dest_addr = strncat (dest_addr, src_addr, max_bytes)
45
46	append the null terminated string pointed to by src_addr to the null
47	terminated string pointed to by dest_addr.  Return the original
48	dest_addr.  If the source string is longer than max_bytes, then
49	append only max_bytes bytes, and tack on a null byte on the end.
50
51	This routine will fail if the source and destination string
52	overlap (in particular, if the end of the source is overlapped
53	by the beginning of the destination).  The behavior is undefined.
54	This is acceptable according to the draft C standard.
55
56	Undefined behavior will also occur if the end of the source string
57	(i.e. the terminating null byte) is in the last two words of the
58	program's allocated memory space.  This is so because strncat fetches
59	ahead.  Disallowing the fetch ahead would impose a severe performance
60	penalty.
61
62	Strategy:
63
64	First, skip to the null byte in the destination string.  Then
65	fetch the source string by words and store them by words to the
66	destination string, until there are fewer than three bytes left
67	to copy.  Then, using the last word of the source (the one that
68	contains the remaining 0, 1, 2, or 3 bytes to be copied), store
69	a byte at a time until Ldone.
70
71	If, before exhausting the max_byte count, the null byte is encountered
72	in the source string, then just copy up thru the null byte.
73
74	Tactics:
75
76	1) Do NOT try to fetch and store the words in a word aligned manner
77	because, in my judgement, the performance degradation experienced due
78	to non-aligned accesses does NOT outweigh the time and complexity added
79	by the preamble and convoluted body that would be necessary to assure
80	alignment.
81*/
82
83	.globl _strncat
84	.globl __strncat
85	.leafproc _strncat,__strncat
86	.align    2
87_strncat:
88#ifndef __PIC
89 	lda	Lrett,g14
90#else
91 	lda	Lrett-(.+8)(ip),g14
92#endif
93__strncat:
94	mov	g14,g6
95	cmpibge	0, g2, Lno_operation	# Lexit early if max_bytes <= 0
96	mov	g0, g5
97Lskip_word_loop:
98	ld	(g5), g7	# fetch word of dest string
99	addo	4, g5, g5	# post-increment dest ptr
100	scanbyte 0, g7		# does it contain null byte?
101	bno	Lskip_word_loop	# if not, loop
102	subo	5, g5, g5	# adjust dest ptr
103	lda	0xff, g3	# byte extraction mask = 0xff;
104Lskip_byte_loop:
105	and	g7, g3, g14	# extract byte of last word of dest string
106	cmpo	0, g14		# is it null?
107	addo	1, g5, g5	# adjust dest ptr
108	shro	8, g7, g7	# position next byte for extraction
109	bne	Lskip_byte_loop	# loop if null not found yet
110
111	ld	(g1), g7	# fetch first word of source string
112Lwloop:				# word copying loop
113	cmpo	4, g2		# max_bytes < 4 ?
114	addo	4, g1, g1	# post-increment source ptr
115	bge	Lcloop.a		# branch if less than 4 bytes to move
116	scanbyte 0, g7		# is null byte reached yet?
117	mov	g7, g4		# keep a copy of the source word
118	be	Lcloop		# branch if null byte reached
119	ld	(g1), g7	# pre-fetch next word of source
120	subo	4, g2, g2	# reduce max_byte counter
121	st	g4, (g5)	# store current word
122	addo	4, g5, g5	# post-increment destination ptr
123	b	Lwloop
124
125Lcloop.b:
126	addo	1, g5, g5	# post-increment destination ptr
127	shro	8, g7, g7	# position next byte for extraction
128Lcloop:				# character copying loop  (max_byte > 3)
129	and	g3, g7, g4	# extract character
130	cmpo	0, g4 		# is it null?
131	stob	g4, (g5)	# store it
132	bne	Lcloop.b		# loop if null not encountered yet
133
134	bx	(g6)		# g0 = dest string address; g14 = 0
135Lrett:
136	ret
137
138Lcloop.c:
139	addo	1, g5, g5	# post-increment destination ptr
140	shro	8, g7, g7	# position next byte for extraction
141Lcloop.a:			# character copying loop  (max_byte <= 3)
142	cmpdeco	0,g2,g2		# max_byte == 0?
143	and	g3, g7, g4	# extract character
144	be	Ldone		# store null and Lexit if max_byte exhausted
145	cmpo	0, g4 		# is it null?
146	stob	g4, (g5)	# store it
147	bne	Lcloop.c		# loop if null not encountered yet
148
149Ldone:	stob	g14, (g5)	# store trailing null
150	bx	(g6)		# g0 = dest string address; g14 = 0
151
152Lno_operation: mov 0, g14	# conform to register conventions
153	bx	(g6)
154
155/* end of strncat */
156