random bug fixes
[drnoksnes] / memcpy.s
1 /* $NetBSD: memcpy.S,v 1.3 1997/11/22 03:27:12 mark Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Neil A. Carson and Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS\'\' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /* This was modified by Jay Monkman <jmonkman@smoothsmoothie.com> to
40 *   save and restore r12. This is necessary for RTEMS.
41 */
42 /* #include <machine/asm.h>*/
43
44 .globl memcpy
45 memcpy:
46 stmfd sp!, {r0, r12, lr}
47 bl _memcpy
48 ldmfd sp!, {r0, r12, pc}
49
50
51 .globl memove
52 memmove:
53 stmfd sp!, {r0, r12, lr}
54 bl _memcpy
55 ldmfd sp!, {r0, r12, pc}
56
57
58
59 /*
60 * This is one fun bit of code ...
61 * Some easy listening music is suggested while trying to understand this
62 * code e.g. Iron Maiden
63 *
64 * For anyone attempting to understand it :
65 *
66 * The core code is implemented here with simple stubs for memcpy()
67 * memmove() and bcopy().
68 *
69 * All local labels are prefixed with Lmemcpy_
70 * Following the prefix a label starting f is used in the forward copy code
71 * while a label using b is used in the backwards copy code
72 * The source and destination addresses determine whether a forward or
73 * backward copy is performed.
74 * Separate bits of code are used to deal with the following situations
75 * for both the forward and backwards copy.
76 * unaligned source address
77 * unaligned destination address
78 * Separate copy routines are used to produce an optimised result for each
79 * of these cases.
80 * The copy code will use LDM/STM instructions to copy up to 32 bytes at
81 * a time where possible.
82 *
83 * Note: r12 (aka ip) can be trashed during the function along with
84 * r0-r3 although r0-r2 have defined uses i.e. src, dest, len through out.
85 * Additional registers are preserved prior to use i.e. r4, r5 & lr
86 *
87 * Apologies for the state of the comments;-)
88 */
89
90
91 _memcpy:
92 /* Determine copy direction */
93 cmp r1, r0
94 bcc Lmemcpy_backwards
95
96 moveq r0, #0   /* Quick abort for len=0 */
97 moveq pc, lr
98
99 stmdb sp!, {r0, lr}  /* memcpy() returns dest addr */
100 subs r2, r2, #4
101 blt Lmemcpy_fl4  /* less than 4 bytes */
102 ands r12, r0, #3
103 bne Lmemcpy_fdestul  /* oh unaligned destination addr */
104 ands r12, r1, #3
105 bne Lmemcpy_fsrcul  /* oh unaligned source addr */
106
107 Lmemcpy_ft8:
108 /* We have aligned source and destination */
109 subs r2, r2, #8
110 blt Lmemcpy_fl12  /* less than 12 bytes (4 from above) */
111 subs r2, r2, #0x14        
112 blt Lmemcpy_fl32  /* less than 32 bytes (12 from above) */
113 stmdb sp!, {r4}  /* borrow r4 */
114
115 /* blat 32 bytes at a time */
116 /* XXX for really big copies perhaps we should use more registers */
117 Lmemcpy_floop32:
118 ldmia r1!, {r3, r4, r12, lr}
119 stmia r0!, {r3, r4, r12, lr}
120 ldmia r1!, {r3, r4, r12, lr}
121 stmia r0!, {r3, r4, r12, lr}
122 subs r2, r2, #0x20        
123 bge Lmemcpy_floop32
124
125 cmn r2, #0x10
126 ldmgeia r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
127 stmgeia r0!, {r3, r4, r12, lr}
128 subge r2, r2, #0x10        
129 ldmia sp!, {r4}  /* return r4 */
130
131 Lmemcpy_fl32:
132 adds r2, r2, #0x14        
133
134 /* blat 12 bytes at a time */
135 Lmemcpy_floop12:
136 ldmgeia r1!, {r3, r12, lr}
137 stmgeia r0!, {r3, r12, lr}
138 subges r2, r2, #0x0c        
139 bge Lmemcpy_floop12
140
141 Lmemcpy_fl12:
142 adds r2, r2, #8
143 blt Lmemcpy_fl4
144
145 subs r2, r2, #4
146 ldrlt r3, [r1], #4
147 strlt r3, [r0], #4
148 ldmgeia r1!, {r3, r12}
149 stmgeia r0!, {r3, r12}
150 subge r2, r2, #4
151
152 Lmemcpy_fl4:
153 /* less than 4 bytes to go */
154 adds r2, r2, #4
155 ldmeqia sp!, {r0, pc}  /* done */
156
157 /* copy the crud byte at a time */
158 cmp r2, #2
159 ldrb r3, [r1], #1
160 strb r3, [r0], #1
161 ldrgeb r3, [r1], #1
162 strgeb r3, [r0], #1
163 ldrgtb r3, [r1], #1
164 strgtb r3, [r0], #1
165 ldmia sp!, {r0, pc}
166
167 /* erg - unaligned destination */
168 Lmemcpy_fdestul:
169 rsb r12, r12, #4
170 cmp r12, #2
171
172 /* align destination with byte copies */
173 ldrb r3, [r1], #1
174 strb r3, [r0], #1
175 ldrgeb r3, [r1], #1
176 strgeb r3, [r0], #1
177 ldrgtb r3, [r1], #1
178 strgtb r3, [r0], #1
179 subs r2, r2, r12
180 blt Lmemcpy_fl4  /* less the 4 bytes */
181
182 ands r12, r1, #3
183 beq Lmemcpy_ft8  /* we have an aligned source */
184
185 /* erg - unaligned source */
186 /* This is where it gets nasty ... */
187 Lmemcpy_fsrcul:
188 bic r1, r1, #3
189 ldr lr, [r1], #4
190 cmp r12, #2
191 bgt Lmemcpy_fsrcul3
192 beq Lmemcpy_fsrcul2
193 cmp r2, #0x0c            
194 blt Lmemcpy_fsrcul1loop4
195 sub r2, r2, #0x0c        
196 stmdb sp!, {r4, r5}
197
198 Lmemcpy_fsrcul1loop16:
199 mov r3, lr, lsr #8
200 ldmia r1!, {r4, r5, r12, lr}
201 orr r3, r3, r4, lsl #24
202 mov r4, r4, lsr #8
203 orr r4, r4, r5, lsl #24
204 mov r5, r5, lsr #8
205 orr r5, r5, r12, lsl #24
206 mov r12, r12, lsr #8
207 orr r12, r12, lr, lsl #24
208 stmia r0!, {r3-r5, r12}
209 subs r2, r2, #0x10        
210 bge Lmemcpy_fsrcul1loop16
211 ldmia sp!, {r4, r5}
212 adds r2, r2, #0x0c        
213 blt Lmemcpy_fsrcul1l4
214
215 Lmemcpy_fsrcul1loop4:
216 mov r12, lr, lsr #8
217 ldr lr, [r1], #4
218 orr r12, r12, lr, lsl #24
219 str r12, [r0], #4
220 subs r2, r2, #4
221 bge Lmemcpy_fsrcul1loop4
222
223 Lmemcpy_fsrcul1l4:
224 sub r1, r1, #3
225 b Lmemcpy_fl4
226
227 Lmemcpy_fsrcul2:
228 cmp r2, #0x0c            
229 blt Lmemcpy_fsrcul2loop4
230 sub r2, r2, #0x0c        
231 stmdb sp!, {r4, r5}
232
233 Lmemcpy_fsrcul2loop16:
234 mov r3, lr, lsr #16
235 ldmia r1!, {r4, r5, r12, lr}
236 orr r3, r3, r4, lsl #16
237 mov r4, r4, lsr #16
238 orr r4, r4, r5, lsl #16
239 mov r5, r5, lsr #16
240 orr r5, r5, r12, lsl #16
241 mov r12, r12, lsr #16
242 orr r12, r12, lr, lsl #16
243 stmia r0!, {r3-r5, r12}
244 subs r2, r2, #0x10        
245 bge Lmemcpy_fsrcul2loop16
246 ldmia sp!, {r4, r5}
247 adds r2, r2, #0x0c        
248 blt Lmemcpy_fsrcul2l4
249
250 Lmemcpy_fsrcul2loop4:
251 mov r12, lr, lsr #16
252 ldr lr, [r1], #4
253 orr r12, r12, lr, lsl #16
254 str r12, [r0], #4
255 subs r2, r2, #4
256 bge Lmemcpy_fsrcul2loop4
257
258 Lmemcpy_fsrcul2l4:
259 sub r1, r1, #2
260 b Lmemcpy_fl4
261
262 Lmemcpy_fsrcul3:
263 cmp r2, #0x0c            
264 blt Lmemcpy_fsrcul3loop4
265 sub r2, r2, #0x0c        
266 stmdb sp!, {r4, r5}
267
268 Lmemcpy_fsrcul3loop16:
269 mov r3, lr, lsr #24
270 ldmia r1!, {r4, r5, r12, lr}
271 orr r3, r3, r4, lsl #8
272 mov r4, r4, lsr #24
273 orr r4, r4, r5, lsl #8
274 mov r5, r5, lsr #24
275 orr r5, r5, r12, lsl #8
276 mov r12, r12, lsr #24
277 orr r12, r12, lr, lsl #8
278 stmia r0!, {r3-r5, r12}
279 subs r2, r2, #0x10        
280 bge Lmemcpy_fsrcul3loop16
281 ldmia sp!, {r4, r5}
282 adds r2, r2, #0x0c        
283 blt Lmemcpy_fsrcul3l4
284
285 Lmemcpy_fsrcul3loop4:
286 mov r12, lr, lsr #24
287 ldr lr, [r1], #4
288 orr r12, r12, lr, lsl #8
289 str r12, [r0], #4
290 subs r2, r2, #4
291 bge Lmemcpy_fsrcul3loop4
292
293 Lmemcpy_fsrcul3l4:
294 sub r1, r1, #1
295 b Lmemcpy_fl4
296
297 Lmemcpy_backwards:
298 add r1, r1, r2
299 add r0, r0, r2
300 subs r2, r2, #4
301 blt Lmemcpy_bl4  /* less than 4 bytes */
302 ands r12, r0, #3
303 bne Lmemcpy_bdestul  /* oh unaligned destination addr */
304 ands r12, r1, #3
305 bne Lmemcpy_bsrcul  /* oh unaligned source addr */
306
307 Lmemcpy_bt8:
308 /* We have aligned source and destination */
309 subs r2, r2, #8
310 blt Lmemcpy_bl12  /* less than 12 bytes (4 from above) */
311 stmdb sp!, {r4, lr}
312 subs r2, r2, #0x14  /* less than 32 bytes (12 from above) */
313 blt Lmemcpy_bl32
314
315 /* blat 32 bytes at a time */
316 /* XXX for really big copies perhaps we should use more registers */
317 Lmemcpy_bloop32:
318 ldmdb r1!, {r3, r4, r12, lr}
319 stmdb r0!, {r3, r4, r12, lr}
320 ldmdb r1!, {r3, r4, r12, lr}
321 stmdb r0!, {r3, r4, r12, lr}
322 subs r2, r2, #0x20        
323 bge Lmemcpy_bloop32
324
325 Lmemcpy_bl32:
326 cmn r2, #0x10            
327 ldmgedb r1!, {r3, r4, r12, lr} /* blat a remaining 16 bytes */
328 stmgedb r0!, {r3, r4, r12, lr}
329 subge r2, r2, #0x10        
330 adds r2, r2, #0x14        
331 ldmgedb r1!, {r3, r12, lr} /* blat a remaining 12 bytes */
332 stmgedb r0!, {r3, r12, lr}
333 subge r2, r2, #0x0c        
334 ldmia sp!, {r4, lr}
335
336 Lmemcpy_bl12:
337 adds r2, r2, #8
338 blt Lmemcpy_bl4
339 subs r2, r2, #4
340 ldrlt r3, [r1, #-4]!
341 strlt r3, [r0, #-4]!
342 ldmgedb r1!, {r3, r12}
343 stmgedb r0!, {r3, r12}
344 subge r2, r2, #4
345
346 Lmemcpy_bl4:
347 /* less than 4 bytes to go */
348 adds r2, r2, #4
349 moveq pc, lr   /* done */
350
351 /* copy the crud byte at a time */
352 cmp r2, #2
353 ldrb r3, [r1, #-1]!
354 strb r3, [r0, #-1]!
355 ldrgeb r3, [r1, #-1]!
356 strgeb r3, [r0, #-1]!
357 ldrgtb r3, [r1, #-1]!
358 strgtb r3, [r0, #-1]!
359 mov pc, lr
360
361 /* erg - unaligned destination */
362 Lmemcpy_bdestul:
363 cmp r12, #2
364
365 /* align destination with byte copies */
366 ldrb r3, [r1, #-1]!
367 strb r3, [r0, #-1]!
368 ldrgeb r3, [r1, #-1]!
369 strgeb r3, [r0, #-1]!
370 ldrgtb r3, [r1, #-1]!
371 strgtb r3, [r0, #-1]!
372 subs r2, r2, r12
373 blt Lmemcpy_bl4  /* less than 4 bytes to go */
374 ands r12, r1, #3
375 beq Lmemcpy_bt8  /* we have an aligned source */
376
377 /* erg - unaligned source */
378 /* This is where it gets nasty ... */
379 Lmemcpy_bsrcul:
380 bic r1, r1, #3
381 ldr r3, [r1, #0]
382 cmp r12, #2
383 blt Lmemcpy_bsrcul1
384 beq Lmemcpy_bsrcul2
385 cmp r2, #0x0c            
386 blt Lmemcpy_bsrcul3loop4
387 sub r2, r2, #0x0c        
388 stmdb sp!, {r4, r5, lr}
389
390 Lmemcpy_bsrcul3loop16:
391 mov lr, r3, lsl #8
392 ldmdb r1!, {r3-r5, r12}
393 orr lr, lr, r12, lsr #24
394 mov r12, r12, lsl #8
395 orr r12, r12, r5, lsr #24
396 mov r5, r5, lsl #8
397 orr r5, r5, r4, lsr #24
398 mov r4, r4, lsl #8
399 orr r4, r4, r3, lsr #24
400 stmdb r0!, {r4, r5, r12, lr}
401 subs r2, r2, #0x10        
402 bge Lmemcpy_bsrcul3loop16
403 ldmia sp!, {r4, r5, lr}
404 adds r2, r2, #0x0c        
405 blt Lmemcpy_bsrcul3l4
406
407 Lmemcpy_bsrcul3loop4:
408 mov r12, r3, lsl #8
409 ldr r3, [r1, #-4]!
410 orr r12, r12, r3, lsr #24
411 str r12, [r0, #-4]!
412 subs r2, r2, #4
413 bge Lmemcpy_bsrcul3loop4
414
415 Lmemcpy_bsrcul3l4:
416 add r1, r1, #3
417 b Lmemcpy_bl4
418
419 Lmemcpy_bsrcul2:
420 cmp r2, #0x0c            
421 blt Lmemcpy_bsrcul2loop4
422 sub r2, r2, #0x0c        
423 stmdb sp!, {r4, r5, lr}
424
425 Lmemcpy_bsrcul2loop16:
426 mov lr, r3, lsl #16
427 ldmdb r1!, {r3-r5, r12}
428 orr lr, lr, r12, lsr #16
429 mov r12, r12, lsl #16
430 orr r12, r12, r5, lsr #16
431 mov r5, r5, lsl #16
432 orr r5, r5, r4, lsr #16
433 mov r4, r4, lsl #16
434 orr r4, r4, r3, lsr #16
435 stmdb r0!, {r4, r5, r12, lr}
436 subs r2, r2, #0x10        
437 bge Lmemcpy_bsrcul2loop16
438 ldmia sp!, {r4, r5, lr}
439 adds r2, r2, #0x0c        
440 blt Lmemcpy_bsrcul2l4
441
442 Lmemcpy_bsrcul2loop4:
443 mov r12, r3, lsl #16
444 ldr r3, [r1, #-4]!
445 orr r12, r12, r3, lsr #16
446 str r12, [r0, #-4]!
447 subs r2, r2, #4
448 bge Lmemcpy_bsrcul2loop4
449
450 Lmemcpy_bsrcul2l4:
451 add r1, r1, #2
452 b Lmemcpy_bl4
453
454 Lmemcpy_bsrcul1:
455 cmp r2, #0x0c            
456 blt Lmemcpy_bsrcul1loop4
457 sub r2, r2, #0x0c        
458 stmdb sp!, {r4, r5, lr}
459
460 Lmemcpy_bsrcul1loop32:
461 mov lr, r3, lsl #24
462 ldmdb r1!, {r3-r5, r12}
463 orr lr, lr, r12, lsr #8
464 mov r12, r12, lsl #24
465 orr r12, r12, r5, lsr #8
466 mov r5, r5, lsl #24
467 orr r5, r5, r4, lsr #8
468 mov r4, r4, lsl #24
469 orr r4, r4, r3, lsr #8
470 stmdb r0!, {r4, r5, r12, lr}
471 subs r2, r2, #0x10        
472 bge Lmemcpy_bsrcul1loop32
473 ldmia sp!, {r4, r5, lr}
474 adds r2, r2, #0x0c        
475 blt Lmemcpy_bsrcul1l4
476
477 Lmemcpy_bsrcul1loop4:
478 mov r12, r3, lsl #24
479 ldr r3, [r1, #-4]!
480 orr r12, r12, r3, lsr #8
481 str r12, [r0, #-4]!
482 subs r2, r2, #4
483 bge Lmemcpy_bsrcul1loop4
484
485 Lmemcpy_bsrcul1l4:
486 add r1, r1, #1
487 b Lmemcpy_bl4