summaryrefslogtreecommitdiffstats
path: root/firmware/asm/arm/memcpy.S
blob: 86fc6b7930a003ad609ef6a69cee249ae3c2bb7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2006 Free Software Foundation, Inc.
 * This file was originally part of the GNU C Library
 * Contributed to glibc by MontaVista Software, Inc. (written by Nicolas Pitre)
 * Adapted for Rockbox by Daniel Ankers
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "config.h"

/*
 * Endian independent macros for shifting bytes within registers.
 */
#ifndef __ARMEB__
#define pull            lsr
#define push            lsl
#else
#define pull            lsl
#define push            lsr
#endif

/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
/* Prototype: void *mempcpy(void *dest, const void *src, size_t n); */

    .section    .icode,"ax",%progbits

    .align      2
    .global     memcpy
    .type       memcpy,%function
    .global     mempcpy
    .type       mempcpy,%function

mempcpy:
        add     r3, r0, r2
        stmfd   sp!, {r3, r4, lr}
        b   0f

memcpy:
        stmfd   sp!, {r0, r4, lr}

0:      subs    r2, r2, #4
        blt 8f
        ands    ip, r0, #3
        bne 9f
        ands    ip, r1, #3
        bne 10f

1:      subs    r2, r2, #(28)
        stmfd   sp!, {r5 - r8}
        blt 5f

2:
3:
4:      ldmia   r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
        subs    r2, r2, #32
        stmia   r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
        bge 3b

5:      ands    ip, r2, #28
        rsb ip, ip, #32
        addne   pc, pc, ip      @ C is always clear here
        b   7f
6:      nop
        ldr r3, [r1], #4
        ldr r4, [r1], #4
        ldr r5, [r1], #4
        ldr r6, [r1], #4
        ldr r7, [r1], #4
        ldr r8, [r1], #4
        ldr lr, [r1], #4

        add pc, pc, ip
        nop
        nop
        str r3, [r0], #4
        str r4, [r0], #4
        str r5, [r0], #4
        str r6, [r0], #4
        str r7, [r0], #4
        str r8, [r0], #4
        str lr, [r0], #4

7:      ldmfd   sp!, {r5 - r8}

8:      movs    r2, r2, lsl #31
        ldrbne  r3, [r1], #1
        ldrbcs  r4, [r1], #1
        ldrbcs  ip, [r1]
        strbne  r3, [r0], #1
        strbcs  r4, [r0], #1
        strbcs  ip, [r0]

        ldmpc   regs="r0, r4"

9:      rsb ip, ip, #4
        cmp ip, #2
        ldrbgt  r3, [r1], #1
        ldrbge  r4, [r1], #1
        ldrb    lr, [r1], #1
        strbgt  r3, [r0], #1
        strbge  r4, [r0], #1
        subs    r2, r2, ip
        strb    lr, [r0], #1
        blt 8b
        ands    ip, r1, #3
        beq 1b

10:     bic r1, r1, #3
        cmp ip, #2
        ldr lr, [r1], #4
        beq 17f
        bgt 18f


        .macro  forward_copy_shift pull push

        subs    r2, r2, #28
        blt 14f

11:     stmfd   sp!, {r5 - r9}

12:
13:     ldmia   r1!, {r4, r5, r6, r7}
        mov r3, lr, pull #\pull
        subs    r2, r2, #32
        ldmia   r1!, {r8, r9, ip, lr}
        orr r3, r3, r4, push #\push
        mov r4, r4, pull #\pull
        orr r4, r4, r5, push #\push
        mov r5, r5, pull #\pull
        orr r5, r5, r6, push #\push
        mov r6, r6, pull #\pull
        orr r6, r6, r7, push #\push
        mov r7, r7, pull #\pull
        orr r7, r7, r8, push #\push
        mov r8, r8, pull #\pull
        orr r8, r8, r9, push #\push
        mov r9, r9, pull #\pull
        orr r9, r9, ip, push #\push
        mov ip, ip, pull #\pull
        orr ip, ip, lr, push #\push
        stmia   r0!, {r3, r4, r5, r6, r7, r8, r9, ip}
        bge 12b

        ldmfd   sp!, {r5 - r9}

14:     ands    ip, r2, #28
        beq 16f

15:     mov r3, lr, pull #\pull
        ldr lr, [r1], #4
        subs    ip, ip, #4
        orr r3, r3, lr, push #\push
        str r3, [r0], #4
        bgt 15b

16:     sub r1, r1, #(\push / 8)
        b   8b

        .endm


        forward_copy_shift  pull=8  push=24

17:     forward_copy_shift  pull=16 push=16

18:     forward_copy_shift  pull=24 push=8