1!    Copyright (C) 2013 Imagination Technologies Ltd.
2
3!    Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
4
5
6	.text
7	.global	_memmove
8	.type	_memmove,function
9! D1Ar1 dst
10! D0Ar2 src
11! D1Ar3 cnt
12! D0Re0 dst
13_memmove:
14	CMP 	D1Ar3, #0
15	MOV 	D0Re0, D1Ar1
16	BZ 	$LEND2
17	MSETL 	[A0StP], D0.5, D0.6, D0.7
18	MOV 	D1Ar5, D0Ar2
19	CMP 	D1Ar1, D1Ar5
20	BLT 	$Lforwards_copy
21	SUB 	D0Ar4, D1Ar1, D1Ar3
22	ADD 	D0Ar4, D0Ar4, #1
23	CMP 	D0Ar2, D0Ar4
24	BLT 	$Lforwards_copy
25	! should copy backwards
26	MOV 	D1Re0, D0Ar2
27	! adjust pointer to the end of mem
28	ADD 	D0Ar2, D1Re0, D1Ar3
29	ADD 	D1Ar1, D1Ar1, D1Ar3
30
31	MOV 	A1.2, D0Ar2
32	MOV 	A0.2, D1Ar1
33	CMP 	D1Ar3, #8
34	BLT 	$Lbbyte_loop
35
36	MOV 	D0Ar4, D0Ar2
37	MOV 	D1Ar5, D1Ar1
38
39	! test 8 byte alignment
40	ANDS 	D1Ar5, D1Ar5, #7
41	BNE 	$Lbdest_unaligned
42
43	ANDS 	D0Ar4, D0Ar4, #7
44	BNE 	$Lbsrc_unaligned
45
46	LSR 	D1Ar5, D1Ar3, #3
47
48$Lbaligned_loop:
49	GETL 	D0Re0, D1Re0, [--A1.2]
50	SETL 	[--A0.2], D0Re0, D1Re0
51	SUBS 	D1Ar5, D1Ar5, #1
52	BNE 	$Lbaligned_loop
53
54	ANDS 	D1Ar3, D1Ar3, #7
55	BZ 	$Lbbyte_loop_exit
56$Lbbyte_loop:
57	GETB 	D1Re0, [--A1.2]
58	SETB 	[--A0.2], D1Re0
59	SUBS 	D1Ar3, D1Ar3, #1
60	BNE 	$Lbbyte_loop
61$Lbbyte_loop_exit:
62	MOV 	D0Re0, A0.2
63$LEND:
64	SUB 	A0.2, A0StP, #24
65	MGETL 	D0.5, D0.6, D0.7, [A0.2]
66	SUB 	A0StP, A0StP, #24
67$LEND2:
68	MOV 	PC, D1RtP
69
70$Lbdest_unaligned:
71	GETB 	D0Re0, [--A1.2]
72	SETB 	[--A0.2], D0Re0
73	SUBS 	D1Ar5, D1Ar5, #1
74	SUB 	D1Ar3, D1Ar3, #1
75	BNE 	$Lbdest_unaligned
76	CMP 	D1Ar3, #8
77	BLT 	$Lbbyte_loop
78$Lbsrc_unaligned:
79	LSR 	D1Ar5, D1Ar3, #3
80	! adjust A1.2
81	MOV 	D0Ar4, A1.2
82	! save original address
83	MOV 	D0Ar6, A1.2
84
85	ADD 	D0Ar4, D0Ar4, #7
86	ANDMB 	D0Ar4, D0Ar4, #0xfff8
87	! new address is the 8-byte aligned one above the original
88	MOV 	A1.2, D0Ar4
89
90	! A0.2 dst 64-bit is aligned
91	! measure the gap size
92	SUB 	D0Ar6, D0Ar4, D0Ar6
93	MOVS 	D0Ar4, D0Ar6
94	! keep this information for the later adjustment
95	! both aligned
96	BZ 	$Lbaligned_loop
97
98	! prefetch
99	GETL 	D0Re0, D1Re0, [--A1.2]
100
101	CMP 	D0Ar6, #4
102	BLT 	$Lbunaligned_1_2_3
103	! 32-bit aligned
104	BZ 	$Lbaligned_4
105
106	SUB 	D0Ar6, D0Ar6, #4
107	! D1.6 stores the gap size in bits
108	MULW 	D1.6, D0Ar6, #8
109	MOV 	D0.6, #32
110	! D0.6 stores the complement of the gap size
111	SUB 	D0.6, D0.6, D1.6
112
113$Lbunaligned_5_6_7:
114	GETL 	D0.7, D1.7, [--A1.2]
115	! form 64-bit data in D0Re0, D1Re0
116	MOV 	D1Re0, D0Re0
117	! D1Re0 << gap-size
118	LSL 	D1Re0, D1Re0, D1.6
119	MOV 	D0Re0, D1.7
120	! D0Re0 >> complement
121	LSR 	D0Re0, D0Re0, D0.6
122	MOV 	D1.5, D0Re0
123	! combine the both
124	ADD 	D1Re0, D1Re0, D1.5
125
126	MOV 	D1.5, D1.7
127	LSL 	D1.5, D1.5, D1.6
128	MOV 	D0Re0, D0.7
129	LSR 	D0Re0, D0Re0, D0.6
130	MOV 	D0.5, D1.5
131	ADD 	D0Re0, D0Re0, D0.5
132
133	SETL 	[--A0.2], D0Re0, D1Re0
134	MOV 	D0Re0, D0.7
135	MOV 	D1Re0, D1.7
136	SUBS 	D1Ar5, D1Ar5, #1
137	BNE 	$Lbunaligned_5_6_7
138
139	ANDS 	D1Ar3, D1Ar3, #7
140	BZ 	$Lbbyte_loop_exit
141	! Adjust A1.2
142	! A1.2 <- A1.2 +8 - gapsize
143	ADD 	A1.2, A1.2, #8
144	SUB 	A1.2, A1.2, D0Ar4
145	B 	$Lbbyte_loop
146
147$Lbunaligned_1_2_3:
148	MULW 	D1.6, D0Ar6, #8
149	MOV 	D0.6, #32
150	SUB 	D0.6, D0.6, D1.6
151
152$Lbunaligned_1_2_3_loop:
153	GETL 	D0.7, D1.7, [--A1.2]
154	! form 64-bit data in D0Re0, D1Re0
155	LSL 	D1Re0, D1Re0, D1.6
156	! save D0Re0 for later use
157	MOV 	D0.5, D0Re0
158	LSR 	D0Re0, D0Re0, D0.6
159	MOV 	D1.5, D0Re0
160	ADD 	D1Re0, D1Re0, D1.5
161
162	! orignal data in D0Re0
163	MOV 	D1.5, D0.5
164	LSL 	D1.5, D1.5, D1.6
165	MOV 	D0Re0, D1.7
166	LSR 	D0Re0, D0Re0, D0.6
167	MOV 	D0.5, D1.5
168	ADD 	D0Re0, D0Re0, D0.5
169
170	SETL 	[--A0.2], D0Re0, D1Re0
171	MOV 	D0Re0, D0.7
172	MOV 	D1Re0, D1.7
173	SUBS 	D1Ar5, D1Ar5, #1
174	BNE 	$Lbunaligned_1_2_3_loop
175
176	ANDS 	D1Ar3, D1Ar3, #7
177	BZ 	$Lbbyte_loop_exit
178	! Adjust A1.2
179	ADD 	A1.2, A1.2, #8
180	SUB 	A1.2, A1.2, D0Ar4
181	B 	$Lbbyte_loop
182
183$Lbaligned_4:
184	GETL 	D0.7, D1.7, [--A1.2]
185	MOV 	D1Re0, D0Re0
186	MOV 	D0Re0, D1.7
187	SETL 	[--A0.2], D0Re0, D1Re0
188	MOV 	D0Re0, D0.7
189	MOV 	D1Re0, D1.7
190	SUBS 	D1Ar5, D1Ar5, #1
191	BNE 	$Lbaligned_4
192	ANDS 	D1Ar3, D1Ar3, #7
193	BZ 	$Lbbyte_loop_exit
194	! Adjust A1.2
195	ADD 	A1.2, A1.2, #8
196	SUB 	A1.2, A1.2, D0Ar4
197	B 	$Lbbyte_loop
198
199$Lforwards_copy:
200	MOV 	A1.2, D0Ar2
201	MOV 	A0.2, D1Ar1
202	CMP 	D1Ar3, #8
203	BLT 	$Lfbyte_loop
204
205	MOV 	D0Ar4, D0Ar2
206	MOV 	D1Ar5, D1Ar1
207
208	ANDS 	D1Ar5, D1Ar5, #7
209	BNE 	$Lfdest_unaligned
210
211	ANDS 	D0Ar4, D0Ar4, #7
212	BNE 	$Lfsrc_unaligned
213
214	LSR 	D1Ar5, D1Ar3, #3
215
216$Lfaligned_loop:
217	GETL 	D0Re0, D1Re0, [A1.2++]
218	SUBS 	D1Ar5, D1Ar5, #1
219	SETL 	[A0.2++], D0Re0, D1Re0
220	BNE 	$Lfaligned_loop
221
222	ANDS 	D1Ar3, D1Ar3, #7
223	BZ 	$Lfbyte_loop_exit
224$Lfbyte_loop:
225	GETB 	D1Re0, [A1.2++]
226	SETB 	[A0.2++], D1Re0
227	SUBS 	D1Ar3, D1Ar3, #1
228	BNE 	$Lfbyte_loop
229$Lfbyte_loop_exit:
230	MOV 	D0Re0, D1Ar1
231	B 	$LEND
232
233$Lfdest_unaligned:
234	GETB 	D0Re0, [A1.2++]
235	ADD 	D1Ar5, D1Ar5, #1
236	SUB 	D1Ar3, D1Ar3, #1
237	SETB 	[A0.2++], D0Re0
238	CMP 	D1Ar5, #8
239	BNE 	$Lfdest_unaligned
240	CMP 	D1Ar3, #8
241	BLT 	$Lfbyte_loop
242$Lfsrc_unaligned:
243	! adjust A1.2
244	LSR 	D1Ar5, D1Ar3, #3
245
246	MOV 	D0Ar4, A1.2
247	MOV 	D0Ar6, A1.2
248	ANDMB 	D0Ar4, D0Ar4, #0xfff8
249	MOV 	A1.2, D0Ar4
250
251	! A0.2 dst 64-bit is aligned
252	SUB 	D0Ar6, D0Ar6, D0Ar4
253	! keep the information for the later adjustment
254	MOVS 	D0Ar4, D0Ar6
255
256	! both aligned
257	BZ 	$Lfaligned_loop
258
259	! prefetch
260	GETL 	D0Re0, D1Re0, [A1.2]
261
262	CMP 	D0Ar6, #4
263	BLT 	$Lfunaligned_1_2_3
264	BZ 	$Lfaligned_4
265
266	SUB 	D0Ar6, D0Ar6, #4
267	MULW 	D0.6, D0Ar6, #8
268	MOV 	D1.6, #32
269	SUB 	D1.6, D1.6, D0.6
270
271$Lfunaligned_5_6_7:
272	GETL 	D0.7, D1.7, [++A1.2]
273	! form 64-bit data in D0Re0, D1Re0
274	MOV 	D0Re0, D1Re0
275	LSR 	D0Re0, D0Re0, D0.6
276	MOV 	D1Re0, D0.7
277	LSL 	D1Re0, D1Re0, D1.6
278	MOV 	D0.5, D1Re0
279	ADD 	D0Re0, D0Re0, D0.5
280
281	MOV 	D0.5, D0.7
282	LSR 	D0.5, D0.5, D0.6
283	MOV 	D1Re0, D1.7
284	LSL 	D1Re0, D1Re0, D1.6
285	MOV 	D1.5, D0.5
286	ADD 	D1Re0, D1Re0, D1.5
287
288	SETL 	[A0.2++], D0Re0, D1Re0
289	MOV 	D0Re0, D0.7
290	MOV 	D1Re0, D1.7
291	SUBS 	D1Ar5, D1Ar5, #1
292	BNE 	$Lfunaligned_5_6_7
293
294	ANDS 	D1Ar3, D1Ar3, #7
295	BZ 	$Lfbyte_loop_exit
296	! Adjust A1.2
297	ADD	A1.2, A1.2, D0Ar4
298	B 	$Lfbyte_loop
299
300$Lfunaligned_1_2_3:
301	MULW 	D0.6, D0Ar6, #8
302	MOV 	D1.6, #32
303	SUB 	D1.6, D1.6, D0.6
304
305$Lfunaligned_1_2_3_loop:
306	GETL 	D0.7, D1.7, [++A1.2]
307	! form 64-bit data in D0Re0, D1Re0
308	LSR 	D0Re0, D0Re0, D0.6
309	MOV 	D1.5, D1Re0
310	LSL 	D1Re0, D1Re0, D1.6
311	MOV 	D0.5, D1Re0
312	ADD 	D0Re0, D0Re0, D0.5
313
314	MOV 	D0.5, D1.5
315	LSR 	D0.5, D0.5, D0.6
316	MOV 	D1Re0, D0.7
317	LSL 	D1Re0, D1Re0, D1.6
318	MOV 	D1.5, D0.5
319	ADD 	D1Re0, D1Re0, D1.5
320
321	SETL 	[A0.2++], D0Re0, D1Re0
322	MOV 	D0Re0, D0.7
323	MOV 	D1Re0, D1.7
324	SUBS 	D1Ar5, D1Ar5, #1
325	BNE 	$Lfunaligned_1_2_3_loop
326
327	ANDS 	D1Ar3, D1Ar3, #7
328	BZ 	$Lfbyte_loop_exit
329	! Adjust A1.2
330	ADD	A1.2, A1.2, D0Ar4
331	B 	$Lfbyte_loop
332
333$Lfaligned_4:
334	GETL 	D0.7, D1.7, [++A1.2]
335	MOV 	D0Re0, D1Re0
336	MOV 	D1Re0, D0.7
337	SETL 	[A0.2++], D0Re0, D1Re0
338	MOV 	D0Re0, D0.7
339	MOV 	D1Re0, D1.7
340	SUBS 	D1Ar5, D1Ar5, #1
341	BNE 	$Lfaligned_4
342	ANDS 	D1Ar3, D1Ar3, #7
343	BZ 	$Lfbyte_loop_exit
344	! Adjust A1.2
345	ADD	A1.2, A1.2, D0Ar4
346	B 	$Lfbyte_loop
347
348	.size _memmove,.-_memmove
349
350libc_hidden_def(memmove)
351