OSDN Git Service

1835e6aa7bfd9610777777e59bc007e9b975b8c3
[uclinux-h8/uClibc.git] / libc / string / powerpc / string.c
1 /*
2  * This program is free software; you can redistribute it and/or modify it under
3  * the terms of the GNU Library General Public License as published by the Free
4  * Software Foundation; either version 2 of the License, or (at your option) any
5  * later version.
6  *
7  * This program is distributed in the hope that it will be useful, but WITHOUT
8  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9  * FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
10  * details.
11  */
12
13 /* These are carefully optimized mem*() functions for PPC written in C.
14  * Don't muck around with these function without checking the generated
15  * assmbler code.
16  * It is possible to optimize these significantly more by using specific
17  * data cache instructions(mainly dcbz). However that requires knownledge
18  * about the CPU's cache line size.
19  *
20  * BUG ALERT!
21  * The cache instructions on MPC8xx CPU's are buggy(they don't update
22  * the DAR register when causing a DTLB Miss/Error) and cannot be
23  * used on 8xx CPU's without a kernel patch to work around this
24  * problem.
25  *   
26  * Copyright (C) 2004 Joakim Tjernlund
27  */
28
29 #define _STDIO_UTILITY
30 #define _GNU_SOURCE
31 #include <string.h>
32 #include <locale.h> /* for __LOCALE_C_ONLY */
33
34 #ifdef L_memcpy
35 void *memcpy(void *to, const void *from, size_t n)
36 /* PPC can do pre increment and load/store, but not post increment and load/store.
37    Therefore use *++ptr instead of *ptr++. */
38 {
39         unsigned long rem, chunks, tmp1, tmp2;
40         void *tmp_to;
41
42         chunks = n / 8;
43         from -= 4;
44         tmp_to = to - 4;
45         if (!chunks)
46                 goto lessthan8;
47         rem = (unsigned long )tmp_to % 4;
48         if (rem)
49                 goto align;
50  copy_chunks:
51         do {
52                 /* make gcc to load all data, then store it */
53                 tmp1 = *(unsigned long *)(from+4);
54                 from += 8;
55                 tmp2 = *(unsigned long *)from;
56                 *(unsigned long *)(tmp_to+4) = tmp1;
57                 tmp_to += 8;
58                 *(unsigned long *)tmp_to = tmp2;
59         } while (--chunks);
60  lessthan8:
61         n = n % 8;
62         if (n >= 4) {
63                 *++(unsigned long *)tmp_to = *++(unsigned long *)from;
64                 n = n-4;
65         }
66         if (!n ) return to;
67         from += 3;
68         tmp_to += 3;
69         do {
70                 *++(unsigned char *)tmp_to = *++(unsigned char *)from;
71         } while (--n);
72         
73         return to;
74  align:
75         rem = 4 - rem;
76         n = n-rem;
77         do {
78                 *(unsigned char *)(tmp_to+4) = *(unsigned char *)(from+4);
79                 ++from;
80                 ++tmp_to;
81         } while (--rem);
82         chunks = n / 8;
83         if (chunks)
84                 goto copy_chunks;
85         goto lessthan8;
86 }
87 #endif
88
89 #ifdef L_memmove
90 void *memmove(void *to, const void *from, size_t n)
91 {
92         unsigned long rem, chunks, tmp1, tmp2;
93         void *tmp_to;
94
95         if (from >= to)
96                 return memcpy(to, from, n);
97         chunks = n / 8;
98         from += n;
99         tmp_to = to + n;
100         if (!chunks)
101                 goto lessthan8;
102         rem = (unsigned long )tmp_to % 4;
103         if (rem)
104                 goto align;
105  copy_chunks:
106         do {
107                 /* make gcc to load all data, then store it */
108                 tmp1 = *(unsigned long *)(from-4);
109                 from -= 8;
110                 tmp2 = *(unsigned long *)from;
111                 *(unsigned long *)(tmp_to-4) = tmp1;
112                 tmp_to -= 8;
113                 *(unsigned long *)tmp_to = tmp2;
114         } while (--chunks);
115  lessthan8:
116         n = n % 8;
117         if (n >= 4) {
118                 *--(unsigned long *)tmp_to = *--(unsigned long *)from;
119                 n = n-4;
120         }
121         if (!n ) return to;
122         do {
123                 *--(unsigned char *)tmp_to = *--(unsigned char *)from;
124         } while (--n);
125         
126         return to;
127  align:
128         rem = 4 - rem;
129         n = n-rem;
130         do {
131                 *--(unsigned char *)tmp_to = *--(unsigned char *)from;
132         } while (--rem);
133         chunks = n / 8;
134         if (chunks)
135                 goto copy_chunks;
136         goto lessthan8;
137 }
138 #endif
139
140 #ifdef L_memset
141 static inline int expand_byte_word(int c){
142         /* this does: 
143            c = c << 8 | c;
144            c = c << 16 | c ;
145         */
146         asm("rlwimi     %0,%0,8,16,23\n"
147             "\trlwimi   %0,%0,16,0,15\n"
148             : "=r" (c) : "0" (c));
149         return c;
150 }
151 void *memset(void *to, int c, size_t n)
152 {
153         unsigned long rem, chunks;
154         void *tmp_to;
155
156         chunks = n / 8;
157         tmp_to = to - 4;
158         c = expand_byte_word(c);
159         if (!chunks)
160                 goto lessthan8;
161         rem = (unsigned long )tmp_to % 4;
162         if (rem)
163                 goto align;
164  copy_chunks:
165         do {
166                 *++(unsigned long *)tmp_to = c;
167                 *++(unsigned long *)tmp_to = c;
168         } while (--chunks);
169  lessthan8:
170         n = n % 8;
171         if (n >= 4) {
172                 *++(unsigned long *)tmp_to = c;
173                 n = n-4;
174         }
175         if (!n ) return to;
176         tmp_to += 3;
177         do {
178                 *++(unsigned char *)tmp_to = c;
179         } while (--n);
180         
181         return to;
182  align:
183         rem = 4 - rem;
184         n = n-rem;
185         do {
186                 *(unsigned char *)(tmp_to+4) = c;
187                 ++tmp_to;
188         } while (--rem);
189         chunks = n / 8;
190         if (chunks)
191                 goto copy_chunks;
192         goto lessthan8;
193 }
194 #endif
195
196 #ifdef L_bzero
197 weak_alias(__bzero,bzero);
198 void __bzero(void *s, size_t n)
199 {
200         (void)memset(s, 0, n);
201 }
202 #endif