GNU Linux-libre 6.1.91-gnu
[releases.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 bcopy(const void *src, void *dest, size_t n);
279  */
280
281 ENTRY(bcopy)
282
283         abi_entry_default
284         # a2=src, a3=dst, a4=len
285         mov     a5, a3
286         mov     a3, a2
287         mov     a2, a5
288         j       .Lmovecommon    # go to common code for memmove+bcopy
289
290 ENDPROC(bcopy)
291
292 /*
293  * void *memmove(void *dst, const void *src, size_t len);
294  *
295  * This function is intended to do the same thing as the standard
296  * library function memmove() for most cases.
297  * However, where the source and/or destination references
298  * an instruction RAM or ROM or a data RAM or ROM, that
299  * source and/or destination will always be accessed with
300  * 32-bit load and store instructions (as required for these
301  * types of devices).
302  *
303  * !!!!!!!  XTFIXME:
304  * !!!!!!!  Handling of IRAM/IROM has not yet
305  * !!!!!!!  been implemented.
306  *
307  * The (general case) algorithm is as follows:
308  *   If end of source doesn't overlap destination then use memcpy.
309  *   Otherwise do memcpy backwards.
310  *
311  * Register use:
312  *      a0/ return address
313  *      a1/ stack pointer
314  *      a2/ return value
315  *      a3/ src
316  *      a4/ length
317  *      a5/ dst
318  *      a6/ tmp
319  *      a7/ tmp
320  *      a8/ tmp
321  *      a9/ tmp
322  *      a10/ tmp
323  *      a11/ tmp
324  */
325
326 /*
327  * Byte by byte copy
328  */
329         .align  4
330         .byte   0               # 1 mod 4 alignment for LOOPNEZ
331                                 # (0 mod 4 alignment for LBEG)
332 .Lbackbytecopy:
333 #if XCHAL_HAVE_LOOPS
334         loopnez a4, .Lbackbytecopydone
335 #else /* !XCHAL_HAVE_LOOPS */
336         beqz    a4, .Lbackbytecopydone
337         sub     a7, a3, a4      # a7 = start address for source
338 #endif /* !XCHAL_HAVE_LOOPS */
339 .Lbacknextbyte:
340         addi    a3, a3, -1
341         l8ui    a6, a3, 0
342         addi    a5, a5, -1
343         s8i     a6, a5, 0
344 #if !XCHAL_HAVE_LOOPS
345         bne     a3, a7, .Lbacknextbyte # continue loop if
346                                        # $a3:src != $a7:src_start
347 #endif /* !XCHAL_HAVE_LOOPS */
348 .Lbackbytecopydone:
349         abi_ret_default
350
351 /*
352  * Destination is unaligned
353  */
354
355         .align  4
356 .Lbackdst1mod2: # dst is only byte aligned
357         _bltui  a4, 7, .Lbackbytecopy   # do short copies byte by byte
358
359         # copy 1 byte
360         addi    a3, a3, -1
361         l8ui    a6, a3,  0
362         addi    a5, a5, -1
363         s8i     a6, a5,  0
364         addi    a4, a4, -1
365         _bbci.l a5, 1, .Lbackdstaligned # if dst is now aligned, then
366                                         # return to main algorithm
367 .Lbackdst2mod4: # dst 16-bit aligned
368         # copy 2 bytes
369         _bltui  a4, 6, .Lbackbytecopy   # do short copies byte by byte
370         addi    a3, a3, -2
371         l8ui    a6, a3,  0
372         l8ui    a7, a3,  1
373         addi    a5, a5, -2
374         s8i     a6, a5,  0
375         s8i     a7, a5,  1
376         addi    a4, a4, -2
377         j       .Lbackdstaligned        # dst is now aligned,
378                                         # return to main algorithm
379
380 ENTRY(__memmove)
381 WEAK(memmove)
382
383         abi_entry_default
384         # a2/ dst, a3/ src, a4/ len
385         mov     a5, a2          # copy dst so that a2 is return value
386 .Lmovecommon:
387         sub     a6, a5, a3
388         bgeu    a6, a4, .Lcommon
389
390         add     a5, a5, a4
391         add     a3, a3, a4
392
393         _bbsi.l a5, 0, .Lbackdst1mod2   # if dst is 1 mod 2
394         _bbsi.l a5, 1, .Lbackdst2mod4   # if dst is 2 mod 4
395 .Lbackdstaligned:       # return here from .Lbackdst?mod? once dst is aligned
396         srli    a7, a4, 4       # number of loop iterations with 16B
397                                 # per iteration
398         movi    a8, 3           # if source is not aligned,
399         _bany   a3, a8, .Lbacksrcunaligned      # then use shifting copy
400         /*
401          * Destination and source are word-aligned, use word copy.
402          */
403         # copy 16 bytes per iteration for word-aligned dst and word-aligned src
404 #if XCHAL_HAVE_LOOPS
405         loopnez a7, .LbackLoop1done
406 #else /* !XCHAL_HAVE_LOOPS */
407         beqz    a7, .LbackLoop1done
408         slli    a8, a7, 4
409         sub     a8, a3, a8      # a8 = start of first 16B source chunk
410 #endif /* !XCHAL_HAVE_LOOPS */
411 .LbackLoop1:
412         addi    a3, a3, -16
413         l32i    a7, a3, 12
414         l32i    a6, a3,  8
415         addi    a5, a5, -16
416         s32i    a7, a5, 12
417         l32i    a7, a3,  4
418         s32i    a6, a5,  8
419         l32i    a6, a3,  0
420         s32i    a7, a5,  4
421         s32i    a6, a5,  0
422 #if !XCHAL_HAVE_LOOPS
423         bne     a3, a8, .LbackLoop1  # continue loop if a3:src != a8:src_start
424 #endif /* !XCHAL_HAVE_LOOPS */
425 .LbackLoop1done:
426         bbci.l  a4, 3, .Lback2
427         # copy 8 bytes
428         addi    a3, a3, -8
429         l32i    a6, a3,  0
430         l32i    a7, a3,  4
431         addi    a5, a5, -8
432         s32i    a6, a5,  0
433         s32i    a7, a5,  4
434 .Lback2:
435         bbsi.l  a4, 2, .Lback3
436         bbsi.l  a4, 1, .Lback4
437         bbsi.l  a4, 0, .Lback5
438         abi_ret_default
439 .Lback3:
440         # copy 4 bytes
441         addi    a3, a3, -4
442         l32i    a6, a3,  0
443         addi    a5, a5, -4
444         s32i    a6, a5,  0
445         bbsi.l  a4, 1, .Lback4
446         bbsi.l  a4, 0, .Lback5
447         abi_ret_default
448 .Lback4:
449         # copy 2 bytes
450         addi    a3, a3, -2
451         l16ui   a6, a3,  0
452         addi    a5, a5, -2
453         s16i    a6, a5,  0
454         bbsi.l  a4, 0, .Lback5
455         abi_ret_default
456 .Lback5:
457         # copy 1 byte
458         addi    a3, a3, -1
459         l8ui    a6, a3,  0
460         addi    a5, a5, -1
461         s8i     a6, a5,  0
462         abi_ret_default
463
464 /*
465  * Destination is aligned, Source is unaligned
466  */
467
468         .align  4
469 .Lbacksrcunaligned:
470         _beqz   a4, .Lbackdone  # avoid loading anything for zero-length copies
471         # copy 16 bytes per iteration for word-aligned dst and unaligned src
472         __ssa8  a3              # set shift amount from byte offset
473 #define SIM_CHECKS_ALIGNMENT    1       /* set to 1 when running on ISS with
474                                          * the lint or ferret client, or 0
475                                          * to save a few cycles */
476 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
477         and     a11, a3, a8     # save unalignment offset for below
478         sub     a3, a3, a11     # align a3
479 #endif
480         l32i    a6, a3, 0       # load first word
481 #if XCHAL_HAVE_LOOPS
482         loopnez a7, .LbackLoop2done
483 #else /* !XCHAL_HAVE_LOOPS */
484         beqz    a7, .LbackLoop2done
485         slli    a10, a7, 4
486         sub     a10, a3, a10    # a10 = start of first 16B source chunk
487 #endif /* !XCHAL_HAVE_LOOPS */
488 .LbackLoop2:
489         addi    a3, a3, -16
490         l32i    a7, a3, 12
491         l32i    a8, a3,  8
492         addi    a5, a5, -16
493         __src_b a6, a7, a6
494         s32i    a6, a5, 12
495         l32i    a9, a3,  4
496         __src_b a7, a8, a7
497         s32i    a7, a5,  8
498         l32i    a6, a3,  0
499         __src_b a8, a9, a8
500         s32i    a8, a5,  4
501         __src_b a9, a6, a9
502         s32i    a9, a5,  0
503 #if !XCHAL_HAVE_LOOPS
504         bne     a3, a10, .LbackLoop2 # continue loop if a3:src != a10:src_start
505 #endif /* !XCHAL_HAVE_LOOPS */
506 .LbackLoop2done:
507         bbci.l  a4, 3, .Lback12
508         # copy 8 bytes
509         addi    a3, a3, -8
510         l32i    a7, a3,  4
511         l32i    a8, a3,  0
512         addi    a5, a5, -8
513         __src_b a6, a7, a6
514         s32i    a6, a5,  4
515         __src_b a7, a8, a7
516         s32i    a7, a5,  0
517         mov     a6, a8
518 .Lback12:
519         bbci.l  a4, 2, .Lback13
520         # copy 4 bytes
521         addi    a3, a3, -4
522         l32i    a7, a3,  0
523         addi    a5, a5, -4
524         __src_b a6, a7, a6
525         s32i    a6, a5,  0
526         mov     a6, a7
527 .Lback13:
528 #if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
529         add     a3, a3, a11     # readjust a3 with correct misalignment
530 #endif
531         bbsi.l  a4, 1, .Lback14
532         bbsi.l  a4, 0, .Lback15
533 .Lbackdone:
534         abi_ret_default
535 .Lback14:
536         # copy 2 bytes
537         addi    a3, a3, -2
538         l8ui    a6, a3,  0
539         l8ui    a7, a3,  1
540         addi    a5, a5, -2
541         s8i     a6, a5,  0
542         s8i     a7, a5,  1
543         bbsi.l  a4, 0, .Lback15
544         abi_ret_default
545 .Lback15:
546         # copy 1 byte
547         addi    a3, a3, -1
548         addi    a5, a5, -1
549         l8ui    a6, a3,  0
550         s8i     a6, a5,  0
551         abi_ret_default
552
553 ENDPROC(__memmove)