Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[sfrench/cifs-2.6.git] / arch / blackfin / lib / memcmp.S
1 /*
2  * File:         arch/blackfin/lib/memcmp.S
3  * Based on:
4  * Author:
5  *
6  * Created:
7  * Description:
8  *
9  * Modified:
10  *               Copyright 2004-2006 Analog Devices Inc.
11  *
12  * Bugs:         Enter bugs at http://blackfin.uclinux.org/
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see the file COPYING, or write
26  * to the Free Software Foundation, Inc.,
27  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
28  */
29
30 #include <linux/linkage.h>
31
32 /* int memcmp(const void *s1, const void *s2, size_t n);
33  * R0 = First Address (s1)
34  * R1 = Second Address (s2)
35  * R2 = count (n)
36  *
37  * Favours word aligned data.
38  */
39
40 .text
41
42 .align 2
43
44 ENTRY(_memcmp)
45         I1 = P3;
46         P0 = R0;                        /* P0 = s1 address */
47         P3 = R1;                        /* P3 = s2 Address  */
48         P2 = R2 ;                       /* P2 = count */
49         CC = R2 <= 7(IU);
50         IF CC JUMP .Ltoo_small;
51         I0 = R1;                        /* s2 */
52         R1 = R1 | R0;           /* OR addresses together */
53         R1 <<= 30;              /* check bottom two bits */
54         CC =  AZ;                       /* AZ set if zero. */
55         IF !CC JUMP .Lbytes ;   /* Jump if addrs not aligned. */
56
57         P1 = P2 >> 2;           /* count = n/4 */
58         R3 =  3;
59         R2 = R2 & R3;           /* remainder */
60         P2 = R2;                        /* set remainder */
61
62         LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1;
63 .Lquad_loop_s:
64 #if ANOMALY_05000202
65         R0 = [P0++];
66         R1 = [I0++];
67 #else
68         MNOP || R0 = [P0++] || R1 = [I0++];
69 #endif
70         CC = R0 == R1;
71         IF !CC JUMP .Lquad_different;
72 .Lquad_loop_e:
73         NOP;
74
75         P3 = I0;                        /* s2 */
76 .Ltoo_small:
77         CC = P2 == 0;           /* Check zero count*/
78         IF CC JUMP .Lfinished;  /* very unlikely*/
79
80 .Lbytes:
81         LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
82 .Lbyte_loop_s:
83         R1 = B[P3++](Z);        /* *s2 */
84         R0 = B[P0++](Z);        /* *s1 */
85         CC = R0 == R1;
86         IF !CC JUMP .Ldifferent;
87 .Lbyte_loop_e:
88         NOP;
89
90 .Ldifferent:
91         R0 = R0 - R1;
92         P3 = I1;
93         RTS;
94
95 .Lquad_different:
96         /* We've read two quads which don't match.
97          * Can't just compare them, because we're
98          * a little-endian machine, so the MSBs of
99          * the regs occur at later addresses in the
100          * string.
101          * Arrange to re-read those two quads again,
102          * byte-by-byte.
103          */
104         P0 += -4;               /* back up to the start of the */
105         P3 = I0;                /* quads, and increase the*/
106         P2 += 4;                /* remainder count*/
107         P3 += -4;
108         JUMP .Lbytes;
109
110 .Lfinished:
111         R0 = 0;
112         P3 = I1;
113         RTS;
114
115 ENDPROC(_memcmp)