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 "sncmp_ca.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/*
45	procedure strncmp  (optimized assembler version for the CA)
46
47	result = strncmp (src1_addr, src2_addr, max_bytes)
48
49	compare the null terminated string pointed to by src1_addr to
50	the string space pointed to by src2_addr.  Return 0 iff the strings
51	are equal, -1 if src1_addr is lexicly less than src2_addr, and 1
52	if it is lexicly greater.  Do not compare more than max_bytes bytes.
53
54	Undefined behavior will occur if the end of either source string
55	(i.e. the terminating null byte) is in the last word of the program's
56	allocated memory space.  This is so because, in several cases, strncmp
57	will fetch ahead one word.  Disallowing the fetch ahead would impose
58	a severe performance penalty.
59
60	This program handles five cases:
61
62	1) both arguments start on a word boundary
63	2) neither are word aligned, but they are offset by the same amount
64	3) source1 is word aligned, source2 is not
65	4) source2 is word aligned, source1 is not
66	5) neither is word aligned, and they are offset by differing amounts
67
68	At the time of this writing, only g0 thru g7 and g14 are available
69	for use in this leafproc;  other registers would have to be saved and
70	restored.  These nine registers are sufficient to implement the routine.
71	The registers are used as follows:
72
73	g0  original src1 ptr;  extracted word;  return result
74	g1  src2 ptr;  0xff  --  byte extraction mask
75	g2  maximum number of bytes to compare
76	g3  src2 word ptr
77	Little endian:
78		g4  lsw of src1
79		g5  msw of src1
80		g6  src2 word
81		g7  src1 word ptr
82	Big endian:
83		g4  msw of src1
84		g5  lsw of src1
85		g6  src1 word ptr
86		g7  src2 word
87	g13 return address
88	g14 shift count
89*/
90
91#if __i960_BIG_ENDIAN__
92#define MSW g4
93#define LSW g5
94#define SRC1 g6
95#define SRC2 g7
96#else
97#define LSW g4
98#define MSW g5
99#define SRC2 g6
100#define SRC1 g7
101#endif
102
103	.globl	_strncmp
104	.globl	__strncmp
105	.leafproc	_strncmp, __strncmp
106	.align	2
107_strncmp:
108#ifndef __PIC
109	lda 	Lrett,g14
110#else
111	lda 	Lrett-(.+8)(ip),g14
112#endif
113__strncmp:
114Lrestart:
115	notand	g0,3,SRC1	# extract word addr of start of src1
116	 lda	(g14),g13	# preserve return address
117	 cmpibge.f 0,g2,Lequal_exit	# return equality if number of bytes to
118					/* compare is none. */
119#if __i960_BIG_ENDIAN__
120	cmpo	g0,SRC1		# check alignment of src1
121#endif
122	 ld	(SRC1),LSW	# fetch word with at least first byte of src1
123	notand	g1,3,g3		# extract word addr of start of src2
124	 ld	4(SRC1),MSW	# fetch second word of src1
125#if __i960_BIG_ENDIAN__
126	 bne	Lsrc1_unaligned	# branch if src1 is unaligned
127	cmpo	g3,g1		# check alignment of src2
128	 ld	(g3),SRC2	# fetch word with at least first byte of src2
129	shlo	3,g0,g14	# compute shift count for src1
130	subo	g14,0,g14	# adjust shift count for big endian
131	 lda	8(SRC1),SRC1	# advance src1 word addr
132	 bne.f	Lsrc2_unaligned	# branch if src2 is NOT word aligned
133
134				/* src2 is word aligned */
135
136	mov	LSW,g0
137
138Lwloop2:				# word comparing loop
139	cmpo	SRC2,g0		# compare src1 and src2 words
140	 lda	0xff000000,g1	# byte extraction mask
141	mov	MSW,LSW		# move msw of src1 to lsw
142	 ld	(SRC1),MSW	# pre-fetch next msw of src1
143	addo	4,SRC1,SRC1	# post-increment src1 addr
144	 lda	4(g3),g3	# pre-increment src2 addr
145	 bne.f	Lcloop		# branch if src1 and src2 unequal
146	scanbyte 0,g0		# check for null byte in src1 word
147	 ld	(g3),SRC2	# pre-fetch next word of src2
148	mov	LSW,g0		# extract word of src1
149	 subi	4,g2,g2		# decrement maximum byte count
150	bo.f	Lequal_exit	# branch if null byte encountered
151	cmpibl.t 0,g2,Lwloop2	# branch if max_bytes not reached yet
152
153	b	Lequal_exit	# strings were equal up through max_bytes
154
155Lsrc1_unaligned:
156#endif
157	cmpo	g3,g1		# check alignment of src2
158	 ld	(g3),SRC2	# fetch word with at least first byte of src2
159	shlo	3,g0,g14	# compute shift count for src1
160#if __i960_BIG_ENDIAN__
161	subo	g14,0,g14	# adjust shift count for big endian
162#endif
163	eshro	g14,g4,LSW	# extract word of src1
164	 lda	8(SRC1),SRC1	# advance src1 word addr
165	 bne.f	Lsrc2_unaligned	# branch if src2 is NOT word aligned
166
167				/* at least src2 is word aligned */
168
169	mov	LSW,g0
170
171Lwloop:				# word comparing loop
172	cmpo	SRC2,g0		# compare src1 and src2 words
173#if __i960_BIG_ENDIAN__
174	 lda	0xff000000,g1	# byte extraction mask
175#else
176	 lda	0xff,g1		# byte extraction mask
177#endif
178	mov	MSW,LSW		# move msw of src1 to lsw
179	 ld	(SRC1),MSW	# pre-fetch next msw of src1
180	addo	4,SRC1,SRC1	# post-increment src1 addr
181	 lda	4(g3),g3	# pre-increment src2 addr
182	 bne.f	Lcloop		# branch if src1 and src2 unequal
183	scanbyte 0,g0		# check for null byte in src1 word
184	 ld	(g3),SRC2	# pre-fetch next word of src2
185	eshro	g14,g4,g0	# extract word of src1
186	 subi	4,g2,g2		# decrement maximum byte count
187	bo.f	Lequal_exit	# branch if null byte encountered
188	cmpibl.t 0,g2,Lwloop	# branch if max_bytes not reached yet
189
190	b	Lequal_exit	# strings were equal up through max_bytes
191
192Lcloop_setup:			# setup for coming from Lsrc2_unaligned
193	mov	LSW,g0		# restore extracted src1 word
194#if __i960_BIG_ENDIAN__
195	 lda	0xff000000,g1	# byte extraction mask
196#else
197	 lda	0xff,g1		# byte extraction mask
198#endif
199
200Lcloop:				# character comparing loop
201	and	SRC2,g1,g3	# extract next char of src2
202	and	g0,g1,LSW	# extract next char of src1
203	cmpobne.f LSW,g3,.diff	# check for equality
204	cmpo	0,LSW		# check for null byte
205#if __i960_BIG_ENDIAN__
206	shro	8,g1,g1		# shift mask for next byte
207#else
208	shlo	8,g1,g1		# shift mask for next byte
209#endif
210	subi	1,g2,g2		# decrement character counter
211	 bne.t	Lcloop		# branch if null not reached
212
213				/* words are equal up thru null byte */
214
215Lequal_exit:
216	mov	0,g14		# conform to register conventions
217	 lda	0,g0		# return zero, indicating equality
218	bx	(g13)		# return
219
220Lrett:
221	ret
222
223.diff:
224	mov	0,g14
225	 bl	Lless_than_exit
226Lgreater_than_exit:
227	cmpibge.f 0,g2,Lequal_exit  # branch if difference is beyond max_bytes
228	mov	1,g0
229	 bx	(g13)		# g0 = 1 (src1 > src2)
230Lless_than_exit:
231	cmpibge.f 0,g2,Lequal_exit  # branch if difference is beyond max_bytes
232	subi	1,0,g0
233	 bx	(g13)		# g0 = -1 (src1 < src2)
234
235Lsrc2_unaligned:
236	notor	g1,3,g14	# first step in computing new src1 ptr
237	 ld	4(g3),SRC1	# fetch second word of src2
238	shlo	3,g1,MSW	# compute shift count for src2
239#if __i960_BIG_ENDIAN__
240	subo	MSW,0,MSW	# adjust shift count for big endian
241#endif
242	eshro	MSW,g6,SRC2	# extract word of src2
243	cmpo	LSW,SRC2	# compare src1 and src2 words
244	 lda	4(g3),g1	# set new src2 ptr
245	 bne.f	Lcloop_setup	# first four bytes differ
246	scanbyte 0,LSW		# check for null byte
247	subo	g14,g0,g0	# second (final) step in computing new src1 ptr
248	addi	g14,g2,g2	# compute new max_bytes too
249	 lda	(g13),g14	# prepare return pointer for Lrestart
250	 bno.t	Lrestart		# if null byte not encountered, continue
251				/* with both string fetches shifted such that*/
252				/* src2 is now word aligned.*/
253	mov	0,g14		# conform to register conventions.
254	 lda	0,g0		# return indicator of equality.
255	bx	(g13)
256