xtensa: drop bcopy implementation
[linux-2.6-block.git] / arch / xtensa / lib / memcopy.S
1 /*
2  * arch/xtensa/lib/hal/memcopy.S -- Core HAL library functions
3  * xthal_memcpy and xthal_bcopy
4  *
5  * This file is subject to the terms and conditions of the GNU General Public
6  * License.  See the file "COPYING" in the main directory of this archive
7  * for more details.
8  *
9  * Copyright (C) 2002 - 2012 Tensilica Inc.
10  */
11
12 #include <linux/linkage.h>
13 #include <asm/asmmacro.h>
14 #include <asm/core.h>
15
16 /*
17  * void *memcpy(void *dst, const void *src, size_t len);
18  *
19  * This function is intended to do the same thing as the standard
20  * library function memcpy() for most cases.
21  * However, where the source and/or destination references
22  * an instruction RAM or ROM or a data RAM or ROM, that
23  * source and/or destination will always be accessed with
24  * 32-bit load and store instructions (as required for these
25  * types of devices).
26  *
27  * !!!!!!!  XTFIXME:
28  * !!!!!!!  Handling of IRAM/IROM has not yet
29  * !!!!!!!  been implemented.
30  *
31  * The (general case) algorithm is as follows:
32  *   If destination is unaligned, align it by conditionally
33  *     copying 1 and 2 bytes.
34  *   If source is aligned,
35  *     do 16 bytes with a loop, and then finish up with
36  *     8, 4, 2, and 1 byte copies conditional on the length;
37  *   else (if source is unaligned),
38  *     do the same, but use SRC to align the source data.
39  *   This code tries to use fall-through branches for the common
40  *     case of aligned source and destination and multiple
41  *     of 4 (or 8) length.
42  *
43  * Register use:
44  *      a0/ return address
45  *      a1/ stack pointer
46  *      a2/ return value
47  *      a3/ src
48  *      a4/ length
49  *      a5/ dst
50  *      a6/ tmp
51  *      a7/ tmp
52  *      a8/ tmp
53  *      a9/ tmp
54  *      a10/ tmp
55  *      a11/ tmp
56  */
57
58         .text
59
60 /*
61  * Byte by byte copy
62  */
63         .align  4
64         .byte   0               # 1 mod 4 alignment for LOOPNEZ
65                                 # (0 mod 4 alignment for LBEG)
66 .Lbytecopy:
67 #if XCHAL_HAVE_LOOPS
68         loopnez a4, .Lbytecopydone
69 #else /* !XCHAL_HAVE_LOOPS */
70         beqz    a4, .Lbytecopydone
71         add     a7, a3, a4      # a7 = end address for source
72 #endif /* !XCHAL_HAVE_LOOPS */
73 .Lnextbyte:
74         l8ui    a6, a3, 0
75         addi    a3, a3, 1
76         s8i     a6, a5, 0
77         addi    a5, a5, 1
78 #if !XCHAL_HAVE_LOOPS
79         bne     a3, a7, .Lnextbyte # continue loop if $a3:src != $a7:src_end
80 #endif /* !XCHAL_HAVE_LOOPS */
81 .Lbytecopydone:
82         abi_ret_default
83
84 /*
85  * Destination is unaligned
86  */
87
88         .align  4
89 .Ldst1mod2:     # dst is only byte aligned
90         _bltui  a4, 7, .Lbytecopy       # do short copies byte by byte
91
92         # copy 1 byte
93         l8ui    a6, a3,  0
94         addi    a3, a3,  1
95         addi    a4, a4, -1
96         s8i     a6, a5,  0
97         addi    a5, a5,  1
98         _bbci.l a5, 1, .Ldstaligned     # if dst is now aligned, then
99                                         # return to main algorithm
100 .Ldst2mod4:     # dst 16-bit aligned
101         # copy 2 bytes
102         _bltui  a4, 6, .Lbytecopy       # do short copies byte by byte
103         l8ui    a6, a3,  0
104         l8ui    a7, a3,  1
105         addi    a3, a3,  2
106         addi    a4, a4, -2
107         s8i     a6, a5,  0
108         s8i     a7, a5,  1
109         addi    a5, a5,  2
110         j       .Ldstaligned    # dst is now aligned, return to main algorithm
111
112 ENTRY(__memcpy)
113 WEAK(memcpy)
114
115         abi_entry_default
116         # a2/ dst, a3/ src, a4/ len
117         mov     a5, a2          # copy dst so that a2 is return value
118 .Lcommon:
119         _bbsi.l a2, 0, .Ldst1mod2       # if dst is 1 mod 2
120         _bbsi.l a2, 1, .Ldst2mod4       # if dst is 2 mod 4
121 .Ldstaligned:   # return here from .Ldst?mod? once dst is aligned
122         srli    a7, a4, 4       # number of loop iterations with 16B
123                                 # per iteration
124         movi    a8, 3           # if source is not aligned,
125         _bany   a3, a8, .Lsrcunaligned  # then use shifting copy
126         /*
127          * Destination and source are word-aligned, use word copy.
128          */
129         # copy 16 bytes per iteration for word-aligned dst and word-aligned src
130 #if XCHAL_HAVE_LOOPS
131         loopnez a7, .Loop1done
132 #else /* !XCHAL_HAVE_LOOPS */
133         beqz    a7, .Loop1done
134         slli    a8, a7, 4
135         add     a8, a8, a3      # a8 = end of last 16B source chunk
136 #endif /* !XCHAL_HAVE_LOOPS */
137 .Loop1:
138         l32i    a6, a3,  0
139         l32i    a7, a3,  4
140         s32i    a6, a5,  0
141         l32i    a6, a3,  8
142         s32i    a7, a5,  4
143         l32i    a7, a3, 12
144         s32i    a6, a5,  8
145         addi    a3, a3, 16
146         s32i    a7, a5, 12
147         addi    a5, a5, 16
148 #if !XCHAL_HAVE_LOOPS
149         bne     a3, a8, .Loop1  # continue loop if a3:src != a8:src_end
150 #endif /* !XCHAL_HAVE_LOOPS */
151 .Loop1done:
152         bbci.l  a4, 3, .L2
153         # copy 8 bytes
154         l32i    a6, a3,  0
155         l32i    a7, a3,  4
156         addi    a3, a3,  8
157         s32i    a6, a5,  0
158         s32i    a7, a5,  4
159         addi    a5, a5,  8
160 .L2:
161         bbsi.l  a4, 2, .L3
162         bbsi.l  a4, 1, .L4
163         bbsi.l  a4, 0, .L5
164         abi_ret_default
165 .L3:
166         # copy 4 bytes
167         l32i    a6, a3,  0
168         addi    a3, a3,  4
169         s32i    a6, a5,  0
170         addi    a5, a5,  4
171         bbsi.l  a4, 1, .L4
172         bbsi.l  a4, 0, .L5
173         abi_ret_default
174 .L4:
175         # copy 2 bytes
176         l16ui   a6, a3,  0
177         addi    a3, a3,  2
178         s16i    a6, a5,  0
179         addi    a5, a5,  2
180         bbsi.l  a4, 0, .L5
181         abi_ret_default
182 .L5:
183         # copy 1 byte
184         l8ui    a6, a3,  0
185         s8i     a6, a5,  0
186         abi_ret_default
187
188 /*
189  * Destination is aligned, Source is unaligned
190  */
191
192         .align  4
193 .Lsrcunaligned:
194         _beqz   a4, .Ldone      # avoid loading anything for zero-length copies
195         # copy 16 bytes per iteration for word-aligned dst and unaligned src
196         __ssa8  a3              # set shift amount from byte offset
197
198 /* set to 1 when running on ISS (simulator) with the
199    lint or ferret client, or 0 to save a few cycles */
200 #define SIM_CHECKS_ALIGNMENT    1
201 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
202         and     a11, a3, a8     # save unalignment offset for below
203         sub     a3, a3, a11     # align a3
204 #endif
205         l32i    a6, a3, 0       # load first word
206 #if XCHAL_HAVE_LOOPS
207         loopnez a7, .Loop2done
208 #else /* !XCHAL_HAVE_LOOPS */
209         beqz    a7, .Loop2done
210         slli    a10, a7, 4
211         add     a10, a10, a3    # a10 = end of last 16B source chunk
212 #endif /* !XCHAL_HAVE_LOOPS */
213 .Loop2:
214         l32i    a7, a3,  4
215         l32i    a8, a3,  8
216         __src_b a6, a6, a7
217         s32i    a6, a5,  0
218         l32i    a9, a3, 12
219         __src_b a7, a7, a8
220         s32i    a7, a5,  4
221         l32i    a6, a3, 16
222         __src_b a8, a8, a9
223         s32i    a8, a5,  8
224         addi    a3, a3, 16
225         __src_b a9, a9, a6
226         s32i    a9, a5, 12
227         addi    a5, a5, 16
228 #if !XCHAL_HAVE_LOOPS
229         bne     a3, a10, .Loop2 # continue loop if a3:src != a10:src_end
230 #endif /* !XCHAL_HAVE_LOOPS */
231 .Loop2done:
232         bbci.l  a4, 3, .L12
233         # copy 8 bytes
234         l32i    a7, a3,  4
235         l32i    a8, a3,  8
236         __src_b a6, a6, a7
237         s32i    a6, a5,  0
238         addi    a3, a3,  8
239         __src_b a7, a7, a8
240         s32i    a7, a5,  4
241         addi    a5, a5,  8
242         mov     a6, a8
243 .L12:
244         bbci.l  a4, 2, .L13
245         # copy 4 bytes
246         l32i    a7, a3,  4
247         addi    a3, a3,  4
248         __src_b a6, a6, a7
249         s32i    a6, a5,  0
250         addi    a5, a5,  4
251         mov     a6, a7
252 .L13:
253 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
254         add     a3, a3, a11     # readjust a3 with correct misalignment
255 #endif
256         bbsi.l  a4, 1, .L14
257         bbsi.l  a4, 0, .L15
258 .Ldone: abi_ret_default
259 .L14:
260         # copy 2 bytes
261         l8ui    a6, a3,  0
262         l8ui    a7, a3,  1
263         addi    a3, a3,  2
264         s8i     a6, a5,  0
265         s8i     a7, a5,  1
266         addi    a5, a5,  2
267         bbsi.l  a4, 0, .L15
268         abi_ret_default
269 .L15:
270         # copy 1 byte
271         l8ui    a6, a3,  0
272         s8i     a6, a5,  0
273         abi_ret_default
274
275 ENDPROC(__memcpy)
276
277 /*
278  * void *memmove(void *dst, const void *src, size_t len);
279  *
280  * This function is intended to do the same thing as the standard
281  * library function memmove() for most cases.
282  * However, where the source and/or destination references
283  * an instruction RAM or ROM or a data RAM or ROM, that
284  * source and/or destination will always be accessed with
285  * 32-bit load and store instructions (as required for these
286  * types of devices).
287  *
288  * !!!!!!!  XTFIXME:
289  * !!!!!!!  Handling of IRAM/IROM has not yet
290  * !!!!!!!  been implemented.
291  *
292  * The (general case) algorithm is as follows:
293  *   If end of source doesn't overlap destination then use memcpy.
294  *   Otherwise do memcpy backwards.
295  *
296  * Register use:
297  *      a0/ return address
298  *      a1/ stack pointer
299  *      a2/ return value
300  *      a3/ src
301  *      a4/ length
302  *      a5/ dst
303  *      a6/ tmp
304  *      a7/ tmp
305  *      a8/ tmp
306  *      a9/ tmp
307  *      a10/ tmp
308  *      a11/ tmp
309  */
310
311 /*
312  * Byte by byte copy
313  */
314         .align  4
315         .byte   0               # 1 mod 4 alignment for LOOPNEZ
316                                 # (0 mod 4 alignment for LBEG)
317 .Lbackbytecopy:
318 #if XCHAL_HAVE_LOOPS
319         loopnez a4, .Lbackbytecopydone
320 #else /* !XCHAL_HAVE_LOOPS */
321         beqz    a4, .Lbackbytecopydone
322         sub     a7, a3, a4      # a7 = start address for source
323 #endif /* !XCHAL_HAVE_LOOPS */
324 .Lbacknextbyte:
325         addi    a3, a3, -1
326         l8ui    a6, a3, 0
327         addi    a5, a5, -1
328         s8i     a6, a5, 0
329 #if !XCHAL_HAVE_LOOPS
330         bne     a3, a7, .Lbacknextbyte # continue loop if
331                                        # $a3:src != $a7:src_start
332 #endif /* !XCHAL_HAVE_LOOPS */
333 .Lbackbytecopydone:
334         abi_ret_default
335
336 /*
337  * Destination is unaligned
338  */
339
340         .align  4
341 .Lbackdst1mod2: # dst is only byte aligned
342         _bltui  a4, 7, .Lbackbytecopy   # do short copies byte by byte
343
344         # copy 1 byte
345         addi    a3, a3, -1
346         l8ui    a6, a3,  0
347         addi    a5, a5, -1
348         s8i     a6, a5,  0
349         addi    a4, a4, -1
350         _bbci.l a5, 1, .Lbackdstaligned # if dst is now aligned, then
351                                         # return to main algorithm
352 .Lbackdst2mod4: # dst 16-bit aligned
353         # copy 2 bytes
354         _bltui  a4, 6, .Lbackbytecopy   # do short copies byte by byte
355         addi    a3, a3, -2
356         l8ui    a6, a3,  0
357         l8ui    a7, a3,  1
358         addi    a5, a5, -2
359         s8i     a6, a5,  0
360         s8i     a7, a5,  1
361         addi    a4, a4, -2
362         j       .Lbackdstaligned        # dst is now aligned,
363                                         # return to main algorithm
364
365 ENTRY(__memmove)
366 WEAK(memmove)
367
368         abi_entry_default
369         # a2/ dst, a3/ src, a4/ len
370         mov     a5, a2          # copy dst so that a2 is return value
371 .Lmovecommon:
372         sub     a6, a5, a3
373         bgeu    a6, a4, .Lcommon
374
375         add     a5, a5, a4
376         add     a3, a3, a4
377
378         _bbsi.l a5, 0, .Lbackdst1mod2   # if dst is 1 mod 2
379         _bbsi.l a5, 1, .Lbackdst2mod4   # if dst is 2 mod 4
380 .Lbackdstaligned:       # return here from .Lbackdst?mod? once dst is aligned
381         srli    a7, a4, 4       # number of loop iterations with 16B
382                                 # per iteration
383         movi    a8, 3           # if source is not aligned,
384         _bany   a3, a8, .Lbacksrcunaligned      # then use shifting copy
385         /*
386          * Destination and source are word-aligned, use word copy.
387          */
388         # copy 16 bytes per iteration for word-aligned dst and word-aligned src
389 #if XCHAL_HAVE_LOOPS
390         loopnez a7, .LbackLoop1done
391 #else /* !XCHAL_HAVE_LOOPS */
392         beqz    a7, .LbackLoop1done
393         slli    a8, a7, 4
394         sub     a8, a3, a8      # a8 = start of first 16B source chunk
395 #endif /* !XCHAL_HAVE_LOOPS */
396 .LbackLoop1:
397         addi    a3, a3, -16
398         l32i    a7, a3, 12
399         l32i    a6, a3,  8
400         addi    a5, a5, -16
401         s32i    a7, a5, 12
402         l32i    a7, a3,  4
403         s32i    a6, a5,  8
404         l32i    a6, a3,  0
405         s32i    a7, a5,  4
406         s32i    a6, a5,  0
407 #if !XCHAL_HAVE_LOOPS
408         bne     a3, a8, .LbackLoop1  # continue loop if a3:src != a8:src_start
409 #endif /* !XCHAL_HAVE_LOOPS */
410 .LbackLoop1done:
411         bbci.l  a4, 3, .Lback2
412         # copy 8 bytes
413         addi    a3, a3, -8
414         l32i    a6, a3,  0
415         l32i    a7, a3,  4
416         addi    a5, a5, -8
417         s32i    a6, a5,  0
418         s32i    a7, a5,  4
419 .Lback2:
420         bbsi.l  a4, 2, .Lback3
421         bbsi.l  a4, 1, .Lback4
422         bbsi.l  a4, 0, .Lback5
423         abi_ret_default
424 .Lback3:
425         # copy 4 bytes
426         addi    a3, a3, -4
427         l32i    a6, a3,  0
428         addi    a5, a5, -4
429         s32i    a6, a5,  0
430         bbsi.l  a4, 1, .Lback4
431         bbsi.l  a4, 0, .Lback5
432         abi_ret_default
433 .Lback4:
434         # copy 2 bytes
435         addi    a3, a3, -2
436         l16ui   a6, a3,  0
437         addi    a5, a5, -2
438         s16i    a6, a5,  0
439         bbsi.l  a4, 0, .Lback5
440         abi_ret_default
441 .Lback5:
442         # copy 1 byte
443         addi    a3, a3, -1
444         l8ui    a6, a3,  0
445         addi    a5, a5, -1
446         s8i     a6, a5,  0
447         abi_ret_default
448
449 /*
450  * Destination is aligned, Source is unaligned
451  */
452
453         .align  4
454 .Lbacksrcunaligned:
455         _beqz   a4, .Lbackdone  # avoid loading anything for zero-length copies
456         # copy 16 bytes per iteration for word-aligned dst and unaligned src
457         __ssa8  a3              # set shift amount from byte offset
458 #define SIM_CHECKS_ALIGNMENT    1       /* set to 1 when running on ISS with
459                                          * the lint or ferret client, or 0
460                                          * to save a few cycles */
461 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
462         and     a11, a3, a8     # save unalignment offset for below
463         sub     a3, a3, a11     # align a3
464 #endif
465         l32i    a6, a3, 0       # load first word
466 #if XCHAL_HAVE_LOOPS
467         loopnez a7, .LbackLoop2done
468 #else /* !XCHAL_HAVE_LOOPS */
469         beqz    a7, .LbackLoop2done
470         slli    a10, a7, 4
471         sub     a10, a3, a10    # a10 = start of first 16B source chunk
472 #endif /* !XCHAL_HAVE_LOOPS */
473 .LbackLoop2:
474         addi    a3, a3, -16
475         l32i    a7, a3, 12
476         l32i    a8, a3,  8
477         addi    a5, a5, -16
478         __src_b a6, a7, a6
479         s32i    a6, a5, 12
480         l32i    a9, a3,  4
481         __src_b a7, a8, a7
482         s32i    a7, a5,  8
483         l32i    a6, a3,  0
484         __src_b a8, a9, a8
485         s32i    a8, a5,  4
486         __src_b a9, a6, a9
487         s32i    a9, a5,  0
488 #if !XCHAL_HAVE_LOOPS
489         bne     a3, a10, .LbackLoop2 # continue loop if a3:src != a10:src_start
490 #endif /* !XCHAL_HAVE_LOOPS */
491 .LbackLoop2done:
492         bbci.l  a4, 3, .Lback12
493         # copy 8 bytes
494         addi    a3, a3, -8
495         l32i    a7, a3,  4
496         l32i    a8, a3,  0
497         addi    a5, a5, -8
498         __src_b a6, a7, a6
499         s32i    a6, a5,  4
500         __src_b a7, a8, a7
501         s32i    a7, a5,  0
502         mov     a6, a8
503 .Lback12:
504         bbci.l  a4, 2, .Lback13
505         # copy 4 bytes
506         addi    a3, a3, -4
507         l32i    a7, a3,  0
508         addi    a5, a5, -4
509         __src_b a6, a7, a6
510         s32i    a6, a5,  0
511         mov     a6, a7
512 .Lback13:
513 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
514         add     a3, a3, a11     # readjust a3 with correct misalignment
515 #endif
516         bbsi.l  a4, 1, .Lback14
517         bbsi.l  a4, 0, .Lback15
518 .Lbackdone:
519         abi_ret_default
520 .Lback14:
521         # copy 2 bytes
522         addi    a3, a3, -2
523         l8ui    a6, a3,  0
524         l8ui    a7, a3,  1
525         addi    a5, a5, -2
526         s8i     a6, a5,  0
527         s8i     a7, a5,  1
528         bbsi.l  a4, 0, .Lback15
529         abi_ret_default
530 .Lback15:
531         # copy 1 byte
532         addi    a3, a3, -1
533         addi    a5, a5, -1
534         l8ui    a6, a3,  0
535         s8i     a6, a5,  0
536         abi_ret_default
537
538 ENDPROC(__memmove)