1/*
2 *  (c) Copyright 1986 HEWLETT-PACKARD COMPANY
3 *
4 *  To anyone who acknowledges that this file is provided "AS IS"
5 *  without any express or implied warranty:
6 *      permission to use, copy, modify, and distribute this file
7 *  for any purpose is hereby granted without fee, provided that
8 *  the above copyright notice and this notice appears in all
9 *  copies, and that the name of Hewlett-Packard Company not be
10 *  used in advertising or publicity pertaining to distribution
11 *  of the software without specific, written prior permission.
12 *  Hewlett-Packard Company makes no representations about the
13 *  suitability of this software for any purpose.
14 */
15
16/* HPUX_ID:	@(#) $Revision$	*/
17/*
18 * strcat(s1, s2)
19 *
20 * Concatenate s2 on the end of s1.  S1's space must be large enough.
21 * Return s1.
22 */
23#include <picolibc.h>
24
25#include "DEFS.h"
26
27#define	d_addr  r26
28#define	s_addr  r25
29#define	tmp6    r24
30#define	tmp1    r19
31#define	tmp2    r20
32#define	tmp3    r21
33#define	tmp4    r22
34#define	tmp5	arg3
35#define	save	r1
36
37
38ENTRY(strcat)
39
40	comb,=		r0,s_addr,done	/* quit if s2=NULL */
41        copy      d_addr,ret0          /* The return value is the value of d_addr. DELAY SLOT*/
42
43/* First look for end of s1 (d_addr) */
44
45        extru       d_addr,31,2,tmp1   /* Extract the low two bits of the dest address. */
46	combt,=		tmp1,r0,dont_mask
47	dep		0,31,2,d_addr	/*set word alignment */
48	ldwm		4(d_addr),tmp2
49	sh3add		tmp1,r0,save	/* build mask based on tmp1 */
50	mtctl		save,11
51	zvdepi		-2,32,save
52	or		save,tmp2,tmp2
53	uxor,nbz	tmp2,r0,save
54search:
55	b,n		found_end	/* nullified under uxor conditions above and below */
56dont_mask:
57	ldwm		4(d_addr),tmp2
58	comib,tr	r0,r0,search
59	uxor,nbz	tmp2,r0,save
60
61found_end:				/* at this point d_addr points to word */
62	extru,<>	save,7,8,r0	/* following word with null */
63	addib,tr,n	-4,d_addr,begin_copy	/*set d_addr to end of s1 */
64	extru,<>	save,15,8,r0
65	addib,tr,n	-3,d_addr,begin_copy
66	extru,<>	save,23,8,r0
67	addi		-1,d_addr,d_addr
68	addi		-1,d_addr,d_addr
69
70
71begin_copy:
72
73        extru       s_addr,31,2,tmp1   /* Extract the low two bits of the source address. */
74        extru       d_addr,31,2,tmp6   /* Extract the low two bits of the destination address. */
75        sub,=       tmp6,tmp1,tmp3     /* Compute the shift quantity and don't branch if tmp6=tmp1. */
76        b           not_aligned        /* Not_aligned says that shifts Will be needed. */
77        dep         0,31,2,s_addr      /* Compute the word address of the source.  DELAY SLOT. */
78/* aligned */
79
80	combt,=		tmp6,r0,skip_mask
81        ldwm        	4(0,s_addr),tmp1   /* tmp1 = *s_addr   s_addr += 4 (DELAY SLOT) */
82	sh3add		tmp6,r0,save
83	mtctl		save,r11
84	zvdepi		-2,32,save
85	or		save,tmp1,tmp1
86	uxor,nbz	tmp1,r0,save
87	b,n		first_null	/* special case: null in first word */
88	b,n		skip_mask2
89
90chunks:
91	b,n		null_found	/* delay slot for uxor below */
92
93skip_mask2:
94	stbys,b,m	tmp1,4(d_addr)
95	ldwm		4(s_addr),tmp1
96skip_mask:
97	comib,tr	0,0,chunks
98	uxor,nbz	tmp1,r0,save
99
100/* Begin non_aligned code.  */
101
102not_aligned:
103        sh3add,>=       tmp3,r0,tmp4        /* compute the shift amt.and skip load if tmp6 > tmp1. */
104        ldwm         	4(0,s_addr),tmp1    /* load up the first word from the source. tmp1 = *s_addr++ */
105        ldwm        	4(0,s_addr),tmp2    /* get either first or second word from source.  */
106	combt,=		tmp6,r0,chunk2      /* don't mask if whole word is valid */
107        mtctl        	tmp4,11             /* load the shift count into cr11 = shift count register. */
108        vshd        	tmp1,tmp2,tmp3      /* position data !  (delay slot) */
109	sh3add		tmp6,r0,save  	    /* setup r1 */
110	mtctl		save,r11	    /* set-up cr11 for mask */
111	zvdepi		-2,32,save
112	or		save, tmp3, tmp3
113	uxor,nbz	tmp3,r0,save
114	b,n		first_null2
115	b		did_mask
116        mtctl        	tmp4,11            /* re-load the shift count into cr11 */
117
118chunk2:
119	vshd		tmp1,tmp2,tmp3
120	uxor,nbz	tmp3, r0, save
121	b,n		null_found
122did_mask:
123        stbys,b,m   	tmp3,4(0,d_addr)    /* store !  */
124
125        ldwm        	4(0,s_addr),tmp1    /* get next word !  */
126        vshd        	tmp2,tmp1,tmp3      /* position data !  */
127	uxor,nbz	tmp3, r0, save
128	b,n		null_found
129	stwm		tmp3,4(d_addr)
130	comib,tr	0,0,chunk2
131	ldwm		4(s_addr),tmp2
132
133
134null_found:				/* adjust d_addr and store final word */
135
136	extru,<>	save,7,8,r0
137	addib,tr,n	1,d_addr,store_final
138	extru,<>	save,15,8,r0
139	addib,tr,n	2,d_addr,store_final
140	extru,<> 	save,23,8,r0
141	addib,tr	3,d_addr,store_final2
142	bv		0(r2)
143	stw		save,0(d_addr)
144
145store_final:
146	bv		0(r2)
147store_final2:
148	stbys,e		save,0(d_addr) 	/* delay slot */
149
150first_null:			/* null found in first word of aligned (wrt d_addr) */
151	addi		-4,s_addr,s_addr
152	ldbx		tmp6(s_addr),tmp4
153	add		tmp6,s_addr,s_addr
154	comib,=		0,tmp4,done
155	stbs,ma		tmp4,1(d_addr)
156	ldbs		1(s_addr),tmp4
157	comib,=		0,tmp4,done
158	stbs,ma		tmp4,1(d_addr)
159	bv		0(r2)		/* done */
160	stbs		0,0(d_addr)
161
162first_null2:	/* null found in first word of non-aligned (wrt d_addr) */
163	addibt,=	-1,tmp6,check3	/* check last 3 bytes of word */
164	extru   	save,15,8,tmp4
165	addibt,=,n	-1,tmp6,check2	/* check last 2 bytes */
166	bv		0(r2)
167	stbys,b		save, 0(d_addr)
168
169check3:
170	combt,=		tmp4,r0,done
171	stbs,ma		tmp4,1(d_addr)
172check2:
173	extru,<>	save,23,8,tmp4
174	bv		0(r2)
175	stbs,ma		tmp4,1(d_addr)
176	bv		0(r2)
177	stbs		r0,0(d_addr)
178
179done:
180EXIT(strcat)
181