aboutsummaryrefslogtreecommitdiffstats
path: root/arch/microblaze/lib
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/microblaze/lib
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/microblaze/lib')
-rw-r--r--arch/microblaze/lib/Makefile16
-rw-r--r--arch/microblaze/lib/ashldi3.c29
-rw-r--r--arch/microblaze/lib/ashrdi3.c31
-rw-r--r--arch/microblaze/lib/divsi3.S73
-rw-r--r--arch/microblaze/lib/fastcopy.S4
-rw-r--r--arch/microblaze/lib/libgcc.h25
-rw-r--r--arch/microblaze/lib/lshrdi3.c29
-rw-r--r--arch/microblaze/lib/memcpy.c54
-rw-r--r--arch/microblaze/lib/memmove.c65
-rw-r--r--arch/microblaze/lib/memset.c24
-rw-r--r--arch/microblaze/lib/modsi3.S73
-rw-r--r--arch/microblaze/lib/muldi3.c61
-rw-r--r--arch/microblaze/lib/mulsi3.S46
-rw-r--r--arch/microblaze/lib/udivsi3.S84
-rw-r--r--arch/microblaze/lib/umodsi3.S86
15 files changed, 671 insertions, 29 deletions
diff --git a/arch/microblaze/lib/Makefile b/arch/microblaze/lib/Makefile
index 4dfe47d3cd91..10c320aa908b 100644
--- a/arch/microblaze/lib/Makefile
+++ b/arch/microblaze/lib/Makefile
@@ -2,6 +2,12 @@
2# Makefile 2# Makefile
3# 3#
4 4
5ifdef CONFIG_FUNCTION_TRACER
6CFLAGS_REMOVE_ashldi3.o = -pg
7CFLAGS_REMOVE_ashrdi3.o = -pg
8CFLAGS_REMOVE_lshrdi3.o = -pg
9endif
10
5lib-y := memset.o 11lib-y := memset.o
6 12
7ifeq ($(CONFIG_OPT_LIB_ASM),y) 13ifeq ($(CONFIG_OPT_LIB_ASM),y)
@@ -11,3 +17,13 @@ lib-y += memcpy.o memmove.o
11endif 17endif
12 18
13lib-y += uaccess_old.o 19lib-y += uaccess_old.o
20
21lib-y += ashldi3.o
22lib-y += ashrdi3.o
23lib-y += divsi3.o
24lib-y += lshrdi3.o
25lib-y += modsi3.o
26lib-y += muldi3.o
27lib-y += mulsi3.o
28lib-y += udivsi3.o
29lib-y += umodsi3.o
diff --git a/arch/microblaze/lib/ashldi3.c b/arch/microblaze/lib/ashldi3.c
new file mode 100644
index 000000000000..beb80f316095
--- /dev/null
+++ b/arch/microblaze/lib/ashldi3.c
@@ -0,0 +1,29 @@
1#include <linux/module.h>
2
3#include "libgcc.h"
4
5long long __ashldi3(long long u, word_type b)
6{
7 DWunion uu, w;
8 word_type bm;
9
10 if (b == 0)
11 return u;
12
13 uu.ll = u;
14 bm = 32 - b;
15
16 if (bm <= 0) {
17 w.s.low = 0;
18 w.s.high = (unsigned int) uu.s.low << -bm;
19 } else {
20 const unsigned int carries = (unsigned int) uu.s.low >> bm;
21
22 w.s.low = (unsigned int) uu.s.low << b;
23 w.s.high = ((unsigned int) uu.s.high << b) | carries;
24 }
25
26 return w.ll;
27}
28
29EXPORT_SYMBOL(__ashldi3);
diff --git a/arch/microblaze/lib/ashrdi3.c b/arch/microblaze/lib/ashrdi3.c
new file mode 100644
index 000000000000..c884a912b660
--- /dev/null
+++ b/arch/microblaze/lib/ashrdi3.c
@@ -0,0 +1,31 @@
1#include <linux/module.h>
2
3#include "libgcc.h"
4
5long long __ashrdi3(long long u, word_type b)
6{
7 DWunion uu, w;
8 word_type bm;
9
10 if (b == 0)
11 return u;
12
13 uu.ll = u;
14 bm = 32 - b;
15
16 if (bm <= 0) {
17 /* w.s.high = 1..1 or 0..0 */
18 w.s.high =
19 uu.s.high >> 31;
20 w.s.low = uu.s.high >> -bm;
21 } else {
22 const unsigned int carries = (unsigned int) uu.s.high << bm;
23
24 w.s.high = uu.s.high >> b;
25 w.s.low = ((unsigned int) uu.s.low >> b) | carries;
26 }
27
28 return w.ll;
29}
30
31EXPORT_SYMBOL(__ashrdi3);
diff --git a/arch/microblaze/lib/divsi3.S b/arch/microblaze/lib/divsi3.S
new file mode 100644
index 000000000000..595b02d6e86b
--- /dev/null
+++ b/arch/microblaze/lib/divsi3.S
@@ -0,0 +1,73 @@
1#include <linux/linkage.h>
2
3/*
4* Divide operation for 32 bit integers.
5* Input : Dividend in Reg r5
6* Divisor in Reg r6
7* Output: Result in Reg r3
8*/
9 .text
10 .globl __divsi3
11 .type __divsi3, @function
12 .ent __divsi3
13__divsi3:
14 .frame r1, 0, r15
15
16 addik r1, r1, -16
17 swi r28, r1, 0
18 swi r29, r1, 4
19 swi r30, r1, 8
20 swi r31, r1, 12
21
22 beqi r6, div_by_zero /* div_by_zero - division error */
23 beqi r5, result_is_zero /* result is zero */
24 bgeid r5, r5_pos
25 xor r28, r5, r6 /* get the sign of the result */
26 rsubi r5, r5, 0 /* make r5 positive */
27r5_pos:
28 bgei r6, r6_pos
29 rsubi r6, r6, 0 /* make r6 positive */
30r6_pos:
31 addik r30, r0, 0 /* clear mod */
32 addik r3, r0, 0 /* clear div */
33 addik r29, r0, 32 /* initialize the loop count */
34
35 /* first part try to find the first '1' in the r5 */
36div0:
37 blti r5, div2 /* this traps r5 == 0x80000000 */
38div1:
39 add r5, r5, r5 /* left shift logical r5 */
40 bgtid r5, div1
41 addik r29, r29, -1
42div2:
43 /* left shift logical r5 get the '1' into the carry */
44 add r5, r5, r5
45 addc r30, r30, r30 /* move that bit into the mod register */
46 rsub r31, r6, r30 /* try to subtract (r30 a r6) */
47 blti r31, mod_too_small
48 /* move the r31 to mod since the result was positive */
49 or r30, r0, r31
50 addik r3, r3, 1
51mod_too_small:
52 addik r29, r29, -1
53 beqi r29, loop_end
54 add r3, r3, r3 /* shift in the '1' into div */
55 bri div2 /* div2 */
56loop_end:
57 bgei r28, return_here
58 brid return_here
59 rsubi r3, r3, 0 /* negate the result */
60div_by_zero:
61result_is_zero:
62 or r3, r0, r0 /* set result to 0 */
63return_here:
64/* restore values of csrs and that of r3 and the divisor and the dividend */
65 lwi r28, r1, 0
66 lwi r29, r1, 4
67 lwi r30, r1, 8
68 lwi r31, r1, 12
69 rtsd r15, 8
70 addik r1, r1, 16
71
72.size __divsi3, . - __divsi3
73.end __divsi3
diff --git a/arch/microblaze/lib/fastcopy.S b/arch/microblaze/lib/fastcopy.S
index fdc48bb065d8..62021d7e249e 100644
--- a/arch/microblaze/lib/fastcopy.S
+++ b/arch/microblaze/lib/fastcopy.S
@@ -29,6 +29,10 @@
29 * between mem locations with size of xfer spec'd in bytes 29 * between mem locations with size of xfer spec'd in bytes
30 */ 30 */
31 31
32#ifdef __MICROBLAZEEL__
33#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM.
34#endif
35
32#include <linux/linkage.h> 36#include <linux/linkage.h>
33 .text 37 .text
34 .globl memcpy 38 .globl memcpy
diff --git a/arch/microblaze/lib/libgcc.h b/arch/microblaze/lib/libgcc.h
new file mode 100644
index 000000000000..05909d58e2fe
--- /dev/null
+++ b/arch/microblaze/lib/libgcc.h
@@ -0,0 +1,25 @@
1#ifndef __ASM_LIBGCC_H
2#define __ASM_LIBGCC_H
3
4#include <asm/byteorder.h>
5
6typedef int word_type __attribute__ ((mode (__word__)));
7
8#ifdef __BIG_ENDIAN
9struct DWstruct {
10 int high, low;
11};
12#elif defined(__LITTLE_ENDIAN)
13struct DWstruct {
14 int low, high;
15};
16#else
17#error I feel sick.
18#endif
19
20typedef union {
21 struct DWstruct s;
22 long long ll;
23} DWunion;
24
25#endif /* __ASM_LIBGCC_H */
diff --git a/arch/microblaze/lib/lshrdi3.c b/arch/microblaze/lib/lshrdi3.c
new file mode 100644
index 000000000000..dcf8d6810b7c
--- /dev/null
+++ b/arch/microblaze/lib/lshrdi3.c
@@ -0,0 +1,29 @@
1#include <linux/module.h>
2
3#include "libgcc.h"
4
5long long __lshrdi3(long long u, word_type b)
6{
7 DWunion uu, w;
8 word_type bm;
9
10 if (b == 0)
11 return u;
12
13 uu.ll = u;
14 bm = 32 - b;
15
16 if (bm <= 0) {
17 w.s.high = 0;
18 w.s.low = (unsigned int) uu.s.high >> -bm;
19 } else {
20 const unsigned int carries = (unsigned int) uu.s.high << bm;
21
22 w.s.high = (unsigned int) uu.s.high >> b;
23 w.s.low = ((unsigned int) uu.s.low >> b) | carries;
24 }
25
26 return w.ll;
27}
28
29EXPORT_SYMBOL(__lshrdi3);
diff --git a/arch/microblaze/lib/memcpy.c b/arch/microblaze/lib/memcpy.c
index 014bac92bdff..52746e718dfa 100644
--- a/arch/microblaze/lib/memcpy.c
+++ b/arch/microblaze/lib/memcpy.c
@@ -33,17 +33,24 @@
33#include <asm/system.h> 33#include <asm/system.h>
34 34
35#ifdef __HAVE_ARCH_MEMCPY 35#ifdef __HAVE_ARCH_MEMCPY
36#ifndef CONFIG_OPT_LIB_FUNCTION
36void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c) 37void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
37{ 38{
38 const char *src = v_src; 39 const char *src = v_src;
39 char *dst = v_dst; 40 char *dst = v_dst;
40#ifndef CONFIG_OPT_LIB_FUNCTION 41
41 /* Simple, byte oriented memcpy. */ 42 /* Simple, byte oriented memcpy. */
42 while (c--) 43 while (c--)
43 *dst++ = *src++; 44 *dst++ = *src++;
44 45
45 return v_dst; 46 return v_dst;
46#else 47}
48#else /* CONFIG_OPT_LIB_FUNCTION */
49void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
50{
51 const char *src = v_src;
52 char *dst = v_dst;
53
47 /* The following code tries to optimize the copy by using unsigned 54 /* The following code tries to optimize the copy by using unsigned
48 * alignment. This will work fine if both source and destination are 55 * alignment. This will work fine if both source and destination are
49 * aligned on the same boundary. However, if they are aligned on 56 * aligned on the same boundary. However, if they are aligned on
@@ -56,8 +63,8 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
56 if (likely(c >= 4)) { 63 if (likely(c >= 4)) {
57 unsigned value, buf_hold; 64 unsigned value, buf_hold;
58 65
59 /* Align the dstination to a word boundry. */ 66 /* Align the destination to a word boundary. */
60 /* This is done in an endian independant manner. */ 67 /* This is done in an endian independent manner. */
61 switch ((unsigned long)dst & 3) { 68 switch ((unsigned long)dst & 3) {
62 case 1: 69 case 1:
63 *dst++ = *src++; 70 *dst++ = *src++;
@@ -73,7 +80,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
73 i_dst = (void *)dst; 80 i_dst = (void *)dst;
74 81
75 /* Choose a copy scheme based on the source */ 82 /* Choose a copy scheme based on the source */
76 /* alignment relative to dstination. */ 83 /* alignment relative to destination. */
77 switch ((unsigned long)src & 3) { 84 switch ((unsigned long)src & 3) {
78 case 0x0: /* Both byte offsets are aligned */ 85 case 0x0: /* Both byte offsets are aligned */
79 i_src = (const void *)src; 86 i_src = (const void *)src;
@@ -86,7 +93,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
86 case 0x1: /* Unaligned - Off by 1 */ 93 case 0x1: /* Unaligned - Off by 1 */
87 /* Word align the source */ 94 /* Word align the source */
88 i_src = (const void *) ((unsigned)src & ~3); 95 i_src = (const void *) ((unsigned)src & ~3);
89 96#ifndef __MICROBLAZEEL__
90 /* Load the holding buffer */ 97 /* Load the holding buffer */
91 buf_hold = *i_src++ << 8; 98 buf_hold = *i_src++ << 8;
92 99
@@ -95,7 +102,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
95 *i_dst++ = buf_hold | value >> 24; 102 *i_dst++ = buf_hold | value >> 24;
96 buf_hold = value << 8; 103 buf_hold = value << 8;
97 } 104 }
105#else
106 /* Load the holding buffer */
107 buf_hold = (*i_src++ & 0xFFFFFF00) >>8;
98 108
109 for (; c >= 4; c -= 4) {
110 value = *i_src++;
111 *i_dst++ = buf_hold | ((value & 0xFF) << 24);
112 buf_hold = (value & 0xFFFFFF00) >>8;
113 }
114#endif
99 /* Realign the source */ 115 /* Realign the source */
100 src = (const void *)i_src; 116 src = (const void *)i_src;
101 src -= 3; 117 src -= 3;
@@ -103,7 +119,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
103 case 0x2: /* Unaligned - Off by 2 */ 119 case 0x2: /* Unaligned - Off by 2 */
104 /* Word align the source */ 120 /* Word align the source */
105 i_src = (const void *) ((unsigned)src & ~3); 121 i_src = (const void *) ((unsigned)src & ~3);
106 122#ifndef __MICROBLAZEEL__
107 /* Load the holding buffer */ 123 /* Load the holding buffer */
108 buf_hold = *i_src++ << 16; 124 buf_hold = *i_src++ << 16;
109 125
@@ -112,7 +128,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
112 *i_dst++ = buf_hold | value >> 16; 128 *i_dst++ = buf_hold | value >> 16;
113 buf_hold = value << 16; 129 buf_hold = value << 16;
114 } 130 }
131#else
132 /* Load the holding buffer */
133 buf_hold = (*i_src++ & 0xFFFF0000 )>>16;
115 134
135 for (; c >= 4; c -= 4) {
136 value = *i_src++;
137 *i_dst++ = buf_hold | ((value & 0xFFFF)<<16);
138 buf_hold = (value & 0xFFFF0000) >>16;
139 }
140#endif
116 /* Realign the source */ 141 /* Realign the source */
117 src = (const void *)i_src; 142 src = (const void *)i_src;
118 src -= 2; 143 src -= 2;
@@ -120,7 +145,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
120 case 0x3: /* Unaligned - Off by 3 */ 145 case 0x3: /* Unaligned - Off by 3 */
121 /* Word align the source */ 146 /* Word align the source */
122 i_src = (const void *) ((unsigned)src & ~3); 147 i_src = (const void *) ((unsigned)src & ~3);
123 148#ifndef __MICROBLAZEEL__
124 /* Load the holding buffer */ 149 /* Load the holding buffer */
125 buf_hold = *i_src++ << 24; 150 buf_hold = *i_src++ << 24;
126 151
@@ -129,7 +154,16 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
129 *i_dst++ = buf_hold | value >> 8; 154 *i_dst++ = buf_hold | value >> 8;
130 buf_hold = value << 24; 155 buf_hold = value << 24;
131 } 156 }
157#else
158 /* Load the holding buffer */
159 buf_hold = (*i_src++ & 0xFF000000) >> 24;
132 160
161 for (; c >= 4; c -= 4) {
162 value = *i_src++;
163 *i_dst++ = buf_hold | ((value & 0xFFFFFF) << 8);
164 buf_hold = (value & 0xFF000000) >> 24;
165 }
166#endif
133 /* Realign the source */ 167 /* Realign the source */
134 src = (const void *)i_src; 168 src = (const void *)i_src;
135 src -= 1; 169 src -= 1;
@@ -139,7 +173,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
139 } 173 }
140 174
141 /* Finish off any remaining bytes */ 175 /* Finish off any remaining bytes */
142 /* simple fast copy, ... unless a cache boundry is crossed */ 176 /* simple fast copy, ... unless a cache boundary is crossed */
143 switch (c) { 177 switch (c) {
144 case 3: 178 case 3:
145 *dst++ = *src++; 179 *dst++ = *src++;
@@ -150,7 +184,7 @@ void *memcpy(void *v_dst, const void *v_src, __kernel_size_t c)
150 } 184 }
151 185
152 return v_dst; 186 return v_dst;
153#endif
154} 187}
188#endif /* CONFIG_OPT_LIB_FUNCTION */
155EXPORT_SYMBOL(memcpy); 189EXPORT_SYMBOL(memcpy);
156#endif /* __HAVE_ARCH_MEMCPY */ 190#endif /* __HAVE_ARCH_MEMCPY */
diff --git a/arch/microblaze/lib/memmove.c b/arch/microblaze/lib/memmove.c
index 0929198c5e68..2146c3752a80 100644
--- a/arch/microblaze/lib/memmove.c
+++ b/arch/microblaze/lib/memmove.c
@@ -31,16 +31,12 @@
31#include <linux/string.h> 31#include <linux/string.h>
32 32
33#ifdef __HAVE_ARCH_MEMMOVE 33#ifdef __HAVE_ARCH_MEMMOVE
34#ifndef CONFIG_OPT_LIB_FUNCTION
34void *memmove(void *v_dst, const void *v_src, __kernel_size_t c) 35void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
35{ 36{
36 const char *src = v_src; 37 const char *src = v_src;
37 char *dst = v_dst; 38 char *dst = v_dst;
38 39
39#ifdef CONFIG_OPT_LIB_FUNCTION
40 const uint32_t *i_src;
41 uint32_t *i_dst;
42#endif
43
44 if (!c) 40 if (!c)
45 return v_dst; 41 return v_dst;
46 42
@@ -48,7 +44,6 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
48 if (v_dst <= v_src) 44 if (v_dst <= v_src)
49 return memcpy(v_dst, v_src, c); 45 return memcpy(v_dst, v_src, c);
50 46
51#ifndef CONFIG_OPT_LIB_FUNCTION
52 /* copy backwards, from end to beginning */ 47 /* copy backwards, from end to beginning */
53 src += c; 48 src += c;
54 dst += c; 49 dst += c;
@@ -58,7 +53,22 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
58 *--dst = *--src; 53 *--dst = *--src;
59 54
60 return v_dst; 55 return v_dst;
61#else 56}
57#else /* CONFIG_OPT_LIB_FUNCTION */
58void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
59{
60 const char *src = v_src;
61 char *dst = v_dst;
62 const uint32_t *i_src;
63 uint32_t *i_dst;
64
65 if (!c)
66 return v_dst;
67
68 /* Use memcpy when source is higher than dest */
69 if (v_dst <= v_src)
70 return memcpy(v_dst, v_src, c);
71
62 /* The following code tries to optimize the copy by using unsigned 72 /* The following code tries to optimize the copy by using unsigned
63 * alignment. This will work fine if both source and destination are 73 * alignment. This will work fine if both source and destination are
64 * aligned on the same boundary. However, if they are aligned on 74 * aligned on the same boundary. However, if they are aligned on
@@ -73,8 +83,8 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
73 if (c >= 4) { 83 if (c >= 4) {
74 unsigned value, buf_hold; 84 unsigned value, buf_hold;
75 85
76 /* Align the destination to a word boundry. */ 86 /* Align the destination to a word boundary. */
77 /* This is done in an endian independant manner. */ 87 /* This is done in an endian independent manner. */
78 88
79 switch ((unsigned long)dst & 3) { 89 switch ((unsigned long)dst & 3) {
80 case 3: 90 case 3:
@@ -104,7 +114,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
104 case 0x1: /* Unaligned - Off by 1 */ 114 case 0x1: /* Unaligned - Off by 1 */
105 /* Word align the source */ 115 /* Word align the source */
106 i_src = (const void *) (((unsigned)src + 4) & ~3); 116 i_src = (const void *) (((unsigned)src + 4) & ~3);
107 117#ifndef __MICROBLAZEEL__
108 /* Load the holding buffer */ 118 /* Load the holding buffer */
109 buf_hold = *--i_src >> 24; 119 buf_hold = *--i_src >> 24;
110 120
@@ -113,7 +123,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
113 *--i_dst = buf_hold << 8 | value; 123 *--i_dst = buf_hold << 8 | value;
114 buf_hold = value >> 24; 124 buf_hold = value >> 24;
115 } 125 }
126#else
127 /* Load the holding buffer */
128 buf_hold = (*--i_src & 0xFF) << 24;
116 129
130 for (; c >= 4; c -= 4) {
131 value = *--i_src;
132 *--i_dst = buf_hold | ((value & 0xFFFFFF00)>>8);
133 buf_hold = (value & 0xFF) << 24;
134 }
135#endif
117 /* Realign the source */ 136 /* Realign the source */
118 src = (const void *)i_src; 137 src = (const void *)i_src;
119 src += 1; 138 src += 1;
@@ -121,7 +140,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
121 case 0x2: /* Unaligned - Off by 2 */ 140 case 0x2: /* Unaligned - Off by 2 */
122 /* Word align the source */ 141 /* Word align the source */
123 i_src = (const void *) (((unsigned)src + 4) & ~3); 142 i_src = (const void *) (((unsigned)src + 4) & ~3);
124 143#ifndef __MICROBLAZEEL__
125 /* Load the holding buffer */ 144 /* Load the holding buffer */
126 buf_hold = *--i_src >> 16; 145 buf_hold = *--i_src >> 16;
127 146
@@ -130,7 +149,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
130 *--i_dst = buf_hold << 16 | value; 149 *--i_dst = buf_hold << 16 | value;
131 buf_hold = value >> 16; 150 buf_hold = value >> 16;
132 } 151 }
152#else
153 /* Load the holding buffer */
154 buf_hold = (*--i_src & 0xFFFF) << 16;
133 155
156 for (; c >= 4; c -= 4) {
157 value = *--i_src;
158 *--i_dst = buf_hold | ((value & 0xFFFF0000)>>16);
159 buf_hold = (value & 0xFFFF) << 16;
160 }
161#endif
134 /* Realign the source */ 162 /* Realign the source */
135 src = (const void *)i_src; 163 src = (const void *)i_src;
136 src += 2; 164 src += 2;
@@ -138,7 +166,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
138 case 0x3: /* Unaligned - Off by 3 */ 166 case 0x3: /* Unaligned - Off by 3 */
139 /* Word align the source */ 167 /* Word align the source */
140 i_src = (const void *) (((unsigned)src + 4) & ~3); 168 i_src = (const void *) (((unsigned)src + 4) & ~3);
141 169#ifndef __MICROBLAZEEL__
142 /* Load the holding buffer */ 170 /* Load the holding buffer */
143 buf_hold = *--i_src >> 8; 171 buf_hold = *--i_src >> 8;
144 172
@@ -147,7 +175,16 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
147 *--i_dst = buf_hold << 24 | value; 175 *--i_dst = buf_hold << 24 | value;
148 buf_hold = value >> 8; 176 buf_hold = value >> 8;
149 } 177 }
178#else
179 /* Load the holding buffer */
180 buf_hold = (*--i_src & 0xFFFFFF) << 8;
150 181
182 for (; c >= 4; c -= 4) {
183 value = *--i_src;
184 *--i_dst = buf_hold | ((value & 0xFF000000)>> 24);
185 buf_hold = (value & 0xFFFFFF) << 8;
186 }
187#endif
151 /* Realign the source */ 188 /* Realign the source */
152 src = (const void *)i_src; 189 src = (const void *)i_src;
153 src += 3; 190 src += 3;
@@ -156,7 +193,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
156 dst = (void *)i_dst; 193 dst = (void *)i_dst;
157 } 194 }
158 195
159 /* simple fast copy, ... unless a cache boundry is crossed */ 196 /* simple fast copy, ... unless a cache boundary is crossed */
160 /* Finish off any remaining bytes */ 197 /* Finish off any remaining bytes */
161 switch (c) { 198 switch (c) {
162 case 4: 199 case 4:
@@ -169,7 +206,7 @@ void *memmove(void *v_dst, const void *v_src, __kernel_size_t c)
169 *--dst = *--src; 206 *--dst = *--src;
170 } 207 }
171 return v_dst; 208 return v_dst;
172#endif
173} 209}
210#endif /* CONFIG_OPT_LIB_FUNCTION */
174EXPORT_SYMBOL(memmove); 211EXPORT_SYMBOL(memmove);
175#endif /* __HAVE_ARCH_MEMMOVE */ 212#endif /* __HAVE_ARCH_MEMMOVE */
diff --git a/arch/microblaze/lib/memset.c b/arch/microblaze/lib/memset.c
index ecfb663e1fc1..ddf67939576d 100644
--- a/arch/microblaze/lib/memset.c
+++ b/arch/microblaze/lib/memset.c
@@ -31,17 +31,30 @@
31#include <linux/string.h> 31#include <linux/string.h>
32 32
33#ifdef __HAVE_ARCH_MEMSET 33#ifdef __HAVE_ARCH_MEMSET
34#ifndef CONFIG_OPT_LIB_FUNCTION
35void *memset(void *v_src, int c, __kernel_size_t n)
36{
37 char *src = v_src;
38
39 /* Truncate c to 8 bits */
40 c = (c & 0xFF);
41
42 /* Simple, byte oriented memset or the rest of count. */
43 while (n--)
44 *src++ = c;
45
46 return v_src;
47}
48#else /* CONFIG_OPT_LIB_FUNCTION */
34void *memset(void *v_src, int c, __kernel_size_t n) 49void *memset(void *v_src, int c, __kernel_size_t n)
35{ 50{
36 char *src = v_src; 51 char *src = v_src;
37#ifdef CONFIG_OPT_LIB_FUNCTION
38 uint32_t *i_src; 52 uint32_t *i_src;
39 uint32_t w32 = 0; 53 uint32_t w32 = 0;
40#endif 54
41 /* Truncate c to 8 bits */ 55 /* Truncate c to 8 bits */
42 c = (c & 0xFF); 56 c = (c & 0xFF);
43 57
44#ifdef CONFIG_OPT_LIB_FUNCTION
45 if (unlikely(c)) { 58 if (unlikely(c)) {
46 /* Make a repeating word out of it */ 59 /* Make a repeating word out of it */
47 w32 = c; 60 w32 = c;
@@ -51,7 +64,7 @@ void *memset(void *v_src, int c, __kernel_size_t n)
51 64
52 if (likely(n >= 4)) { 65 if (likely(n >= 4)) {
53 /* Align the destination to a word boundary */ 66 /* Align the destination to a word boundary */
54 /* This is done in an endian independant manner */ 67 /* This is done in an endian independent manner */
55 switch ((unsigned) src & 3) { 68 switch ((unsigned) src & 3) {
56 case 1: 69 case 1:
57 *src++ = c; 70 *src++ = c;
@@ -72,12 +85,13 @@ void *memset(void *v_src, int c, __kernel_size_t n)
72 85
73 src = (void *)i_src; 86 src = (void *)i_src;
74 } 87 }
75#endif 88
76 /* Simple, byte oriented memset or the rest of count. */ 89 /* Simple, byte oriented memset or the rest of count. */
77 while (n--) 90 while (n--)
78 *src++ = c; 91 *src++ = c;
79 92
80 return v_src; 93 return v_src;
81} 94}
95#endif /* CONFIG_OPT_LIB_FUNCTION */
82EXPORT_SYMBOL(memset); 96EXPORT_SYMBOL(memset);
83#endif /* __HAVE_ARCH_MEMSET */ 97#endif /* __HAVE_ARCH_MEMSET */
diff --git a/arch/microblaze/lib/modsi3.S b/arch/microblaze/lib/modsi3.S
new file mode 100644
index 000000000000..84e0bee6e8c7
--- /dev/null
+++ b/arch/microblaze/lib/modsi3.S
@@ -0,0 +1,73 @@
1#include <linux/linkage.h>
2
3/*
4* modulo operation for 32 bit integers.
5* Input : op1 in Reg r5
6* op2 in Reg r6
7* Output: op1 mod op2 in Reg r3
8*/
9
10 .text
11 .globl __modsi3
12 .type __modsi3, @function
13 .ent __modsi3
14
15__modsi3:
16 .frame r1, 0, r15
17
18 addik r1, r1, -16
19 swi r28, r1, 0
20 swi r29, r1, 4
21 swi r30, r1, 8
22 swi r31, r1, 12
23
24 beqi r6, div_by_zero /* div_by_zero division error */
25 beqi r5, result_is_zero /* result is zero */
26 bgeid r5, r5_pos
27 /* get the sign of the result [ depends only on the first arg] */
28 add r28, r5, r0
29 rsubi r5, r5, 0 /* make r5 positive */
30r5_pos:
31 bgei r6, r6_pos
32 rsubi r6, r6, 0 /* make r6 positive */
33r6_pos:
34 addik r3, r0, 0 /* clear mod */
35 addik r30, r0, 0 /* clear div */
36 addik r29, r0, 32 /* initialize the loop count */
37/* first part try to find the first '1' in the r5 */
38div1:
39 add r5, r5, r5 /* left shift logical r5 */
40 bgeid r5, div1
41 addik r29, r29, -1
42div2:
43 /* left shift logical r5 get the '1' into the carry */
44 add r5, r5, r5
45 addc r3, r3, r3 /* move that bit into the mod register */
46 rsub r31, r6, r3 /* try to subtract (r30 a r6) */
47 blti r31, mod_too_small
48 /* move the r31 to mod since the result was positive */
49 or r3, r0, r31
50 addik r30, r30, 1
51mod_too_small:
52 addik r29, r29, -1
53 beqi r29, loop_end
54 add r30, r30, r30 /* shift in the '1' into div */
55 bri div2 /* div2 */
56loop_end:
57 bgei r28, return_here
58 brid return_here
59 rsubi r3, r3, 0 /* negate the result */
60div_by_zero:
61result_is_zero:
62 or r3, r0, r0 /* set result to 0 [both mod as well as div are 0] */
63return_here:
64/* restore values of csrs and that of r3 and the divisor and the dividend */
65 lwi r28, r1, 0
66 lwi r29, r1, 4
67 lwi r30, r1, 8
68 lwi r31, r1, 12
69 rtsd r15, 8
70 addik r1, r1, 16
71
72.size __modsi3, . - __modsi3
73.end __modsi3
diff --git a/arch/microblaze/lib/muldi3.c b/arch/microblaze/lib/muldi3.c
new file mode 100644
index 000000000000..0585bccb7fad
--- /dev/null
+++ b/arch/microblaze/lib/muldi3.c
@@ -0,0 +1,61 @@
1#include <linux/module.h>
2
3#include "libgcc.h"
4
5#define DWtype long long
6#define UWtype unsigned long
7#define UHWtype unsigned short
8
9#define W_TYPE_SIZE 32
10
11#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
12#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
13#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
14
15/* If we still don't have umul_ppmm, define it using plain C. */
16#if !defined(umul_ppmm)
17#define umul_ppmm(w1, w0, u, v) \
18 do { \
19 UWtype __x0, __x1, __x2, __x3; \
20 UHWtype __ul, __vl, __uh, __vh; \
21 \
22 __ul = __ll_lowpart(u); \
23 __uh = __ll_highpart(u); \
24 __vl = __ll_lowpart(v); \
25 __vh = __ll_highpart(v); \
26 \
27 __x0 = (UWtype) __ul * __vl; \
28 __x1 = (UWtype) __ul * __vh; \
29 __x2 = (UWtype) __uh * __vl; \
30 __x3 = (UWtype) __uh * __vh; \
31 \
32 __x1 += __ll_highpart(__x0); /* this can't give carry */\
33 __x1 += __x2; /* but this indeed can */ \
34 if (__x1 < __x2) /* did we get it? */ \
35 __x3 += __ll_B; /* yes, add it in the proper pos */ \
36 \
37 (w1) = __x3 + __ll_highpart(__x1); \
38 (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\
39 } while (0)
40#endif
41
42#if !defined(__umulsidi3)
43#define __umulsidi3(u, v) ({ \
44 DWunion __w; \
45 umul_ppmm(__w.s.high, __w.s.low, u, v); \
46 __w.ll; \
47 })
48#endif
49
50DWtype __muldi3(DWtype u, DWtype v)
51{
52 const DWunion uu = {.ll = u};
53 const DWunion vv = {.ll = v};
54 DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)};
55
56 w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
57 + (UWtype) uu.s.high * (UWtype) vv.s.low);
58
59 return w.ll;
60}
61EXPORT_SYMBOL(__muldi3);
diff --git a/arch/microblaze/lib/mulsi3.S b/arch/microblaze/lib/mulsi3.S
new file mode 100644
index 000000000000..90bd7b93afe6
--- /dev/null
+++ b/arch/microblaze/lib/mulsi3.S
@@ -0,0 +1,46 @@
1#include <linux/linkage.h>
2
3/*
4 * Multiply operation for 32 bit integers.
5 * Input : Operand1 in Reg r5
6 * Operand2 in Reg r6
7 * Output: Result [op1 * op2] in Reg r3
8 */
9 .text
10 .globl __mulsi3
11 .type __mulsi3, @function
12 .ent __mulsi3
13
14__mulsi3:
15 .frame r1, 0, r15
16 add r3, r0, r0
17 beqi r5, result_is_zero /* multiply by zero */
18 beqi r6, result_is_zero /* multiply by zero */
19 bgeid r5, r5_pos
20 xor r4, r5, r6 /* get the sign of the result */
21 rsubi r5, r5, 0 /* make r5 positive */
22r5_pos:
23 bgei r6, r6_pos
24 rsubi r6, r6, 0 /* make r6 positive */
25r6_pos:
26 bri l1
27l2:
28 add r5, r5, r5
29l1:
30 srl r6, r6
31 addc r7, r0, r0
32 beqi r7, l2
33 bneid r6, l2
34 add r3, r3, r5
35 blti r4, negateresult
36 rtsd r15, 8
37 nop
38negateresult:
39 rtsd r15, 8
40 rsub r3, r3, r0
41result_is_zero:
42 rtsd r15, 8
43 addi r3, r0, 0
44
45.size __mulsi3, . - __mulsi3
46.end __mulsi3
diff --git a/arch/microblaze/lib/udivsi3.S b/arch/microblaze/lib/udivsi3.S
new file mode 100644
index 000000000000..64cf57e4bb85
--- /dev/null
+++ b/arch/microblaze/lib/udivsi3.S
@@ -0,0 +1,84 @@
1#include <linux/linkage.h>
2
3/*
4* Unsigned divide operation.
5* Input : Divisor in Reg r5
6* Dividend in Reg r6
7* Output: Result in Reg r3
8*/
9
10 .text
11 .globl __udivsi3
12 .type __udivsi3, @function
13 .ent __udivsi3
14
15__udivsi3:
16
17 .frame r1, 0, r15
18
19 addik r1, r1, -12
20 swi r29, r1, 0
21 swi r30, r1, 4
22 swi r31, r1, 8
23
24 beqi r6, div_by_zero /* div_by_zero /* division error */
25 beqid r5, result_is_zero /* result is zero */
26 addik r30, r0, 0 /* clear mod */
27 addik r29, r0, 32 /* initialize the loop count */
28
29/* check if r6 and r5 are equal - if yes, return 1 */
30 rsub r18, r5, r6
31 beqid r18, return_here
32 addik r3, r0, 1
33
34/* check if (uns)r6 is greater than (uns)r5. in that case, just return 0 */
35 xor r18, r5, r6
36 bgeid r18, 16
37 add r3, r0, r0 /* we would anyways clear r3 */
38 blti r6, return_here /* r6[bit 31 = 1] hence is greater */
39 bri checkr6
40 rsub r18, r6, r5 /* microblazecmp */
41 blti r18, return_here
42
43/* if r6 [bit 31] is set, then return result as 1 */
44checkr6:
45 bgti r6, div0
46 brid return_here
47 addik r3, r0, 1
48
49/* first part try to find the first '1' in the r5 */
50div0:
51 blti r5, div2
52div1:
53 add r5, r5, r5 /* left shift logical r5 */
54 bgtid r5, div1
55 addik r29, r29, -1
56div2:
57/* left shift logical r5 get the '1' into the carry */
58 add r5, r5, r5
59 addc r30, r30, r30 /* move that bit into the mod register */
60 rsub r31, r6, r30 /* try to subtract (r30 a r6) */
61 blti r31, mod_too_small
62/* move the r31 to mod since the result was positive */
63 or r30, r0, r31
64 addik r3, r3, 1
65mod_too_small:
66 addik r29, r29, -1
67 beqi r29, loop_end
68 add r3, r3, r3 /* shift in the '1' into div */
69 bri div2 /* div2 */
70loop_end:
71 bri return_here
72div_by_zero:
73result_is_zero:
74 or r3, r0, r0 /* set result to 0 */
75return_here:
76/* restore values of csrs and that of r3 and the divisor and the dividend */
77 lwi r29, r1, 0
78 lwi r30, r1, 4
79 lwi r31, r1, 8
80 rtsd r15, 8
81 addik r1, r1, 12
82
83.size __udivsi3, . - __udivsi3
84.end __udivsi3
diff --git a/arch/microblaze/lib/umodsi3.S b/arch/microblaze/lib/umodsi3.S
new file mode 100644
index 000000000000..17d16bafae58
--- /dev/null
+++ b/arch/microblaze/lib/umodsi3.S
@@ -0,0 +1,86 @@
1#include <linux/linkage.h>
2
3/*
4 * Unsigned modulo operation for 32 bit integers.
5 * Input : op1 in Reg r5
6 * op2 in Reg r6
7 * Output: op1 mod op2 in Reg r3
8 */
9
10 .text
11 .globl __umodsi3
12 .type __umodsi3, @function
13 .ent __umodsi3
14
15__umodsi3:
16 .frame r1, 0, r15
17
18 addik r1, r1, -12
19 swi r29, r1, 0
20 swi r30, r1, 4
21 swi r31, r1, 8
22
23 beqi r6, div_by_zero /* div_by_zero - division error */
24 beqid r5, result_is_zero /* result is zero */
25 addik r3, r0, 0 /* clear div */
26 addik r30, r0, 0 /* clear mod */
27 addik r29, r0, 32 /* initialize the loop count */
28
29/* check if r6 and r5 are equal /* if yes, return 0 */
30 rsub r18, r5, r6
31 beqi r18, return_here
32
33/* check if (uns)r6 is greater than (uns)r5. in that case, just return r5 */
34 xor r18, r5, r6
35 bgeid r18, 16
36 addik r3, r5, 0
37 blti r6, return_here
38 bri $lcheckr6
39 rsub r18, r5, r6 /* microblazecmp */
40 bgti r18, return_here
41
42/* if r6 [bit 31] is set, then return result as r5-r6 */
43$lcheckr6:
44 bgtid r6, div0
45 addik r3, r0, 0
46 addik r18, r0, 0x7fffffff
47 and r5, r5, r18
48 and r6, r6, r18
49 brid return_here
50 rsub r3, r6, r5
51/* first part: try to find the first '1' in the r5 */
52div0:
53 blti r5, div2
54div1:
55 add r5, r5, r5 /* left shift logical r5 */
56 bgeid r5, div1
57 addik r29, r29, -1
58div2:
59 /* left shift logical r5 get the '1' into the carry */
60 add r5, r5, r5
61 addc r3, r3, r3 /* move that bit into the mod register */
62 rsub r31, r6, r3 /* try to subtract (r3 a r6) */
63 blti r31, mod_too_small
64 /* move the r31 to mod since the result was positive */
65 or r3, r0, r31
66 addik r30, r30, 1
67mod_too_small:
68 addik r29, r29, -1
69 beqi r29, loop_end
70 add r30, r30, r30 /* shift in the '1' into div */
71 bri div2 /* div2 */
72loop_end:
73 bri return_here
74div_by_zero:
75result_is_zero:
76 or r3, r0, r0 /* set result to 0 */
77return_here:
78/* restore values of csrs and that of r3 and the divisor and the dividend */
79 lwi r29, r1, 0
80 lwi r30, r1, 4
81 lwi r31, r1, 8
82 rtsd r15, 8
83 addik r1, r1, 12
84
85.size __umodsi3, . - __umodsi3
86.end __umodsi3