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#include <picolibc.h>
32
33	.file "strncat.s"
34#ifdef	__PIC
35	.pic
36#endif
37#ifdef	__PID
38	.pid
39#endif
40/*
41 * (c) copyright 1988,1993 Intel Corp., all rights reserved
42 */
43/*
44	procedure strncat  (optimized assembler version for the 80960K Series)
45
46	dest_addr = strncat (dest_addr, src_addr, max_bytes)
47
48	append the null terminated string pointed to by src_addr to the null
49	terminated string pointed to by dest_addr.  Return the original
50	dest_addr.  If the source string is longer than max_bytes, then
51	append only max_bytes bytes, and tack on a null byte on the end.
52
53	This routine will fail if the source and destination string
54	overlap (in particular, if the end of the source is overlapped
55	by the beginning of the destination).  The behavior is undefined.
56	This is acceptable according to the draft C standard.
57
58	Undefined behavior will also occur if the end of the source string
59	(i.e. the terminating null byte) is in the last two words of the
60	program's allocated memory space.  This is so because strncat fetches
61	ahead.  Disallowing the fetch ahead would impose a severe performance
62	penalty.
63
64	Strategy:
65
66	First, skip to the null byte in the destination string.  Then
67	fetch the source string by words and store them by words to the
68	destination string, until there are fewer than three bytes left
69	to copy.  Then, using the last word of the source (the one that
70	contains the remaining 0, 1, 2, or 3 bytes to be copied), store
71	a byte at a time until Ldone.
72
73	If, before exhausting the max_byte count, the null byte is encountered
74	in the source string, then just copy up thru the null byte.
75
76	Tactics:
77
78	1) Do NOT try to fetch and store the words in a word aligned manner
79	because, in my judgement, the performance degradation experienced due
80	to non-aligned accesses does NOT outweigh the time and complexity added
81	by the preamble and convoluted body that would be necessary to assure
82	alignment.
83*/
84
85	.globl _strncat
86	.globl __strncat
87	.leafproc _strncat,__strncat
88	.align    2
89_strncat:
90#ifndef __PIC
91 	lda	Lrett,g14
92#else
93 	lda	Lrett-(.+8)(ip),g14
94#endif
95__strncat:
96	mov	g14,g6
97	cmpibge	0, g2, Lno_operation	# Lexit early if max_bytes <= 0
98	mov	g0, g5
99Lskip_word_loop:
100	ld	(g5), g7	# fetch word of dest string
101	addo	4, g5, g5	# post-increment dest ptr
102	scanbyte 0, g7		# does it contain null byte?
103	bno	Lskip_word_loop	# if not, loop
104	subo	5, g5, g5	# adjust dest ptr
105	lda	0xff, g3	# byte extraction mask = 0xff;
106Lskip_byte_loop:
107	and	g7, g3, g14	# extract byte of last word of dest string
108	cmpo	0, g14		# is it null?
109	addo	1, g5, g5	# adjust dest ptr
110	shro	8, g7, g7	# position next byte for extraction
111	bne	Lskip_byte_loop	# loop if null not found yet
112
113	ld	(g1), g7	# fetch first word of source string
114Lwloop:				# word copying loop
115	cmpo	4, g2		# max_bytes < 4 ?
116	addo	4, g1, g1	# post-increment source ptr
117	bge	Lcloop.a		# branch if less than 4 bytes to move
118	scanbyte 0, g7		# is null byte reached yet?
119	mov	g7, g4		# keep a copy of the source word
120	be	Lcloop		# branch if null byte reached
121	ld	(g1), g7	# pre-fetch next word of source
122	subo	4, g2, g2	# reduce max_byte counter
123	st	g4, (g5)	# store current word
124	addo	4, g5, g5	# post-increment destination ptr
125	b	Lwloop
126
127Lcloop.b:
128	addo	1, g5, g5	# post-increment destination ptr
129	shro	8, g7, g7	# position next byte for extraction
130Lcloop:				# character copying loop  (max_byte > 3)
131	and	g3, g7, g4	# extract character
132	cmpo	0, g4 		# is it null?
133	stob	g4, (g5)	# store it
134	bne	Lcloop.b		# loop if null not encountered yet
135
136	bx	(g6)		# g0 = dest string address; g14 = 0
137Lrett:
138	ret
139
140Lcloop.c:
141	addo	1, g5, g5	# post-increment destination ptr
142	shro	8, g7, g7	# position next byte for extraction
143Lcloop.a:			# character copying loop  (max_byte <= 3)
144	cmpdeco	0,g2,g2		# max_byte == 0?
145	and	g3, g7, g4	# extract character
146	be	Ldone		# store null and Lexit if max_byte exhausted
147	cmpo	0, g4 		# is it null?
148	stob	g4, (g5)	# store it
149	bne	Lcloop.c		# loop if null not encountered yet
150
151Ldone:	stob	g14, (g5)	# store trailing null
152	bx	(g6)		# g0 = dest string address; g14 = 0
153
154Lno_operation: mov 0, g14	# conform to register conventions
155	bx	(g6)
156
157/* end of strncat */
158