aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/lib')
-rw-r--r--arch/blackfin/lib/Makefile11
-rw-r--r--arch/blackfin/lib/ashldi3.c58
-rw-r--r--arch/blackfin/lib/ashrdi3.c59
-rw-r--r--arch/blackfin/lib/checksum.c140
-rw-r--r--arch/blackfin/lib/divsi3.S216
-rw-r--r--arch/blackfin/lib/gcclib.h47
-rw-r--r--arch/blackfin/lib/ins.S69
-rw-r--r--arch/blackfin/lib/lshrdi3.c72
-rw-r--r--arch/blackfin/lib/memchr.S70
-rw-r--r--arch/blackfin/lib/memcmp.S110
-rw-r--r--arch/blackfin/lib/memcpy.S142
-rw-r--r--arch/blackfin/lib/memmove.S103
-rw-r--r--arch/blackfin/lib/memset.S109
-rw-r--r--arch/blackfin/lib/modsi3.S79
-rw-r--r--arch/blackfin/lib/muldi3.c99
-rw-r--r--arch/blackfin/lib/outs.S62
-rw-r--r--arch/blackfin/lib/smulsi3_highpart.S30
-rw-r--r--arch/blackfin/lib/strcmp.c11
-rw-r--r--arch/blackfin/lib/strcpy.c11
-rw-r--r--arch/blackfin/lib/strncmp.c11
-rw-r--r--arch/blackfin/lib/strncpy.c11
-rw-r--r--arch/blackfin/lib/udivsi3.S298
-rw-r--r--arch/blackfin/lib/umodsi3.S66
-rw-r--r--arch/blackfin/lib/umulsi3_highpart.S23
24 files changed, 1907 insertions, 0 deletions
diff --git a/arch/blackfin/lib/Makefile b/arch/blackfin/lib/Makefile
new file mode 100644
index 000000000000..635288fc5f54
--- /dev/null
+++ b/arch/blackfin/lib/Makefile
@@ -0,0 +1,11 @@
1#
2# arch/blackfin/lib/Makefile
3#
4
5lib-y := \
6 ashldi3.o ashrdi3.o lshrdi3.o \
7 muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
8 checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \
9 strcmp.o strcpy.o strncmp.o strncpy.o \
10 umulsi3_highpart.o smulsi3_highpart.o \
11 ins.o outs.o
diff --git a/arch/blackfin/lib/ashldi3.c b/arch/blackfin/lib/ashldi3.c
new file mode 100644
index 000000000000..a8c279e9b192
--- /dev/null
+++ b/arch/blackfin/lib/ashldi3.c
@@ -0,0 +1,58 @@
1/*
2 * File: arch/blackfin/lib/ashldi3.c
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 "gcclib.h"
31
32#ifdef CONFIG_ARITHMETIC_OPS_L1
33DItype __ashldi3(DItype u, word_type b)__attribute__((l1_text));
34#endif
35
36DItype __ashldi3(DItype u, word_type b)
37{
38 DIunion w;
39 word_type bm;
40 DIunion uu;
41
42 if (b == 0)
43 return u;
44
45 uu.ll = u;
46
47 bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
48 if (bm <= 0) {
49 w.s.low = 0;
50 w.s.high = (USItype) uu.s.low << -bm;
51 } else {
52 USItype carries = (USItype) uu.s.low >> bm;
53 w.s.low = (USItype) uu.s.low << b;
54 w.s.high = ((USItype) uu.s.high << b) | carries;
55 }
56
57 return w.ll;
58}
diff --git a/arch/blackfin/lib/ashrdi3.c b/arch/blackfin/lib/ashrdi3.c
new file mode 100644
index 000000000000..a0d3419329ca
--- /dev/null
+++ b/arch/blackfin/lib/ashrdi3.c
@@ -0,0 +1,59 @@
1/*
2 * File: arch/blackfin/lib/ashrdi3.c
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 "gcclib.h"
31
32#ifdef CONFIG_ARITHMETIC_OPS_L1
33DItype __ashrdi3(DItype u, word_type b)__attribute__((l1_text));
34#endif
35
36DItype __ashrdi3(DItype u, word_type b)
37{
38 DIunion w;
39 word_type bm;
40 DIunion uu;
41
42 if (b == 0)
43 return u;
44
45 uu.ll = u;
46
47 bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
48 if (bm <= 0) {
49 /* w.s.high = 1..1 or 0..0 */
50 w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
51 w.s.low = uu.s.high >> -bm;
52 } else {
53 USItype carries = (USItype) uu.s.high << bm;
54 w.s.high = uu.s.high >> b;
55 w.s.low = ((USItype) uu.s.low >> b) | carries;
56 }
57
58 return w.ll;
59}
diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c
new file mode 100644
index 000000000000..42768e0c80ca
--- /dev/null
+++ b/arch/blackfin/lib/checksum.c
@@ -0,0 +1,140 @@
1/*
2 * File: arch/blackfin/lib/checksum.c
3 * Based on: none - original work
4 * Author:
5 *
6 * Created:
7 * Description: An implementation of the TCP/IP protocol suite for the LINUX
8 * operating system. INET is implemented using the BSD Socket
9 * interface as the means of communication with the user level.
10 *
11 * Modified:
12 * Copyright 2004-2006 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#include <net/checksum.h>
33#include <asm/checksum.h>
34
35#ifdef CONFIG_IP_CHECKSUM_L1
36static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text));
37#endif
38
39static unsigned short do_csum(const unsigned char *buff, int len)
40{
41 register unsigned long sum = 0;
42 int swappem = 0;
43
44 if (1 & (unsigned long)buff) {
45 sum = *buff << 8;
46 buff++;
47 len--;
48 ++swappem;
49 }
50
51 while (len > 1) {
52 sum += *(unsigned short *)buff;
53 buff += 2;
54 len -= 2;
55 }
56
57 if (len > 0)
58 sum += *buff;
59
60 /* Fold 32-bit sum to 16 bits */
61 while (sum >> 16)
62 sum = (sum & 0xffff) + (sum >> 16);
63
64 if (swappem)
65 sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8);
66
67 return sum;
68
69}
70
71/*
72 * This is a version of ip_compute_csum() optimized for IP headers,
73 * which always checksum on 4 octet boundaries.
74 */
75unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
76{
77 return ~do_csum(iph, ihl * 4);
78}
79
80/*
81 * computes the checksum of a memory block at buff, length len,
82 * and adds in "sum" (32-bit)
83 *
84 * returns a 32-bit number suitable for feeding into itself
85 * or csum_tcpudp_magic
86 *
87 * this function must be called with even lengths, except
88 * for the last fragment, which may be odd
89 *
90 * it's best to have buff aligned on a 32-bit boundary
91 */
92unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
93{
94 /*
95 * Just in case we get nasty checksum data...
96 * Like 0xffff6ec3 in the case of our IPv6 multicast header.
97 * We fold to begin with, as well as at the end.
98 */
99 sum = (sum & 0xffff) + (sum >> 16);
100
101 sum += do_csum(buff, len);
102
103 sum = (sum & 0xffff) + (sum >> 16);
104
105 return sum;
106}
107
108/*
109 * this routine is used for miscellaneous IP-like checksums, mainly
110 * in icmp.c
111 */
112unsigned short ip_compute_csum(const unsigned char *buff, int len)
113{
114 return ~do_csum(buff, len);
115}
116
117/*
118 * copy from fs while checksumming, otherwise like csum_partial
119 */
120
121unsigned int
122csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
123 int len, int sum, int *csum_err)
124{
125 if (csum_err)
126 *csum_err = 0;
127 memcpy(dst, src, len);
128 return csum_partial(dst, len, sum);
129}
130
131/*
132 * copy from ds while checksumming, otherwise like csum_partial
133 */
134
135unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
136 int len, int sum)
137{
138 memcpy(dst, src, len);
139 return csum_partial(dst, len, sum);
140}
diff --git a/arch/blackfin/lib/divsi3.S b/arch/blackfin/lib/divsi3.S
new file mode 100644
index 000000000000..3e29861852b2
--- /dev/null
+++ b/arch/blackfin/lib/divsi3.S
@@ -0,0 +1,216 @@
1/*
2 * File: arch/blackfin/lib/divsi3.S
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: 16 / 32 bit signed division.
8 * Special cases :
9 * 1) If(numerator == 0)
10 * return 0
11 * 2) If(denominator ==0)
12 * return positive max = 0x7fffffff
13 * 3) If(numerator == denominator)
14 * return 1
15 * 4) If(denominator ==1)
16 * return numerator
17 * 5) If(denominator == -1)
18 * return -numerator
19 *
20 * Operand : R0 - Numerator (i)
21 * R1 - Denominator (i)
22 * R0 - Quotient (o)
23 * Registers Used : R2-R7,P0-P2
24 *
25 * Modified:
26 * Copyright 2004-2006 Analog Devices Inc.
27 *
28 * Bugs: Enter bugs at http://blackfin.uclinux.org/
29 *
30 * This program is free software; you can redistribute it and/or modify
31 * it under the terms of the GNU General Public License as published by
32 * the Free Software Foundation; either version 2 of the License, or
33 * (at your option) any later version.
34 *
35 * This program is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 * GNU General Public License for more details.
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, see the file COPYING, or write
42 * to the Free Software Foundation, Inc.,
43 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
44 */
45
46.global ___divsi3;
47
48#ifdef CONFIG_ARITHMETIC_OPS_L1
49.section .l1.text
50#else
51.text
52#endif
53
54.align 2;
55___divsi3 :
56
57
58 R3 = R0 ^ R1;
59 R0 = ABS R0;
60
61 CC = V;
62
63 r3 = rot r3 by -1;
64 r1 = abs r1; /* now both positive, r3.30 means "negate result",
65 ** r3.31 means overflow, add one to result
66 */
67 cc = r0 < r1;
68 if cc jump .Lret_zero;
69 r2 = r1 >> 15;
70 cc = r2;
71 if cc jump .Lidents;
72 r2 = r1 << 16;
73 cc = r2 <= r0;
74 if cc jump .Lidents;
75
76 DIVS(R0, R1);
77 DIVQ(R0, R1);
78 DIVQ(R0, R1);
79 DIVQ(R0, R1);
80 DIVQ(R0, R1);
81 DIVQ(R0, R1);
82 DIVQ(R0, R1);
83 DIVQ(R0, R1);
84 DIVQ(R0, R1);
85 DIVQ(R0, R1);
86 DIVQ(R0, R1);
87 DIVQ(R0, R1);
88 DIVQ(R0, R1);
89 DIVQ(R0, R1);
90 DIVQ(R0, R1);
91 DIVQ(R0, R1);
92 DIVQ(R0, R1);
93
94 R0 = R0.L (Z);
95 r1 = r3 >> 31; /* add overflow issue back in */
96 r0 = r0 + r1;
97 r1 = -r0;
98 cc = bittst(r3, 30);
99 if cc r0 = r1;
100 RTS;
101
102/* Can't use the primitives. Test common identities.
103** If the identity is true, return the value in R2.
104*/
105
106.Lidents:
107 CC = R1 == 0; /* check for divide by zero */
108 IF CC JUMP .Lident_return;
109
110 CC = R0 == 0; /* check for division of zero */
111 IF CC JUMP .Lzero_return;
112
113 CC = R0 == R1; /* check for identical operands */
114 IF CC JUMP .Lident_return;
115
116 CC = R1 == 1; /* check for divide by 1 */
117 IF CC JUMP .Lident_return;
118
119 R2.L = ONES R1;
120 R2 = R2.L (Z);
121 CC = R2 == 1;
122 IF CC JUMP .Lpower_of_two;
123
124 /* Identities haven't helped either.
125 ** Perform the full division process.
126 */
127
128 P1 = 31; /* Set loop counter */
129
130 [--SP] = (R7:5); /* Push registers R5-R7 */
131 R2 = -R1;
132 [--SP] = R2;
133 R2 = R0 << 1; /* R2 lsw of dividend */
134 R6 = R0 ^ R1; /* Get sign */
135 R5 = R6 >> 31; /* Shift sign to LSB */
136
137 R0 = 0 ; /* Clear msw partial remainder */
138 R2 = R2 | R5; /* Shift quotient bit */
139 R6 = R0 ^ R1; /* Get new quotient bit */
140
141 LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */
142.Llst: R7 = R2 >> 31; /* record copy of carry from R2 */
143 R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
144 R0 = R0 << 1 || R5 = [SP];
145 R0 = R0 | R7; /* and add carry */
146 CC = R6 < 0; /* Check quotient(AQ) */
147 /* we might be subtracting divisor (AQ==0) */
148 IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/
149 R0 = R0 + R5; /* do add or subtract, as indicated by AQ */
150 R6 = R0 ^ R1; /* Generate next quotient bit */
151 R5 = R6 >> 31;
152 /* Assume AQ==1, shift in zero */
153 BITTGL(R5,0); /* tweak AQ to be what we want to shift in */
154.Llend: R2 = R2 + R5; /* and then set shifted-in value to
155 ** tweaked AQ.
156 */
157 r1 = r3 >> 31;
158 r2 = r2 + r1;
159 cc = bittst(r3,30);
160 r0 = -r2;
161 if !cc r0 = r2;
162 SP += 4;
163 (R7:5)= [SP++]; /* Pop registers R6-R7 */
164 RTS;
165
166.Lident_return:
167 CC = R1 == 0; /* check for divide by zero => 0x7fffffff */
168 R2 = -1 (X);
169 R2 >>= 1;
170 IF CC JUMP .Ltrue_ident_return;
171
172 CC = R0 == R1; /* check for identical operands => 1 */
173 R2 = 1 (Z);
174 IF CC JUMP .Ltrue_ident_return;
175
176 R2 = R0; /* assume divide by 1 => numerator */
177 /*FALLTHRU*/
178
179.Ltrue_ident_return:
180 R0 = R2; /* Return an identity value */
181 R2 = -R2;
182 CC = bittst(R3,30);
183 IF CC R0 = R2;
184.Lzero_return:
185 RTS; /* ...including zero */
186
187.Lpower_of_two:
188 /* Y has a single bit set, which means it's a power of two.
189 ** That means we can perform the division just by shifting
190 ** X to the right the appropriate number of bits
191 */
192
193 /* signbits returns the number of sign bits, minus one.
194 ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
195 ** to shift right n-signbits spaces. It also means 0x80000000
196 ** is a special case, because that *also* gives a signbits of 0
197 */
198
199 R2 = R0 >> 31;
200 CC = R1 < 0;
201 IF CC JUMP .Ltrue_ident_return;
202
203 R1.l = SIGNBITS R1;
204 R1 = R1.L (Z);
205 R1 += -30;
206 R0 = LSHIFT R0 by R1.L;
207 r1 = r3 >> 31;
208 r0 = r0 + r1;
209 R2 = -R0; // negate result if necessary
210 CC = bittst(R3,30);
211 IF CC R0 = R2;
212 RTS;
213
214.Lret_zero:
215 R0 = 0;
216 RTS;
diff --git a/arch/blackfin/lib/gcclib.h b/arch/blackfin/lib/gcclib.h
new file mode 100644
index 000000000000..9ccd39a135ee
--- /dev/null
+++ b/arch/blackfin/lib/gcclib.h
@@ -0,0 +1,47 @@
1/*
2 * File: arch/blackfin/lib/gcclib.h
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#define BITS_PER_UNIT 8
31#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
32
33typedef unsigned int UQItype __attribute__ ((mode(QI)));
34typedef int SItype __attribute__ ((mode(SI)));
35typedef unsigned int USItype __attribute__ ((mode(SI)));
36typedef int DItype __attribute__ ((mode(DI)));
37typedef int word_type __attribute__ ((mode(__word__)));
38typedef unsigned int UDItype __attribute__ ((mode(DI)));
39
40struct DIstruct {
41 SItype low, high;
42};
43
44typedef union {
45 struct DIstruct s;
46 DItype ll;
47} DIunion;
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S
new file mode 100644
index 000000000000..730d2b427538
--- /dev/null
+++ b/arch/blackfin/lib/ins.S
@@ -0,0 +1,69 @@
1/*
2 * File: arch/blackfin/lib/ins.S
3 * Based on:
4 * Author: Bas Vermeulen <bas@buyways.nl>
5 *
6 * Created: Tue Mar 22 15:27:24 CEST 2005
7 * Description: Implementation of ins{bwl} for BlackFin processors using zero overhead loops.
8 *
9 * Modified:
10 * Copyright 2004-2006 Analog Devices Inc.
11 * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
12 *
13 * Bugs: Enter bugs at http://blackfin.uclinux.org/
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see the file COPYING, or write
27 * to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 */
30
31#include <linux/linkage.h>
32
33.align 2
34
35ENTRY(_insl)
36 P0 = R0; /* P0 = port */
37 cli R3;
38 P1 = R1; /* P1 = address */
39 P2 = R2; /* P2 = count */
40 SSYNC;
41 LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
42.Llong_loop_s: R0 = [P0];
43.Llong_loop_e: [P1++] = R0;
44 sti R3;
45 RTS;
46
47ENTRY(_insw)
48 P0 = R0; /* P0 = port */
49 cli R3;
50 P1 = R1; /* P1 = address */
51 P2 = R2; /* P2 = count */
52 SSYNC;
53 LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
54.Lword_loop_s: R0 = W[P0];
55.Lword_loop_e: W[P1++] = R0;
56 sti R3;
57 RTS;
58
59ENTRY(_insb)
60 P0 = R0; /* P0 = port */
61 cli R3;
62 P1 = R1; /* P1 = address */
63 P2 = R2; /* P2 = count */
64 SSYNC;
65 LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
66.Lbyte_loop_s: R0 = B[P0];
67.Lbyte_loop_e: B[P1++] = R0;
68 sti R3;
69 RTS;
diff --git a/arch/blackfin/lib/lshrdi3.c b/arch/blackfin/lib/lshrdi3.c
new file mode 100644
index 000000000000..84b9c5592220
--- /dev/null
+++ b/arch/blackfin/lib/lshrdi3.c
@@ -0,0 +1,72 @@
1/*
2 * File: arch/blackfin/lib/lshrdi3.c
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#define BITS_PER_UNIT 8
31
32typedef int SItype __attribute__ ((mode(SI)));
33typedef unsigned int USItype __attribute__ ((mode(SI)));
34typedef int DItype __attribute__ ((mode(DI)));
35typedef int word_type __attribute__ ((mode(__word__)));
36
37struct DIstruct {
38 SItype high, low;
39};
40
41typedef union {
42 struct DIstruct s;
43 DItype ll;
44} DIunion;
45
46#ifdef CONFIG_ARITHMETIC_OPS_L1
47DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text));
48#endif
49
50DItype __lshrdi3(DItype u, word_type b)
51{
52 DIunion w;
53 word_type bm;
54 DIunion uu;
55
56 if (b == 0)
57 return u;
58
59 uu.ll = u;
60
61 bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
62 if (bm <= 0) {
63 w.s.high = 0;
64 w.s.low = (USItype) uu.s.high >> -bm;
65 } else {
66 USItype carries = (USItype) uu.s.high << bm;
67 w.s.high = (USItype) uu.s.high >> b;
68 w.s.low = ((USItype) uu.s.low >> b) | carries;
69 }
70
71 return w.ll;
72}
diff --git a/arch/blackfin/lib/memchr.S b/arch/blackfin/lib/memchr.S
new file mode 100644
index 000000000000..498122250d07
--- /dev/null
+++ b/arch/blackfin/lib/memchr.S
@@ -0,0 +1,70 @@
1/*
2 * File: arch/blackfin/lib/memchr.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/* void *memchr(const void *s, int c, size_t n);
33 * R0 = address (s)
34 * R1 = sought byte (c)
35 * R2 = count (n)
36 *
37 * Returns pointer to located character.
38 */
39
40.text
41
42.align 2
43
44ENTRY(_memchr)
45 P0 = R0; /* P0 = address */
46 P2 = R2; /* P2 = count */
47 R1 = R1.B(Z);
48 CC = R2 == 0;
49 IF CC JUMP .Lfailed;
50
51.Lbytes:
52 LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
53
54.Lbyte_loop_s:
55 R3 = B[P0++](Z);
56 CC = R3 == R1;
57 IF CC JUMP .Lfound;
58.Lbyte_loop_e:
59 NOP;
60
61.Lfailed:
62 R0=0;
63 RTS;
64
65.Lfound:
66 R0 = P0;
67 R0 += -1;
68 RTS;
69
70.size _memchr,.-_memchr
diff --git a/arch/blackfin/lib/memcmp.S b/arch/blackfin/lib/memcmp.S
new file mode 100644
index 000000000000..5b9502368fc6
--- /dev/null
+++ b/arch/blackfin/lib/memcmp.S
@@ -0,0 +1,110 @@
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
44ENTRY(_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 MNOP || R0 = [P0++] || R1 = [I0++];
65 CC = R0 == R1;
66 IF !CC JUMP .Lquad_different;
67.Lquad_loop_e:
68 NOP;
69
70 P3 = I0; /* s2 */
71.Ltoo_small:
72 CC = P2 == 0; /* Check zero count*/
73 IF CC JUMP .Lfinished; /* very unlikely*/
74
75.Lbytes:
76 LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
77.Lbyte_loop_s:
78 R1 = B[P3++](Z); /* *s2 */
79 R0 = B[P0++](Z); /* *s1 */
80 CC = R0 == R1;
81 IF !CC JUMP .Ldifferent;
82.Lbyte_loop_e:
83 NOP;
84
85.Ldifferent:
86 R0 = R0 - R1;
87 P3 = I1;
88 RTS;
89
90.Lquad_different:
91 /* We've read two quads which don't match.
92 * Can't just compare them, because we're
93 * a little-endian machine, so the MSBs of
94 * the regs occur at later addresses in the
95 * string.
96 * Arrange to re-read those two quads again,
97 * byte-by-byte.
98 */
99 P0 += -4; /* back up to the start of the */
100 P3 = I0; /* quads, and increase the*/
101 P2 += 4; /* remainder count*/
102 P3 += -4;
103 JUMP .Lbytes;
104
105.Lfinished:
106 R0 = 0;
107 P3 = I1;
108 RTS;
109
110.size _memcmp,.-_memcmp
diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
new file mode 100644
index 000000000000..c1e00eff541c
--- /dev/null
+++ b/arch/blackfin/lib/memcpy.S
@@ -0,0 +1,142 @@
1/*
2 * File: arch/blackfin/lib/memcpy.S
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: internal version of memcpy(), issued by the compiler
8 * to copy blocks of data around.
9 * This is really memmove() - it has to be able to deal with
10 * possible overlaps, because that ambiguity is when the compiler
11 * gives up and calls a function. We have our own, internal version
12 * so that we get something we trust, even if the user has redefined
13 * the normal symbol.
14 *
15 * Modified:
16 * Copyright 2004-2006 Analog Devices Inc.
17 *
18 * Bugs: Enter bugs at http://blackfin.uclinux.org/
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, see the file COPYING, or write
32 * to the Free Software Foundation, Inc.,
33 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 */
35
36#include <linux/linkage.h>
37
38/* void *memcpy(void *dest, const void *src, size_t n);
39 * R0 = To Address (dest) (leave unchanged to form result)
40 * R1 = From Address (src)
41 * R2 = count
42 *
43 * Note: Favours word alignment
44 */
45
46#ifdef CONFIG_MEMCPY_L1
47.section .l1.text
48#else
49.text
50#endif
51
52.align 2
53
54ENTRY(_memcpy)
55 CC = R2 <= 0; /* length not positive? */
56 IF CC JUMP .L_P1L2147483647; /* Nothing to do */
57
58 P0 = R0 ; /* dst*/
59 P1 = R1 ; /* src*/
60 P2 = R2 ; /* length */
61
62 /* check for overlapping data */
63 CC = R1 < R0; /* src < dst */
64 IF !CC JUMP .Lno_overlap;
65 R3 = R1 + R2;
66 CC = R0 < R3; /* and dst < src+len */
67 IF CC JUMP .Lhas_overlap;
68
69.Lno_overlap:
70 /* Check for aligned data.*/
71
72 R3 = R1 | R0;
73 R0 = 0x3;
74 R3 = R3 & R0;
75 CC = R3; /* low bits set on either address? */
76 IF CC JUMP .Lnot_aligned;
77
78 /* Both addresses are word-aligned, so we can copy
79 at least part of the data using word copies.*/
80 P2 = P2 >> 2;
81 CC = P2 <= 2;
82 IF !CC JUMP .Lmore_than_seven;
83 /* less than eight bytes... */
84 P2 = R2;
85 LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
86 R0 = R1; /* setup src address for return */
87.Lthree_start:
88 R3 = B[P1++] (X);
89.Lthree_end:
90 B[P0++] = R3;
91
92 RTS;
93
94.Lmore_than_seven:
95 /* There's at least eight bytes to copy. */
96 P2 += -1; /* because we unroll one iteration */
97 LSETUP(.Lword_loop, .Lword_loop) LC0=P2;
98 R0 = R1;
99 I1 = P1;
100 R3 = [I1++];
101.Lword_loop:
102 MNOP || [P0++] = R3 || R3 = [I1++];
103
104 [P0++] = R3;
105 /* Any remaining bytes to copy? */
106 R3 = 0x3;
107 R3 = R2 & R3;
108 CC = R3 == 0;
109 P1 = I1; /* in case there's something left, */
110 IF !CC JUMP .Lbytes_left;
111 RTS;
112.Lbytes_left: P2 = R3;
113.Lnot_aligned:
114 /* From here, we're copying byte-by-byte. */
115 LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
116 R0 = R1; /* Save src address for return */
117.Lbyte_start:
118 R1 = B[P1++] (X);
119.Lbyte_end:
120 B[P0++] = R1;
121
122.L_P1L2147483647:
123 RTS;
124
125.Lhas_overlap:
126 /* Need to reverse the copying, because the
127 * dst would clobber the src.
128 * Don't bother to work out alignment for
129 * the reverse case.
130 */
131 R0 = R1; /* save src for later. */
132 P0 = P0 + P2;
133 P0 += -1;
134 P1 = P1 + P2;
135 P1 += -1;
136 LSETUP(.Lover_start, .Lover_end) LC0=P2;
137.Lover_start:
138 R1 = B[P1--] (X);
139.Lover_end:
140 B[P0--] = R1;
141
142 RTS;
diff --git a/arch/blackfin/lib/memmove.S b/arch/blackfin/lib/memmove.S
new file mode 100644
index 000000000000..2e5fb7f8df13
--- /dev/null
+++ b/arch/blackfin/lib/memmove.S
@@ -0,0 +1,103 @@
1/*
2 * File: arch/blackfin/lib/memmove.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.align 2
33
34/*
35 * C Library function MEMMOVE
36 * R0 = To Address (leave unchanged to form result)
37 * R1 = From Address
38 * R2 = count
39 * Data may overlap
40 */
41
42ENTRY(_memmove)
43 I1 = P3;
44 P0 = R0; /* P0 = To address */
45 P3 = R1; /* P3 = From Address */
46 P2 = R2; /* P2 = count */
47 CC = P2 == 0; /* Check zero count*/
48 IF CC JUMP .Lfinished; /* very unlikely */
49
50 CC = R1 < R0 (IU); /* From < To */
51 IF !CC JUMP .Lno_overlap;
52 R3 = R1 + R2;
53 CC = R0 <= R3 (IU); /* (From+len) >= To */
54 IF CC JUMP .Loverlap;
55.Lno_overlap:
56 R3 = 11;
57 CC = R2 <= R3;
58 IF CC JUMP .Lbytes;
59 R3 = R1 | R0; /* OR addresses together */
60 R3 <<= 30; /* check bottom two bits */
61 CC = AZ; /* AZ set if zero.*/
62 IF !CC JUMP .Lbytes; /* Jump if addrs not aligned.*/
63
64 I0 = P3;
65 P1 = P2 >> 2; /* count = n/4 */
66 P1 += -1;
67 R3 = 3;
68 R2 = R2 & R3; /* remainder */
69 P2 = R2; /* set remainder */
70 R1 = [I0++];
71
72 LSETUP (.Lquad_loop, .Lquad_loop) LC0=P1;
73.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++];
74 [P0++] = R1;
75
76 CC = P2 == 0; /* any remaining bytes? */
77 P3 = I0; /* Ammend P3 to updated ptr. */
78 IF !CC JUMP .Lbytes;
79 P3 = I1;
80 RTS;
81
82.Lbytes: LSETUP (.Lbyte2_s, .Lbyte2_e) LC0=P2;
83.Lbyte2_s: R1 = B[P3++](Z);
84.Lbyte2_e: B[P0++] = R1;
85
86.Lfinished: P3 = I1;
87 RTS;
88
89.Loverlap:
90 P2 += -1;
91 P0 = P0 + P2;
92 P3 = P3 + P2;
93 R1 = B[P3--] (Z);
94 CC = P2 == 0;
95 IF CC JUMP .Lno_loop;
96 LSETUP (.Lol_s, .Lol_e) LC0 = P2;
97.Lol_s: B[P0--] = R1;
98.Lol_e: R1 = B[P3--] (Z);
99.Lno_loop: B[P0] = R1;
100 P3 = I1;
101 RTS;
102
103.size _memmove,.-_memmove
diff --git a/arch/blackfin/lib/memset.S b/arch/blackfin/lib/memset.S
new file mode 100644
index 000000000000..ba6d047568dd
--- /dev/null
+++ b/arch/blackfin/lib/memset.S
@@ -0,0 +1,109 @@
1/*
2 * File: arch/blackfin/lib/memset.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.align 2
33
34#ifdef CONFIG_MEMSET_L1
35.section .l1.text
36#else
37.text
38#endif
39
40/*
41 * C Library function MEMSET
42 * R0 = address (leave unchanged to form result)
43 * R1 = filler byte
44 * R2 = count
45 * Favours word aligned data.
46 */
47
48ENTRY(_memset)
49 P0 = R0 ; /* P0 = address */
50 P2 = R2 ; /* P2 = count */
51 R3 = R0 + R2; /* end */
52 CC = R2 <= 7(IU);
53 IF CC JUMP .Ltoo_small;
54 R1 = R1.B (Z); /* R1 = fill char */
55 R2 = 3;
56 R2 = R0 & R2; /* addr bottom two bits */
57 CC = R2 == 0; /* AZ set if zero. */
58 IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */
59
60.Laligned:
61 P1 = P2 >> 2; /* count = n/4 */
62 R2 = R1 << 8; /* create quad filler */
63 R2.L = R2.L + R1.L(NS);
64 R2.H = R2.L + R1.H(NS);
65 P2 = R3;
66
67 LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
68.Lquad_loop:
69 [P0++] = R2;
70
71 CC = P0 == P2;
72 IF !CC JUMP .Lbytes_left;
73 RTS;
74
75.Lbytes_left:
76 R2 = R3; /* end point */
77 R3 = P0; /* current position */
78 R2 = R2 - R3; /* bytes left */
79 P2 = R2;
80
81.Ltoo_small:
82 CC = P2 == 0; /* Check zero count */
83 IF CC JUMP .Lfinished; /* Unusual */
84
85.Lbytes:
86 LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
87.Lbyte_loop:
88 B[P0++] = R1;
89
90.Lfinished:
91 RTS;
92
93.Lforce_align:
94 CC = BITTST (R0, 0); /* odd byte */
95 R0 = 4;
96 R0 = R0 - R2;
97 P1 = R0;
98 R0 = P0; /* Recover return address */
99 IF !CC JUMP .Lskip1;
100 B[P0++] = R1;
101.Lskip1:
102 CC = R2 <= 2; /* 2 bytes */
103 P2 -= P1; /* reduce count */
104 IF !CC JUMP .Laligned;
105 B[P0++] = R1;
106 B[P0++] = R1;
107 JUMP .Laligned;
108
109.size _memset,.-_memset
diff --git a/arch/blackfin/lib/modsi3.S b/arch/blackfin/lib/modsi3.S
new file mode 100644
index 000000000000..528b8b1ccb34
--- /dev/null
+++ b/arch/blackfin/lib/modsi3.S
@@ -0,0 +1,79 @@
1/*
2 * File: arch/blackfin/lib/modsi3.S
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: This program computes 32 bit signed remainder. It calls div32 function
8 * for quotient estimation.
9 *
10 * Registers used :
11 * Numerator/ Denominator in R0, R1
12 * R0 - returns remainder.
13 * R2-R7
14 *
15 * Modified:
16 * Copyright 2004-2006 Analog Devices Inc.
17 *
18 * Bugs: Enter bugs at http://blackfin.uclinux.org/
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, see the file COPYING, or write
32 * to the Free Software Foundation, Inc.,
33 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 */
35
36.global ___modsi3;
37.type ___modsi3, STT_FUNC;
38.extern ___divsi3;
39.type ___divsi3, STT_FUNC;
40
41#ifdef CONFIG_ARITHMETIC_OPS_L1
42.section .l1.text
43#else
44.text
45#endif
46
47___modsi3:
48
49 CC=R0==0;
50 IF CC JUMP .LRETURN_R0; /* Return 0, if numerator == 0 */
51 CC=R1==0;
52 IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 0 */
53 CC=R0==R1;
54 IF CC JUMP .LRETURN_ZERO; /* Return 0, if numerator == denominator */
55 CC = R1 == 1;
56 IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 1 */
57 CC = R1 == -1;
58 IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == -1 */
59
60 /* Valid input. Use __divsi3() to compute the quotient, and then
61 * derive the remainder from that. */
62
63 [--SP] = (R7:6); /* Push R7 and R6 */
64 [--SP] = RETS; /* and return address */
65 R7 = R0; /* Copy of R0 */
66 R6 = R1; /* Save for later */
67 SP += -12; /* Should always provide this space */
68 CALL ___divsi3; /* Compute signed quotient using ___divsi3()*/
69 SP += 12;
70 R0 *= R6; /* Quotient * divisor */
71 R0 = R7 - R0; /* Dividend - (quotient * divisor) */
72 RETS = [SP++]; /* Get back return address */
73 (R7:6) = [SP++]; /* Pop registers R7 and R4 */
74 RTS; /* Store remainder */
75
76.LRETURN_ZERO:
77 R0 = 0;
78.LRETURN_R0:
79 RTS;
diff --git a/arch/blackfin/lib/muldi3.c b/arch/blackfin/lib/muldi3.c
new file mode 100644
index 000000000000..303d0c6a6dba
--- /dev/null
+++ b/arch/blackfin/lib/muldi3.c
@@ -0,0 +1,99 @@
1/*
2 * File: arch/blackfin/lib/muldi3.c
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#ifndef SI_TYPE_SIZE
31#define SI_TYPE_SIZE 32
32#endif
33#define __ll_b (1L << (SI_TYPE_SIZE / 2))
34#define __ll_lowpart(t) ((usitype) (t) % __ll_b)
35#define __ll_highpart(t) ((usitype) (t) / __ll_b)
36#define BITS_PER_UNIT 8
37
38#if !defined(umul_ppmm)
39#define umul_ppmm(w1, w0, u, v) \
40 do { \
41 usitype __x0, __x1, __x2, __x3; \
42 usitype __ul, __vl, __uh, __vh; \
43 \
44 __ul = __ll_lowpart (u); \
45 __uh = __ll_highpart (u); \
46 __vl = __ll_lowpart (v); \
47 __vh = __ll_highpart (v); \
48 \
49 __x0 = (usitype) __ul * __vl; \
50 __x1 = (usitype) __ul * __vh; \
51 __x2 = (usitype) __uh * __vl; \
52 __x3 = (usitype) __uh * __vh; \
53 \
54 __x1 += __ll_highpart (__x0);/* this can't give carry */ \
55 __x1 += __x2; /* but this indeed can */ \
56 if (__x1 < __x2) /* did we get it? */ \
57 __x3 += __ll_b; /* yes, add it in the proper pos. */ \
58 \
59 (w1) = __x3 + __ll_highpart (__x1); \
60 (w0) = __ll_lowpart (__x1) * __ll_b + __ll_lowpart (__x0); \
61 } while (0)
62#endif
63
64#if !defined(__umulsidi3)
65#define __umulsidi3(u, v) \
66 ({diunion __w; \
67 umul_ppmm (__w.s.high, __w.s.low, u, v); \
68 __w.ll; })
69#endif
70
71typedef unsigned int usitype __attribute__ ((mode(SI)));
72typedef int sitype __attribute__ ((mode(SI)));
73typedef int ditype __attribute__ ((mode(DI)));
74typedef int word_type __attribute__ ((mode(__word__)));
75
76struct distruct {
77 sitype low, high;
78};
79typedef union {
80 struct distruct s;
81 ditype ll;
82} diunion;
83
84#ifdef CONFIG_ARITHMETIC_OPS_L1
85ditype __muldi3(ditype u, ditype v)__attribute__((l1_text));
86#endif
87
88ditype __muldi3(ditype u, ditype v)
89{
90 diunion w;
91 diunion uu, vv;
92
93 uu.ll = u, vv.ll = v;
94 w.ll = __umulsidi3(uu.s.low, vv.s.low);
95 w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high
96 + (usitype) uu.s.high * (usitype) vv.s.low);
97
98 return w.ll;
99}
diff --git a/arch/blackfin/lib/outs.S b/arch/blackfin/lib/outs.S
new file mode 100644
index 000000000000..f8c876fe8930
--- /dev/null
+++ b/arch/blackfin/lib/outs.S
@@ -0,0 +1,62 @@
1/*
2 * File: arch/blackfin/lib/outs.S
3 * Based on:
4 * Author: Bas Vermeulen <bas@buyways.nl>
5 *
6 * Created: Tue Mar 22 15:27:24 CEST 2005
7 * Description: Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
8 *
9 * Modified: Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
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.align 2
33
34ENTRY(_outsl)
35 P0 = R0; /* P0 = port */
36 P1 = R1; /* P1 = address */
37 P2 = R2; /* P2 = count */
38
39 LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
40.Llong_loop_s: R0 = [P1++];
41.Llong_loop_e: [P0] = R0;
42 RTS;
43
44ENTRY(_outsw)
45 P0 = R0; /* P0 = port */
46 P1 = R1; /* P1 = address */
47 P2 = R2; /* P2 = count */
48
49 LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
50.Lword_loop_s: R0 = W[P1++];
51.Lword_loop_e: W[P0] = R0;
52 RTS;
53
54ENTRY(_outsb)
55 P0 = R0; /* P0 = port */
56 P1 = R1; /* P1 = address */
57 P2 = R2; /* P2 = count */
58
59 LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
60.Lbyte_loop_s: R0 = B[P1++];
61.Lbyte_loop_e: B[P0] = R0;
62 RTS;
diff --git a/arch/blackfin/lib/smulsi3_highpart.S b/arch/blackfin/lib/smulsi3_highpart.S
new file mode 100644
index 000000000000..10b8f8da576f
--- /dev/null
+++ b/arch/blackfin/lib/smulsi3_highpart.S
@@ -0,0 +1,30 @@
1.align 2
2.global ___smulsi3_highpart;
3.type ___smulsi3_highpart, STT_FUNC;
4
5#ifdef CONFIG_ARITHMETIC_OPS_L1
6.section .l1.text
7#else
8.text
9#endif
10
11___smulsi3_highpart:
12 R2 = R1.L * R0.L (FU);
13 R3 = R1.H * R0.L (IS,M);
14 R0 = R0.H * R1.H, R1 = R0.H * R1.L (IS,M);
15
16 R1.L = R2.H + R1.L;
17 cc = ac0;
18 R2 = cc;
19
20 R1.L = R1.L + R3.L;
21 cc = ac0;
22 R1 >>>= 16;
23 R3 >>>= 16;
24 R1 = R1 + R3;
25 R1 = R1 + R2;
26 R2 = cc;
27 R1 = R1 + R2;
28
29 R0 = R0 + R1;
30 RTS;
diff --git a/arch/blackfin/lib/strcmp.c b/arch/blackfin/lib/strcmp.c
new file mode 100644
index 000000000000..2ad47c4254ba
--- /dev/null
+++ b/arch/blackfin/lib/strcmp.c
@@ -0,0 +1,11 @@
1#include <linux/types.h>
2
3#define strcmp __inline_strcmp
4#include <asm/string.h>
5#undef strcmp
6
7int strcmp(const char *dest, const char *src)
8{
9 return __inline_strcmp(dest, src);
10}
11
diff --git a/arch/blackfin/lib/strcpy.c b/arch/blackfin/lib/strcpy.c
new file mode 100644
index 000000000000..4dc835a8a19b
--- /dev/null
+++ b/arch/blackfin/lib/strcpy.c
@@ -0,0 +1,11 @@
1#include <linux/types.h>
2
3#define strcpy __inline_strcpy
4#include <asm/string.h>
5#undef strcpy
6
7char *strcpy(char *dest, const char *src)
8{
9 return __inline_strcpy(dest, src);
10}
11
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c
new file mode 100644
index 000000000000..947bcfe3f3bb
--- /dev/null
+++ b/arch/blackfin/lib/strncmp.c
@@ -0,0 +1,11 @@
1#include <linux/types.h>
2
3#define strncmp __inline_strncmp
4#include <asm/string.h>
5#undef strncmp
6
7int strncmp(const char *cs, const char *ct, size_t count)
8{
9 return __inline_strncmp(cs, ct, count);
10}
11
diff --git a/arch/blackfin/lib/strncpy.c b/arch/blackfin/lib/strncpy.c
new file mode 100644
index 000000000000..77a9b2e95097
--- /dev/null
+++ b/arch/blackfin/lib/strncpy.c
@@ -0,0 +1,11 @@
1#include <linux/types.h>
2
3#define strncpy __inline_strncpy
4#include <asm/string.h>
5#undef strncpy
6
7char *strncpy(char *dest, const char *src, size_t n)
8{
9 return __inline_strncpy(dest, src, n);
10}
11
diff --git a/arch/blackfin/lib/udivsi3.S b/arch/blackfin/lib/udivsi3.S
new file mode 100644
index 000000000000..d39a12916259
--- /dev/null
+++ b/arch/blackfin/lib/udivsi3.S
@@ -0,0 +1,298 @@
1/*
2 * File: arch/blackfin/lib/udivsi3.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#define CARRY AC0
33
34#ifdef CONFIG_ARITHMETIC_OPS_L1
35.section .l1.text
36#else
37.text
38#endif
39
40
41ENTRY(___udivsi3)
42
43 CC = R0 < R1 (IU); /* If X < Y, always return 0 */
44 IF CC JUMP .Lreturn_ident;
45
46 R2 = R1 << 16;
47 CC = R2 <= R0 (IU);
48 IF CC JUMP .Lidents;
49
50 R2 = R0 >> 31; /* if X is a 31-bit number */
51 R3 = R1 >> 15; /* and Y is a 15-bit number */
52 R2 = R2 | R3; /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/
53 CC = R2;
54 IF CC JUMP .Ly_16bit;
55
56/* METHOD 1: FAST DIVQ
57 We know we have a 31-bit dividend, and 15-bit divisor so we can use the
58 simple divq approach (first setting AQ to 0 - implying unsigned division,
59 then 16 DIVQ's).
60*/
61
62 AQ = CC; /* Clear AQ (CC==0) */
63
64/* ISR States: When dividing two integers (32.0/16.0) using divide primitives,
65 we need to shift the dividend one bit to the left.
66 We have already checked that we have a 31-bit number so we are safe to do
67 that.
68*/
69 R0 <<= 1;
70 DIVQ(R0, R1); // 1
71 DIVQ(R0, R1); // 2
72 DIVQ(R0, R1); // 3
73 DIVQ(R0, R1); // 4
74 DIVQ(R0, R1); // 5
75 DIVQ(R0, R1); // 6
76 DIVQ(R0, R1); // 7
77 DIVQ(R0, R1); // 8
78 DIVQ(R0, R1); // 9
79 DIVQ(R0, R1); // 10
80 DIVQ(R0, R1); // 11
81 DIVQ(R0, R1); // 12
82 DIVQ(R0, R1); // 13
83 DIVQ(R0, R1); // 14
84 DIVQ(R0, R1); // 15
85 DIVQ(R0, R1); // 16
86 R0 = R0.L (Z);
87 RTS;
88
89.Ly_16bit:
90 /* We know that the upper 17 bits of Y might have bits set,
91 ** or that the sign bit of X might have a bit. If Y is a
92 ** 16-bit number, but not bigger, then we can use the builtins
93 ** with a post-divide correction.
94 ** R3 currently holds Y>>15, which means R3's LSB is the
95 ** bit we're interested in.
96 */
97
98 /* According to the ISR, to use the Divide primitives for
99 ** unsigned integer divide, the useable range is 31 bits
100 */
101 CC = ! BITTST(R0, 31);
102
103 /* IF condition is true we can scale our inputs and use the divide primitives,
104 ** with some post-adjustment
105 */
106 R3 += -1; /* if so, Y is 0x00008nnn */
107 CC &= AZ;
108
109 /* If condition is true we can scale our inputs and use the divide primitives,
110 ** with some post-adjustment
111 */
112 R3 = R1 >> 1; /* Pre-scaled divisor for primitive case */
113 R2 = R0 >> 16;
114
115 R2 = R3 - R2; /* shifted divisor < upper 16 bits of dividend */
116 CC &= CARRY;
117 IF CC JUMP .Lshift_and_correct;
118
119 /* Fall through to the identities */
120
121/* METHOD 2: identities and manual calculation
122 We are not able to use the divide primites, but may still catch some special
123 cases.
124*/
125.Lidents:
126 /* Test for common identities. Value to be returned is placed in R2. */
127 CC = R0 == 0; /* 0/Y => 0 */
128 IF CC JUMP .Lreturn_r0;
129 CC = R0 == R1; /* X==Y => 1 */
130 IF CC JUMP .Lreturn_ident;
131 CC = R1 == 1; /* X/1 => X */
132 IF CC JUMP .Lreturn_ident;
133
134 R2.L = ONES R1;
135 R2 = R2.L (Z);
136 CC = R2 == 1;
137 IF CC JUMP .Lpower_of_two;
138
139 [--SP] = (R7:5); /* Push registers R5-R7 */
140
141 /* Idents don't match. Go for the full operation. */
142
143
144 R6 = 2; /* assume we'll shift two */
145 R3 = 1;
146
147 P2 = R1;
148 /* If either R0 or R1 have sign set, */
149 /* divide them by two, and note it's */
150 /* been done. */
151 CC = R1 < 0;
152 R2 = R1 >> 1;
153 IF CC R1 = R2; /* Possibly-shifted R1 */
154 IF !CC R6 = R3; /* R1 doesn't, so at most 1 shifted */
155
156 P0 = 0;
157 R3 = -R1;
158 [--SP] = R3;
159 R2 = R0 >> 1;
160 R2 = R0 >> 1;
161 CC = R0 < 0;
162 IF CC P0 = R6; /* Number of values divided */
163 IF !CC R2 = R0; /* Shifted R0 */
164
165 /* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */
166
167 /* r2 holds Copy dividend */
168 R3 = 0; /* Clear partial remainder */
169 R7 = 0; /* Initialise quotient bit */
170
171 P1 = 32; /* Set loop counter */
172 LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */
173.Lulst: R6 = R2 >> 31; /* R6 = sign bit of R2, for carry */
174 R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
175 R3 = R3 << 1 || R5 = [SP];
176 R3 = R3 | R6; /* Include any carry */
177 CC = R7 < 0; /* Check quotient(AQ) */
178 /* If AQ==0, we'll sub divisor */
179 IF CC R5 = R1; /* and if AQ==1, we'll add it. */
180 R3 = R3 + R5; /* Add/sub divsor to partial remainder */
181 R7 = R3 ^ R1; /* Generate next quotient bit */
182
183 R5 = R7 >> 31; /* Get AQ */
184 BITTGL(R5, 0); /* Invert it, to get what we'll shift */
185.Lulend: R2 = R2 + R5; /* and "shift" it in. */
186
187 CC = P0 == 0; /* Check how many inputs we shifted */
188 IF CC JUMP .Lno_mult; /* if none... */
189 R6 = R2 << 1;
190 CC = P0 == 1;
191 IF CC R2 = R6; /* if 1, Q = Q*2 */
192 IF !CC R1 = P2; /* if 2, restore stored divisor */
193
194 R3 = R2; /* Copy of R2 */
195 R3 *= R1; /* Q * divisor */
196 R5 = R0 - R3; /* Z = (dividend - Q * divisor) */
197 CC = R1 <= R5 (IU); /* Check if divisor <= Z? */
198 R6 = CC; /* if yes, R6 = 1 */
199 R2 = R2 + R6; /* if yes, add one to quotient(Q) */
200.Lno_mult:
201 SP += 4;
202 (R7:5) = [SP++]; /* Pop registers R5-R7 */
203 R0 = R2; /* Store quotient */
204 RTS;
205
206.Lreturn_ident:
207 CC = R0 < R1 (IU); /* If X < Y, always return 0 */
208 R2 = 0;
209 IF CC JUMP .Ltrue_return_ident;
210 R2 = -1 (X); /* X/0 => 0xFFFFFFFF */
211 CC = R1 == 0;
212 IF CC JUMP .Ltrue_return_ident;
213 R2 = -R2; /* R2 now 1 */
214 CC = R0 == R1; /* X==Y => 1 */
215 IF CC JUMP .Ltrue_return_ident;
216 R2 = R0; /* X/1 => X */
217 /*FALLTHRU*/
218
219.Ltrue_return_ident:
220 R0 = R2;
221.Lreturn_r0:
222 RTS;
223
224.Lpower_of_two:
225 /* Y has a single bit set, which means it's a power of two.
226 ** That means we can perform the division just by shifting
227 ** X to the right the appropriate number of bits
228 */
229
230 /* signbits returns the number of sign bits, minus one.
231 ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
232 ** to shift right n-signbits spaces. It also means 0x80000000
233 ** is a special case, because that *also* gives a signbits of 0
234 */
235
236 R2 = R0 >> 31;
237 CC = R1 < 0;
238 IF CC JUMP .Ltrue_return_ident;
239
240 R1.l = SIGNBITS R1;
241 R1 = R1.L (Z);
242 R1 += -30;
243 R0 = LSHIFT R0 by R1.L;
244 RTS;
245
246/* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION
247 Two scaling operations are required to use the divide primitives with a
248 divisor > 0x7FFFF.
249 Firstly (as in method 1) we need to shift the dividend 1 to the left for
250 integer division.
251 Secondly we need to shift both the divisor and dividend 1 to the right so
252 both are in range for the primitives.
253 The left/right shift of the dividend does nothing so we can skip it.
254*/
255.Lshift_and_correct:
256 R2 = R0;
257 // R3 is already R1 >> 1
258 CC=!CC;
259 AQ = CC; /* Clear AQ, got here with CC = 0 */
260 DIVQ(R2, R3); // 1
261 DIVQ(R2, R3); // 2
262 DIVQ(R2, R3); // 3
263 DIVQ(R2, R3); // 4
264 DIVQ(R2, R3); // 5
265 DIVQ(R2, R3); // 6
266 DIVQ(R2, R3); // 7
267 DIVQ(R2, R3); // 8
268 DIVQ(R2, R3); // 9
269 DIVQ(R2, R3); // 10
270 DIVQ(R2, R3); // 11
271 DIVQ(R2, R3); // 12
272 DIVQ(R2, R3); // 13
273 DIVQ(R2, R3); // 14
274 DIVQ(R2, R3); // 15
275 DIVQ(R2, R3); // 16
276
277 /* According to the Instruction Set Reference:
278 To divide by a divisor > 0x7FFF,
279 1. prescale and perform divide to obtain quotient (Q) (done above),
280 2. multiply quotient by unscaled divisor (result M)
281 3. subtract the product from the divident to get an error (E = X - M)
282 4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q)
283 */
284 R3 = R2.L (Z); /* Q = X' / Y' */
285 R2 = R3; /* Preserve Q */
286 R2 *= R1; /* M = Q * Y */
287 R2 = R0 - R2; /* E = X - M */
288 R0 = R3; /* Copy Q into result reg */
289
290/* Correction: If result of the multiply is negative, we overflowed
291 and need to correct the result by subtracting 1 from the result.*/
292 R3 = 0xFFFF (Z);
293 R2 = R2 >> 16; /* E >> 16 */
294 CC = R2 == R3;
295 R3 = 1 ;
296 R1 = R0 - R3;
297 IF CC R0 = R1;
298 RTS;
diff --git a/arch/blackfin/lib/umodsi3.S b/arch/blackfin/lib/umodsi3.S
new file mode 100644
index 000000000000..b55ce96ab89f
--- /dev/null
+++ b/arch/blackfin/lib/umodsi3.S
@@ -0,0 +1,66 @@
1/*
2 * File: arch/blackfin/lib/umodsi3.S
3 * Based on:
4 * Author:
5 *
6 * Created:
7 * Description: libgcc1 routines for Blackfin 5xx
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#ifdef CONFIG_ARITHMETIC_OPS_L1
31.section .l1.text
32#else
33.text
34#endif
35
36.extern ___udivsi3;
37.globl ___umodsi3
38___umodsi3:
39
40 CC=R0==0;
41 IF CC JUMP .LRETURN_R0; /* Return 0, if NR == 0 */
42 CC= R1==0;
43 IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 0 */
44 CC=R0==R1;
45 IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if NR == DR */
46 CC = R1 == 1;
47 IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 1 */
48 CC = R0<R1 (IU);
49 IF CC JUMP .LRETURN_R0; /* Return dividend (R0),IF NR<DR */
50
51 [--SP] = (R7:6); /* Push registers and */
52 [--SP] = RETS; /* Return address */
53 R7 = R0; /* Copy of R0 */
54 R6 = R1;
55 SP += -12; /* Should always provide this space */
56 CALL ___udivsi3; /* Compute unsigned quotient using ___udiv32()*/
57 SP += 12;
58 R0 *= R6; /* Quotient * divisor */
59 R0 = R7 - R0; /* Dividend - (quotient * divisor) */
60 RETS = [SP++]; /* Pop return address */
61 ( R7:6) = [SP++]; /* And registers */
62 RTS; /* Return remainder */
63.LRETURN_ZERO_VAL:
64 R0 = 0;
65.LRETURN_R0:
66 RTS;
diff --git a/arch/blackfin/lib/umulsi3_highpart.S b/arch/blackfin/lib/umulsi3_highpart.S
new file mode 100644
index 000000000000..aac8218fb258
--- /dev/null
+++ b/arch/blackfin/lib/umulsi3_highpart.S
@@ -0,0 +1,23 @@
1.align 2
2.global ___umulsi3_highpart;
3.type ___umulsi3_highpart, STT_FUNC;
4
5#ifdef CONFIG_ARITHMETIC_OPS_L1
6.section .l1.text
7#else
8.text
9#endif
10
11___umulsi3_highpart:
12 R2 = R1.H * R0.H, R3 = R1.L * R0.H (FU);
13 R0 = R1.L * R0.L, R1 = R1.H * R0.L (FU);
14 R0 >>= 16;
15 /* Unsigned multiplication has the nice property that we can
16 ignore carry on this first addition. */
17 R0 = R0 + R3;
18 R0 = R0 + R1;
19 cc = ac0;
20 R1 = cc;
21 R1 = PACK(R1.l,R0.h);
22 R0 = R1 + R2;
23 RTS;