1/* ANSI C standard library function strncpy.
2
3   Copyright (c) 2001-2008 Tensilica Inc.
4
5   Permission is hereby granted, free of charge, to any person obtaining
6   a copy of this software and associated documentation files (the
7   "Software"), to deal in the Software without restriction, including
8   without limitation the rights to use, copy, modify, merge, publish,
9   distribute, sublicense, and/or sell copies of the Software, and to
10   permit persons to whom the Software is furnished to do so, subject to
11   the following conditions:
12
13   The above copyright notice and this permission notice shall be included
14   in all copies or substantial portions of the Software.
15
16   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
23
24#include "xtensa-asm.h"
25
26	.text
27.begin schedule
28	.align	4
29	.literal_position
30__strncpy_aux:
31
32.Lsrc1mod2: // src address is odd
33	l8ui	a8, a3, 0	// get byte 0
34	addi	a3, a3, 1	// advance src pointer
35	s8i	a8, a10, 0	// store byte 0
36	addi	a4, a4, -1	// decrement n
37	beqz    a4, .Lret       // if n is zero
38	addi	a10, a10, 1	// advance dst pointer
39	beqz	a8, .Lfill	// if byte 0 is zero
40	bbci.l	a3, 1, .Lsrcaligned // if src is now word-aligned
41
42.Lsrc2mod4: // src address is 2 mod 4
43	l8ui	a8, a3, 0	// get byte 0
44	addi	a4, a4, -1	// decrement n
45	s8i	a8, a10, 0	// store byte 0
46	beqz    a4, .Lret       // if n is zero
47	addi	a10, a10, 1	// advance dst pointer
48	beqz	a8, .Lfill	// if byte 0 is zero
49	l8ui	a8, a3, 1	// get byte 0
50	addi	a3, a3, 2	// advance src pointer
51	s8i	a8, a10, 0	// store byte 0
52	addi	a4, a4, -1	// decrement n
53	beqz    a4, .Lret       // if n is zero
54	addi	a10, a10, 1	// advance dst pointer
55	bnez	a8, .Lsrcaligned
56	j	.Lfill
57
58.Lret:
59#ifdef PSRAM_FIX
60	memw
61#endif
62	leaf_return
63
64
65	.align	4
66	.global	strncpy
67	.type	strncpy, @function
68strncpy:
69	leaf_entry sp, 16
70	/* a2 = dst, a3 = src */
71
72	mov	a10, a2		// leave dst in return value register
73	beqz    a4, .Lret       // if n is zero
74
75	movi	a11, MASK0
76	movi	a5, MASK1
77	movi	a6, MASK2
78	movi	a7, MASK3
79	bbsi.l	a3, 0, .Lsrc1mod2
80	bbsi.l	a3, 1, .Lsrc2mod4
81.Lsrcaligned:
82
83	/* Check if the destination is aligned.  */
84	movi	a8, 3
85	bnone	a10, a8, .Laligned
86
87	j	.Ldstunaligned
88
89
90/* Fill the dst with zeros -- n is at least 1.  */
91
92.Lfill:
93	movi	a9, 0
94	bbsi.l	a10, 0, .Lfill1mod2
95	bbsi.l	a10, 1, .Lfill2mod4
96.Lfillaligned:
97	blti	a4, 4, .Lfillcleanup
98
99	/* Loop filling complete words with zero.  */
100#if XCHAL_HAVE_LOOPS
101
102	srai	a8, a4, 2
103	loop	a8, 1f
104	s32i	a9, a10, 0
105	addi	a10, a10, 4
106
1071:	slli	a8, a8, 2
108	sub	a4, a4, a8
109
110#else /* !XCHAL_HAVE_LOOPS */
111
1121:	s32i	a9, a10, 0
113	addi	a10, a10, 4
114	addi	a4, a4, -4
115	bgei    a4, 4, 1b
116
117#endif /* !XCHAL_HAVE_LOOPS */
118
119	beqz	a4, 2f
120
121.Lfillcleanup:
122	/* Fill leftover (1 to 3) bytes with zero.  */
123	s8i	a9, a10, 0	// store byte 0
124	addi	a4, a4, -1	// decrement n
125	addi	a10, a10, 1
126	bnez    a4, .Lfillcleanup
127
1282:
129#ifdef PSRAM_FIX
130	memw
131#endif
132	leaf_return
133
134.Lfill1mod2: // dst address is odd
135	s8i	a9, a10, 0	// store byte 0
136	addi	a4, a4, -1	// decrement n
137	beqz    a4, 2b		// if n is zero
138	addi    a10, a10, 1	// advance dst pointer
139	bbci.l	a10, 1, .Lfillaligned // if dst is now word-aligned
140
141.Lfill2mod4: // dst address is 2 mod 4
142	s8i	a9, a10, 0	// store byte 0
143	addi	a4, a4, -1	// decrement n
144	beqz    a4, 2b		// if n is zero
145	s8i	a9, a10, 1	// store byte 1
146	addi	a4, a4, -1	// decrement n
147	beqz    a4, 2b		// if n is zero
148	addi    a10, a10, 2	// advance dst pointer
149	j	.Lfillaligned
150
151
152/* dst is word-aligned; src is word-aligned; n is at least 1.  */
153
154	.align	4
155#if XCHAL_HAVE_LOOPS
156#if XCHAL_HAVE_DENSITY
157	/* (2 mod 4) alignment for loop instruction */
158#else
159	/* (1 mod 4) alignment for loop instruction */
160	.byte	0
161	.byte	0
162#endif
163#endif
164.Laligned:
165#if XCHAL_HAVE_LOOPS
166#if XCHAL_HAVE_DENSITY
167	_movi.n	a8, 0		// set up for the maximum loop count
168#else
169	_movi	a8, 0		// set up for the maximum loop count
170#endif
171	loop	a8, 1f		// loop forever (almost anyway)
172	blti	a4, 5, .Ldstunaligned // n is near limit; do one at a time
173	l32i	a8, a3, 0	// get word from src
174	addi	a3, a3, 4	// advance src pointer
175	bnone	a8, a11, .Lz0	// if byte 0 is zero
176	bnone	a8, a5, .Lz1	// if byte 1 is zero
177	bnone	a8, a6, .Lz2	// if byte 2 is zero
178	s32i	a8, a10, 0	// store word to dst
179	addi	a4, a4, -4	// decrement n
180	addi	a10, a10, 4	// advance dst pointer
181	bnone	a8, a7, .Lfill	// if byte 3 is zero
1821:
183
184#else /* !XCHAL_HAVE_LOOPS */
185
1861:	blti	a4, 5, .Ldstunaligned // n is near limit; do one at a time
187	l32i	a8, a3, 0	// get word from src
188	addi	a3, a3, 4	// advance src pointer
189	bnone	a8, a11, .Lz0	// if byte 0 is zero
190	bnone	a8, a5, .Lz1	// if byte 1 is zero
191	bnone	a8, a6, .Lz2	// if byte 2 is zero
192	s32i	a8, a10, 0	// store word to dst
193	addi	a4, a4, -4	// decrement n
194	addi	a10, a10, 4	// advance dst pointer
195	bany	a8, a7, 1b	// no zeroes
196#endif /* !XCHAL_HAVE_LOOPS */
197
198	j	.Lfill
199
200.Lz0:	/* Byte 0 is zero.  */
201#ifdef __XTENSA_EB__
202	movi	a8, 0
203#endif
204	s8i	a8, a10, 0
205	addi	a4, a4, -1	// decrement n
206	addi	a10, a10, 1	// advance dst pointer
207	j	.Lfill
208
209.Lz1:	/* Byte 1 is zero.  */
210#ifdef __XTENSA_EB__
211        extui   a8, a8, 16, 16
212#endif
213	s16i	a8, a10, 0
214	addi	a4, a4, -2	// decrement n
215	addi	a10, a10, 2	// advance dst pointer
216	j	.Lfill
217
218.Lz2:	/* Byte 2 is zero.  */
219#ifdef __XTENSA_EB__
220        extui   a8, a8, 16, 16
221#endif
222	s16i	a8, a10, 0
223	movi	a8, 0
224	s8i	a8, a10, 2
225	addi	a4, a4, -3	// decrement n
226	addi	a10, a10, 3	// advance dst pointer
227	j	.Lfill
228
229	.align	4
230#if XCHAL_HAVE_LOOPS
231#if XCHAL_HAVE_DENSITY
232	/* (2 mod 4) alignment for loop instruction */
233#else
234	/* (1 mod 4) alignment for loop instruction */
235	.byte	0
236	.byte	0
237#endif
238#endif
239.Ldstunaligned:
240
241#if XCHAL_HAVE_LOOPS
242#if XCHAL_HAVE_DENSITY
243	_movi.n	a8, 0		// set up for the maximum loop count
244#else
245	_movi	a8, 0		// set up for the maximum loop count
246#endif
247	loop	a8, 2f		// loop forever (almost anyway)
248#endif
2491:	l8ui	a8, a3, 0
250	addi	a3, a3, 1
251#ifdef PSRAM_FIX
252	nop
253	nop
254	nop
255#endif
256	s8i	a8, a10, 0
257	addi	a4, a4, -1
258	beqz	a4, 3f
259	addi	a10, a10, 1
260#if XCHAL_HAVE_LOOPS
261	beqz	a8, 2f
262#else
263	bnez	a8, 1b
264#endif
2652:	j	.Lfill
266
2673:
268#ifdef PSRAM_FIX
269	memw
270#endif
271	leaf_return
272.end schedule
273
274	.size	strncpy, . - strncpy
275