0
|
1 |
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
2 |
// All rights reserved.
|
|
3 |
// This component and the accompanying materials are made available
|
|
4 |
// under the terms of the License "Eclipse Public License v1.0"
|
|
5 |
// which accompanies this distribution, and is available
|
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
|
7 |
//
|
|
8 |
// Initial Contributors:
|
|
9 |
// Nokia Corporation - initial contribution.
|
|
10 |
//
|
|
11 |
// Contributors:
|
|
12 |
//
|
|
13 |
// Description:
|
|
14 |
// e32\common\arm\atomic_8_16_v6.h
|
|
15 |
// 8 and 16 bit atomic operations on V6 processors using LDREX/STREX and shifts
|
|
16 |
// Must use these user side so that it will work with data paging.
|
|
17 |
//
|
|
18 |
//
|
|
19 |
|
|
20 |
#include "atomic_ops.h"
|
|
21 |
|
|
22 |
#if defined(__CPU_ARM_HAS_LDREX_STREX_V6K) || !defined(__CPU_ARM_HAS_LDREX_STREX)
|
|
23 |
#error 8/16 bit atomic operations using LDREX/STREX
|
|
24 |
#endif
|
|
25 |
|
|
26 |
#ifdef __BARRIERS_NEEDED__
|
|
27 |
#error Barriers not supported on V6/V5, only V6K/V7
|
|
28 |
#endif
|
|
29 |
|
|
30 |
#if __DATA_SIZE__!=8 && __DATA_SIZE__!=16
|
|
31 |
#error Unsupported data size
|
|
32 |
#endif
|
|
33 |
|
|
34 |
#if defined(__OP_LOAD__)
|
|
35 |
#error Load operation not defined
|
|
36 |
|
|
37 |
#elif defined(__OP_STORE__)
|
|
38 |
#error Store operation not defined
|
|
39 |
|
|
40 |
#elif defined(__OP_RMW1__)
|
|
41 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
|
|
42 |
{
|
|
43 |
// R0=a, R1=v
|
|
44 |
// return value in R0
|
|
45 |
// just fall through
|
|
46 |
}
|
|
47 |
|
|
48 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
|
|
49 |
{
|
|
50 |
// R0=a, R1=v
|
|
51 |
// return value in R0
|
|
52 |
// just fall through
|
|
53 |
}
|
|
54 |
|
|
55 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
|
|
56 |
{
|
|
57 |
// R0=a, R1=v
|
|
58 |
// return value in R0
|
|
59 |
// just fall through
|
|
60 |
}
|
|
61 |
|
|
62 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*v*/)
|
|
63 |
{
|
|
64 |
// R0=a, R1=v
|
|
65 |
// return value in R0
|
|
66 |
asm("bic r12, r0, #3 ");
|
|
67 |
asm("and r3, r0, #3 ");
|
|
68 |
asm("stmfd sp!, {r4-r5} ");
|
|
69 |
asm("movs r4, r3, lsl #3 "); // r4 = bit offset of data in word
|
|
70 |
#if __DATA_SIZE__==16
|
|
71 |
asm("eor r4, r4, #16 "); // r4 = right rotate to take hword of interest to top (0->16, 2->0)
|
|
72 |
asm("mov r5, r4 ");
|
|
73 |
#elif __DATA_SIZE__==8
|
|
74 |
asm("add r4, r4, #8 ");
|
|
75 |
asm("and r4, r4, #31 "); // right rotate to take byte of interest to top byte (0->8, 1->16, 2->24, 3->0)
|
|
76 |
asm("rsb r5, r4, #32 ");
|
|
77 |
asm("and r5, r5, #31 "); // right rotate to take top byte to byte of interest (0->8, 1->16, 2->24, 3->0)
|
|
78 |
#endif
|
|
79 |
#if defined(__OP_AND__)
|
|
80 |
asm("mvn r1, r1 ");
|
|
81 |
asm("mvn r1, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__)); // v in upper bits of r1, 1's in lower bits
|
|
82 |
#endif
|
|
83 |
asm("1: ");
|
|
84 |
LDREX(0,12);
|
|
85 |
asm("mov r0, r0, ror r4 "); // rotate so desired data is at top
|
|
86 |
#if defined(__OP_SWP__)
|
|
87 |
asm("orr r2, r1, r0, lsl #%a0" : : "i" (__DATA_SIZE__));
|
|
88 |
asm("mov r2, r2, ror #%a0" : : "i" (__DATA_SIZE__));
|
|
89 |
#elif defined(__OP_ADD__)
|
|
90 |
asm("add r2, r0, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));
|
|
91 |
#elif defined(__OP_AND__)
|
|
92 |
asm("and r2, r0, r1 ");
|
|
93 |
#elif defined(__OP_IOR__)
|
|
94 |
asm("orr r2, r0, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));
|
|
95 |
#elif defined(__OP_XOR__)
|
|
96 |
asm("eor r2, r0, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__));
|
|
97 |
#endif
|
|
98 |
asm("mov r2, r2, ror r5 "); // rotate back
|
|
99 |
STREX(3,2,12);
|
|
100 |
asm("cmp r3, #0 ");
|
|
101 |
asm("bne 1b ");
|
|
102 |
asm("mov r0, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__)); // shift return value so data is at bottom
|
|
103 |
asm("ldmfd sp!, {r4-r5} ");
|
|
104 |
__JUMP(,lr);
|
|
105 |
}
|
|
106 |
|
|
107 |
|
|
108 |
#elif defined(__OP_CAS__)
|
|
109 |
extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
|
|
110 |
{
|
|
111 |
// R0=a, R1=q, R2=v
|
|
112 |
// return value in R0
|
|
113 |
// just fall through
|
|
114 |
}
|
|
115 |
|
|
116 |
extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
|
|
117 |
{
|
|
118 |
// R0=a, R1=q, R2=v
|
|
119 |
// return value in R0
|
|
120 |
// just fall through
|
|
121 |
}
|
|
122 |
|
|
123 |
extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
|
|
124 |
{
|
|
125 |
// R0=a, R1=q, R2=v
|
|
126 |
// return value in R0
|
|
127 |
// just fall through
|
|
128 |
}
|
|
129 |
|
|
130 |
extern "C" EXPORT_C __NAKED__ TBool __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ * /*q*/, __TYPE__ /*v*/)
|
|
131 |
{
|
|
132 |
// R0=a, R1=q, R2=v
|
|
133 |
// return value in R0
|
|
134 |
asm("bic r12, r0, #3 ");
|
|
135 |
asm("and r3, r0, #3 ");
|
|
136 |
asm("stmfd sp!, {r4-r6} ");
|
|
137 |
asm("movs r4, r3, lsl #3 "); // r4 = bit offset of data in word
|
|
138 |
__LDR_INST__( ," r6, [r1] "); // r6 = expected value
|
|
139 |
#if __DATA_SIZE__==16
|
|
140 |
asm("mov r5, r4 "); // r5 = right rotate to take bottom hword to hword of interest (0->0, 2->16)
|
|
141 |
asm("eor r4, r4, #16 "); // r4 = right rotate to take hword of interest to top (0->16, 2->0)
|
|
142 |
#elif __DATA_SIZE__==8
|
|
143 |
asm("rsb r5, r4, #32 ");
|
|
144 |
asm("and r5, r5, #31 "); // right rotate to take bottom byte to byte of interest (0->0, 1->24, 2->16, 3->8)
|
|
145 |
asm("add r4, r4, #8 ");
|
|
146 |
asm("and r4, r4, #31 "); // right rotate to take byte of interest to top byte (0->8, 1->16, 2->24, 3->0)
|
|
147 |
#endif
|
|
148 |
asm("1: ");
|
|
149 |
LDREX(0,12);
|
|
150 |
asm("mov r0, r0, ror r4 "); // rotate so desired data is at top
|
|
151 |
asm("cmp r6, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__)); // check desired data against expected value *q
|
|
152 |
asm("bne 2f "); // if no match, give up
|
|
153 |
asm("orr r0, r2, r0, lsl #%a0" : : "i" (__DATA_SIZE__)); // substitute value v into bottom bits of r0, replacing original
|
|
154 |
asm("mov r0, r0, ror r5 "); // rotate back (bottom byte/hword goes to byte/hword of interest)
|
|
155 |
STREX(3,0,12);
|
|
156 |
asm("cmp r3, #0 ");
|
|
157 |
asm("bne 1b ");
|
|
158 |
asm("2: ");
|
|
159 |
asm("movne r0, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__)); // shift return value so data is at bottom
|
|
160 |
__STR_INST__(ne, "r0, [r1] "); // update *q with observed value
|
|
161 |
asm("ldmfd sp!, {r4-r6} ");
|
|
162 |
asm("movne r0, #0 "); // if *a not updated return FALSE
|
|
163 |
asm("moveq r0, #1 "); // if *a updated return TRUE
|
|
164 |
__JUMP(,lr);
|
|
165 |
}
|
|
166 |
|
|
167 |
|
|
168 |
#elif defined(__OP_AXO__)
|
|
169 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
170 |
{
|
|
171 |
// R0=a, R1=u, R2=v
|
|
172 |
// return value in R0
|
|
173 |
// just fall through
|
|
174 |
}
|
|
175 |
|
|
176 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
177 |
{
|
|
178 |
// R0=a, R1=u, R2=v
|
|
179 |
// return value in R0
|
|
180 |
// just fall through
|
|
181 |
}
|
|
182 |
|
|
183 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
184 |
{
|
|
185 |
// R0=a, R1=u, R2=v
|
|
186 |
// return value in R0
|
|
187 |
// just fall through
|
|
188 |
}
|
|
189 |
|
|
190 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
191 |
{
|
|
192 |
// R0=a, R1=u, R2=v
|
|
193 |
// return value in R0
|
|
194 |
asm("and r3, r0, #3 ");
|
|
195 |
asm("bic r12, r0, #3 ");
|
|
196 |
asm("stmfd sp!, {r4-r5} ");
|
|
197 |
asm("mvn r1, r1, lsl #%a0" : : "i" (32-__DATA_SIZE__)); // ~u in upper bits of r1, 1's in lower bits
|
|
198 |
asm("movs r4, r3, lsl #3 "); // r4 = bit offset of data in word
|
|
199 |
asm("mov r1, r1, lsr #%a0" : : "i" (32-__DATA_SIZE__)); // ~u in lower bits of r1, zero extended
|
|
200 |
asm("1: ");
|
|
201 |
LDREX(0,12);
|
|
202 |
asm("bic r5, r0, r1, lsl r4 "); // r5 = r0 & u in relevant bit positions, other bit positions unchanged
|
|
203 |
asm("eor r5, r5, r2, lsl r4 ");
|
|
204 |
STREX(3,5,12);
|
|
205 |
asm("cmp r3, #0 ");
|
|
206 |
asm("bne 1b ");
|
|
207 |
asm("mov r0, r0, lsr r4 "); // shift original value so byte/hword of interest is at the bottom
|
|
208 |
asm("ldmfd sp!, {r4-r5} ");
|
|
209 |
#if __DATA_SIZE__==16
|
|
210 |
asm("bic r0, r0, #0xff000000 "); // mask upper 16 bits
|
|
211 |
asm("bic r0, r0, #0x00ff0000 ");
|
|
212 |
#elif __DATA_SIZE__==8
|
|
213 |
asm("and r0, r0, #0xff "); // mask upper 24 bits
|
|
214 |
#endif
|
|
215 |
__JUMP(,lr);
|
|
216 |
}
|
|
217 |
|
|
218 |
|
|
219 |
#elif defined(__OP_RMW3__)
|
|
220 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rel,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
221 |
{
|
|
222 |
// R0=a, R1=t, R2=u, R3=v
|
|
223 |
// return value in R0
|
|
224 |
// just fall through
|
|
225 |
}
|
|
226 |
|
|
227 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,rlx,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
228 |
{
|
|
229 |
// R0=a, R1=t, R2=u, R3=v
|
|
230 |
// return value in R0
|
|
231 |
// just fall through
|
|
232 |
}
|
|
233 |
|
|
234 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,ord,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
235 |
{
|
|
236 |
// R0=a, R1=t, R2=u, R3=v
|
|
237 |
// return value in R0
|
|
238 |
// just fall through
|
|
239 |
}
|
|
240 |
|
|
241 |
extern "C" EXPORT_C __NAKED__ __TYPE__ __fname__(__OPERATION__,acq,__DATA_SIZE__)(volatile TAny* /*a*/, __TYPE__ /*t*/, __TYPE__ /*u*/, __TYPE__ /*v*/)
|
|
242 |
{
|
|
243 |
// R0=a, R1=t, R2=u, R3=v
|
|
244 |
// return value in R0
|
|
245 |
asm("bic r12, r0, #3 ");
|
|
246 |
asm("stmfd sp!, {r4-r7} ");
|
|
247 |
asm("and r4, r0, #3 ");
|
|
248 |
asm("movs r4, r4, lsl #3 "); // r4 = bit offset of data in word
|
|
249 |
#if __DATA_SIZE__==16
|
|
250 |
asm("eor r4, r4, #16 "); // r4 = right rotate to take hword of interest to top (0->16, 2->0)
|
|
251 |
asm("mov r5, r4 "); // r5 = right rotate to undo r4
|
|
252 |
#elif __DATA_SIZE__==8
|
|
253 |
asm("add r4, r4, #8 ");
|
|
254 |
asm("and r4, r4, #31 "); // right rotate to take byte of interest to top byte (0->8, 1->16, 2->24, 3->0)
|
|
255 |
asm("rsb r5, r4, #32 ");
|
|
256 |
asm("and r5, r5, #31 "); // right rotate to take top byte to byte of interest (0->8, 1->16, 2->24, 3->0)
|
|
257 |
#endif
|
|
258 |
asm("1: ");
|
|
259 |
LDREX(0,12);
|
|
260 |
asm("mov r0, r0, ror r4 "); // rotate so desired data is at top
|
|
261 |
#if defined(__OP_TAU__)
|
|
262 |
asm("cmp r1, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__)); // t - byte/hword of interest
|
|
263 |
asm("addls r6, r0, r2, lsl #%a0" : : "i" (32-__DATA_SIZE__)); // if t<=*a add u
|
|
264 |
asm("addhi r6, r0, r3, lsl #%a0" : : "i" (32-__DATA_SIZE__)); // if t>*a add v
|
|
265 |
#elif defined(__OP_TAS__)
|
|
266 |
asm("cmp r1, r0, asr #%a0" : : "i" (32-__DATA_SIZE__)); // t - byte/hword of interest
|
|
267 |
asm("addle r6, r0, r2, lsl #%a0" : : "i" (32-__DATA_SIZE__)); // if t<=*a add u
|
|
268 |
asm("addgt r6, r0, r3, lsl #%a0" : : "i" (32-__DATA_SIZE__)); // if t>*a add v
|
|
269 |
#endif
|
|
270 |
asm("mov r6, r6, ror r5 "); // rotate back
|
|
271 |
STREX(7,6,12);
|
|
272 |
asm("cmp r7, #0 ");
|
|
273 |
asm("bne 1b ");
|
|
274 |
asm("ldmfd sp!, {r4-r7} ");
|
|
275 |
#if defined(__OP_TAU__)
|
|
276 |
asm("mov r0, r0, lsr #%a0" : : "i" (32-__DATA_SIZE__)); // shift return value so data is at bottom
|
|
277 |
#elif defined(__OP_TAS__)
|
|
278 |
asm("mov r0, r0, asr #%a0" : : "i" (32-__DATA_SIZE__)); // shift return value so data is at bottom
|
|
279 |
#endif
|
|
280 |
__JUMP(,lr);
|
|
281 |
}
|
|
282 |
|
|
283 |
#endif
|
|
284 |
|
|
285 |
// Second inclusion undefines temporaries
|
|
286 |
#include "atomic_ops.h"
|