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 "strcp_ca.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/*
43	procedure strcpy  (optimized assembler version for the CA)
44
45	dest_addr = strcpy (dest_addr, src_addr)
46
47	copy the null terminated string pointed to by src_addr to
48	the string space pointed to by dest_addr.  Return the original
49	dest_addr.
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 word of the program's
58	allocated memory space.  This is so because, in several cases, strcpy
59	will fetch ahead one word.  Disallowing the fetch ahead would impose
60	a severe performance penalty.
61
62	This program handles five cases:
63
64	1) both arguments start on a word boundary
65	2) neither are word aligned, but they are offset by the same amount
66	3) source is word aligned, destination is not
67	4) destination is word aligned, source is not
68	5) neither is word aligned, and they are offset by differing amounts
69
70	At the time of this writing, only g0 thru g7 and g13 are available
71	for use in this leafproc;  other registers would have to be saved and
72	restored.  These nine registers, plus tricky use of g14 are sufficient
73	to implement the routine.  The registers are used as follows:
74
75	g0  original dest ptr;  not modified, so that it may be returned.
76	g1  src ptr;  shift count
77	g2  dest ptr;  4 bytes of src
78	g3  src ptr (word aligned)
79	g4  dest ptr (word aligned)
80	g5  0xff  --  byte extraction mask
81	g6  lsw of double word for extraction of 4 bytes (little endian)
82	    msw of double word for extraction of 4 bytes (big endian)
83	g7  msw of double word for extraction of 4 bytes (little endian)
84	    lsw of double word for extraction of 4 bytes (big endian)
85	g13 return address
86	g14 byte extracted.  When reaches null byte, which is zero, we will
87	    be in conformance with register conventions, and can return to
88	    the caller with a clear conscience.
89
90	procedure strcat
91
92	dest_addr = strcat (dest_addr, src_addr)
93
94	Appends the string pointed to by src_addr to the string pointed
95	to by dest_addr.  The first character of the source string is
96	copied to the location initially occupied by the trailing null
97	byte of the destination string.  Thereafter, characters are copied
98	from the source to the destination up thru the null byte that
99	trails the source string.
100*/
101
102#if __i960_BIG_ENDIAN__
103#define MSW g6
104#define LSW g7
105#else
106#define LSW g6
107#define MSW g7
108#endif
109
110	.globl	_strcpy, _strcat
111	.globl	__strcpy, __strcat
112	.leafproc	_strcpy, __strcpy
113	.leafproc	_strcat, __strcat
114	.align	2
115_strcat:
116#ifndef __PIC
117	lda	Lrett,g14
118#else
119	lda	Lrett-(.+8)(ip),g14
120#endif
121__strcat:
122	notand	g0,3,g4		# extract word addr of start of dest
123	lda	(g14),g13	# preserve return address
124	and	g0,3,LSW	# extract byte offset of dest
125	ld	(g4),MSW	# fetch word containing at least first byte
126	shlo	3,LSW,g14	# get shift count for making mask for first word
127	subi	1,0,LSW		# mask initially all ones
128#if __i960_BIG_ENDIAN__
129	shro	g14,LSW,LSW	# get mask for bytes needed from first word
130	lda	0xff000000,g5	# byte extraction mask
131#else
132	shlo	g14,LSW,LSW	# get mask for bytes needed from first word
133	lda	0xff,g5		# byte extraction mask
134#endif
135	notor	MSW,LSW,MSW	# set unneeded bytes to all ones
136Lsearch_for_word_with_null:
137	scanbyte 0,MSW		# check for null byte
138	lda	4(g4),g4	# post-increment dest word pointer
139	mov	MSW,LSW		# keep a copy of current word
140	ld	(g4),MSW	# fetch next word of dest
141	bno.t	Lsearch_for_word_with_null	# branch if null not found yet
142	and	g5,LSW,g14	# extract byte
143	cmpo	0,g14		# branch if null is first byte of word
144	subo	4,g4,g4		# move dest word ptr back to word with null
145	notand	g1,3,g3		# extract word addr of start of src
146	lda	(g4),g2		# set dest byte ptr to 1st byte of word w/ null
147	be.f	Lcase_14
148Lsearch_for_null:
149#if __i960_BIG_ENDIAN__
150	shro	8,g5,g5		# move mask down to next byte
151#else
152	shlo	8,g5,g5		# move mask up to next byte
153#endif
154	lda	1(g2),g2	# move dest byte ptr to next byte
155	and	g5,LSW,g14	# extract byte
156	cmpobne.t 0,g14,Lsearch_for_null	# branch if null is not yet found
157	lda	0xff,g5		# byte extraction mask
158	b	Lcase_235.a
159
160
161_strcpy:
162#ifndef __PIC
163	lda 	Lrett,g14
164#else
165	lda 	Lrett-(.+8)(ip),g14
166#endif
167__strcpy:
168	notand	g0,3,g4		# extract word addr of start of dest
169	lda	(g14),g13	# preserve return address
170	cmpo	g0,g4		# check alignment of dest
171	lda	0xff,g5		# load mask for byte extraction
172	notand	g1,3,g3		# extract word addr of start of src
173	bne.f	Lcase_235	# branch if dest is NOT word aligned
174
175Lcase_14:
176	cmpo	g3,g1		# check alignment of src
177	ld	(g3),LSW	# fetch word containing at least first byte
178	shlo	3,g1,g1		# compute shift count
179	lda	4(g3),g3	# advance src word addr
180#if __i960_BIG_ENDIAN__
181	lda	0xff,g5		# byte extraction mask
182#endif
183	bne.f	Lcase_4		# branch if src is NOT word aligned
184
185Lcase_1:				# src and dest are word aligned
186	subo	4,g4,g4		# store is pre-incrementing;  back up dest addr
187Lcase_1_wloop:			# word copying loop
188	scanbyte 0,LSW		# check for null byte in src word
189	lda	(LSW),g2	# keep a copy of the src word
190	addo	4,g4,g4		# pre-increment dest addr
191	ld	(g3),LSW	# pre-fetch next word of src
192	addo	4,g3,g3		# post-increment src addr
193	bo.f	Lcase_1_cloop	# branch if word contains null byte
194	st	g2,(g4)		# store word in dest string
195	b	Lcase_1_wloop
196
197Lcase_3_cloop:
198Lcase_1_cloop:			# character copying loop
199#if __i960_BIG_ENDIAN__
200	rotate	8,g2,g2		# move next byte into position for extraction
201	and	g5,g2,g14	# extract next char
202#else
203	and	g5,g2,g14	# extract next char
204	shro	8,g2,g2		# move next byte into position for extraction
205#endif
206	cmpo	0,g14		# check for null byte
207	stob	g14,(g4)	# store the byte in dest
208	lda	1(g4),g4	# post-increment dest byte addr
209	bne.t	Lcase_1_cloop	# branch if null not reached
210
211Lexit_code:
212	bx	(g13)		# g0 = addr of dest;  g14 = 0
213Lrett:
214	ret
215
216Lcase_3:				# src is word aligned; dest is not
217	addo	4,g4,g4		# move dest word ptr to first word boundary
218	mov	LSW,MSW		# make copy of first word of src
219	lda	0,g1		# initialize shift count to zero
220
221Lcase_25:
222Lcase_3_cloop_at_start:		# character copying loop for start of dest str
223#if __i960_BIG_ENDIAN__
224	rotate	8,MSW,MSW	# move next byte into position for extraction
225	and	g5,MSW,g14	# extract next char
226#else
227	and	g5,MSW,g14	# extract next char
228	shro	8,MSW,MSW	# move next byte into position for extraction
229#endif
230	cmpo	0,g14		# check for null byte
231	stob	g14,(g2)	# store the byte in dest
232	lda	1(g2),g2	# post-increment dest ptr
233	be.f	Lexit_code	# branch if null byte reached
234	cmpo	g2,g4		# have we reached word boundary in dest?
235	lda	8(g1),g1	# augment the shift counter
236	bne.t	Lcase_3_cloop_at_start
237
238Lcase_4:
239	ld	(g3),MSW	# fetch msw of operand for double shift
240#if __i960_BIG_ENDIAN__
241	subo	g1,0,g1		# Adjust shift count for big endian.
242#endif
243
244Lcase_3_wloop:
245	eshro	g1,g6,g2	# extract 4 bytes of src
246	lda	4(g3),g3	# post-increment src word addr
247	scanbyte 0,g2		# check for null byte
248	lda	(MSW),LSW	# move msw to lsw
249	ld	(g3),MSW	# pre-fetch msw of operand for double shift
250	bo.f	Lcase_3_cloop	# branch if word contains null byte
251	st	g2,(g4)		# store 4 bytes to dest
252	addo	4,g4,g4		# post-increment dest ptr
253	b	Lcase_3_wloop
254
255Lcase_235:
256	lda	(g0),g2		# copy dest ptr
257Lcase_235.a:
258	cmpo	g3,g1		# check alignment of src
259	ld	(g3),LSW	# fetch word containing at least first byte
260	and	3,g1,g14	# compute shift count
261	lda	4(g3),g3	# advance src word addr
262	shlo	3,g14,g1
263	be.t	Lcase_3		# branch if dest is word aligned
264	or	g4,g14,g14	# is src earlier in word, later, or sync w/ dst
265	ld	(g3),MSW	# pre-fetch second half
266        cmpo    g2,g14		# < indicates first word of dest has more bytes
267	lda	4(g4),g4	# move dest word addr to first word boundary
268				/* than first word of source. */
269#if __i960_BIG_ENDIAN__
270	subo	g1,0,g14	# Adjust shift count for big endian.
271	eshro	g14,g6,g14	# extract four bytes
272	bge.f	1f
273#else
274	eshro	g1,g6,g14	# extract four bytes
275	bg.f	1f
276#endif
277	mov	MSW,LSW
278	lda	4(g3),g3	# move src word addr to second word boundary
2791:
280	mov	g14,MSW
281	b	Lcase_25
282
283/* end of strcpy */
284
285