|
1 // Copyright (c) 1995-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\euser\epoc\arm\uc_utl.cia |
|
15 // |
|
16 // |
|
17 |
|
18 #include <e32cia.h> |
|
19 #include <u32std.h> |
|
20 #include <e32base.h> |
|
21 #include <e32rom.h> |
|
22 #include <e32svr.h> |
|
23 #include <e32hashtab.h> |
|
24 #include <u32exec.h> |
|
25 #include "uc_std.h" |
|
26 |
|
27 |
|
28 #if defined(__MEM_MACHINE_CODED__) |
|
29 EXPORT_C __NAKED__ void Mem::Swap(TAny* /*aPtr1*/, TAny* /*aPtr2*/, TInt /*aLength*/) |
|
30 /** |
|
31 Swaps a number of bytes of data between two specified locations. |
|
32 |
|
33 The source and target areas can overlap. |
|
34 |
|
35 @param aPtr1 A pointer to the first location taking part in the swap. |
|
36 @param aPtr2 A pointer to second location taking part in the swap. |
|
37 @param aLength The number of bytes to be swapped between the two locations. |
|
38 This value must not be negative. |
|
39 |
|
40 @panic USER 94 In debug builds only, if aLength is negative. |
|
41 */ |
|
42 { |
|
43 |
|
44 asm(" cmp r0,r1"); |
|
45 asm(" cmpne r2,#0"); |
|
46 __JUMP(eq,lr); |
|
47 // |
|
48 // Test for same alignment, if more than 16 bytes to swap |
|
49 // |
|
50 asm(" and r3,r0,#3"); |
|
51 asm(" and ip,r1,#3"); |
|
52 asm(" cmp r2,#16"); |
|
53 asm(" addlt r3,r3,#4"); |
|
54 asm(" cmp r3,ip"); |
|
55 asm(" beq same_aligned_swap"); |
|
56 |
|
57 asm(" stmfd sp!,{r4,lr}"); |
|
58 |
|
59 asm("swap_loop:"); |
|
60 |
|
61 asm(" ldrb r3,[r0]"); |
|
62 asm(" ldrb r4,[r1]"); |
|
63 asm(" strb r3,[r1],#1"); |
|
64 asm(" strb r4,[r0],#1"); |
|
65 asm(" subs r2,r2,#1"); |
|
66 asm("beq swap_exit1 "); |
|
67 |
|
68 asm(" ldrb r3,[r0]"); |
|
69 asm(" ldrb r4,[r1]"); |
|
70 asm(" strb r3,[r1],#1"); |
|
71 asm(" strb r4,[r0],#1"); |
|
72 asm(" subs r2,r2,#1"); |
|
73 asm("beq swap_exit1 "); |
|
74 |
|
75 asm(" ldrb r3,[r0]"); |
|
76 asm(" ldrb r4,[r1]"); |
|
77 asm(" strb r3,[r1],#1"); |
|
78 asm(" strb r4,[r0],#1"); |
|
79 asm(" subs r2,r2,#1"); |
|
80 asm("beq swap_exit1 "); |
|
81 |
|
82 asm(" ldrb r3,[r0]"); |
|
83 asm(" ldrb r4,[r1]"); |
|
84 asm(" strb r3,[r1],#1"); |
|
85 asm(" strb r4,[r0],#1"); |
|
86 asm(" subs r2,r2,#1"); |
|
87 asm(" bne swap_loop"); |
|
88 asm("swap_exit1: "); |
|
89 __POPRET("r4,"); |
|
90 |
|
91 asm("same_aligned_swap:"); |
|
92 |
|
93 asm(" stmfd sp!,{r4-r10,lr}"); |
|
94 // |
|
95 // r3 contains the byte offset from word alignment, 0,1,2 or 3 |
|
96 // subtract 1 to get -1,0,1 or 2, and if -1 make it 3 |
|
97 // that gives us 0,1,2 or 3 if the alignment is 3,2,1 or 0 respectively |
|
98 // We can use that to jump directly to the appropriate place for |
|
99 // swapping the relevent number of bytes to achieve word alignment |
|
100 // r4 is set to 3-r3 to correct the length for the number of bytes |
|
101 // swapped |
|
102 // |
|
103 asm(" subs r3,r3,#1"); |
|
104 asm(" movmi r3,#3"); |
|
105 asm(" rsb r4,r3,#3"); |
|
106 asm(" sub r2,r2,r4"); |
|
107 asm(" add pc,pc,r3,asl #4"); |
|
108 asm(" nop "); // never executed |
|
109 // |
|
110 // Jumps here if 3 bytes to swap before word aligned |
|
111 // |
|
112 asm(" ldrb r4,[r0]"); |
|
113 asm(" ldrb ip,[r1]"); |
|
114 asm(" strb r4,[r1],#1"); |
|
115 asm(" strb ip,[r0],#1"); |
|
116 // |
|
117 // Jumps here if 2 bytes to swap before word aligned |
|
118 // |
|
119 asm(" ldrb r4,[r0]"); |
|
120 asm(" ldrb ip,[r1]"); |
|
121 asm(" strb r4,[r1],#1"); |
|
122 asm(" strb ip,[r0],#1"); |
|
123 // |
|
124 // Jumps here if 1 byte to swap before word aligned |
|
125 // |
|
126 asm(" ldrb r4,[r0]"); |
|
127 asm(" ldrb ip,[r1]"); |
|
128 asm(" strb r4,[r1],#1"); |
|
129 asm(" strb ip,[r0],#1"); |
|
130 // |
|
131 // We are now word aligned. Fast swapping, here we come... |
|
132 // |
|
133 asm("word_aligned_swap:"); |
|
134 asm(" movs ip,r2,lsr #6"); // Number of 64 blocks to swap |
|
135 asm(" beq its_smaller_swap"); |
|
136 |
|
137 asm("swap_64_bytes:"); |
|
138 asm(" ldmia r1,{r3-r6}"); |
|
139 asm(" ldmia r0,{r7-r10}"); |
|
140 asm(" stmia r1!,{r7-r10}"); |
|
141 asm(" stmia r0!,{r3-r6}"); |
|
142 asm(" ldmia r1,{r3-r6}"); |
|
143 asm(" ldmia r0,{r7-r10}"); |
|
144 asm(" stmia r1!,{r7-r10}"); |
|
145 asm(" stmia r0!,{r3-r6}"); |
|
146 asm(" ldmia r1,{r3-r6}"); |
|
147 asm(" ldmia r0,{r7-r10}"); |
|
148 asm(" stmia r1!,{r7-r10}"); |
|
149 asm(" stmia r0!,{r3-r6}"); |
|
150 asm(" ldmia r1,{r3-r6}"); |
|
151 asm(" ldmia r0,{r7-r10}"); |
|
152 asm(" stmia r1!,{r7-r10}"); |
|
153 asm(" stmia r0!,{r3-r6}"); |
|
154 asm(" subs ip,ip,#1"); |
|
155 asm(" bne swap_64_bytes"); |
|
156 // |
|
157 // Less than 64 bytes to go... |
|
158 // |
|
159 asm("its_smaller_swap:"); |
|
160 asm(" ands r2,r2,#63"); |
|
161 asm("beq swap_exit2 "); |
|
162 asm(" cmp r2,#4"); |
|
163 asm(" blt finish_swap"); |
|
164 asm("final_swap_loop:"); |
|
165 asm(" ldr r3,[r1]"); |
|
166 asm(" ldr ip,[r0]"); |
|
167 asm(" str r3,[r0],#4"); |
|
168 asm(" str ip,[r1],#4"); |
|
169 asm(" subs r2,r2,#4"); |
|
170 asm(" cmp r2,#4"); |
|
171 asm(" bge final_swap_loop"); |
|
172 // |
|
173 // Less than 4 bytes to go... |
|
174 // |
|
175 asm("finish_swap:"); |
|
176 asm(" tst r2,#2"); |
|
177 asm(" ldrneb r3,[r0]"); |
|
178 asm(" ldrneb ip,[r1]"); |
|
179 asm(" strneb r3,[r1],#1"); |
|
180 asm(" strneb ip,[r0],#1"); |
|
181 asm(" ldrneb r3,[r0]"); |
|
182 asm(" ldrneb ip,[r1]"); |
|
183 asm(" strneb r3,[r1],#1"); |
|
184 asm(" strneb ip,[r0],#1"); |
|
185 |
|
186 asm(" tst r2,#1"); |
|
187 asm(" ldrneb r3,[r0]"); |
|
188 asm(" ldrneb ip,[r1]"); |
|
189 asm(" strneb r3,[r1],#1"); |
|
190 asm(" strneb ip,[r0],#1"); |
|
191 |
|
192 asm("swap_exit2: "); |
|
193 __POPRET("r4-r10,"); |
|
194 } |
|
195 #endif |
|
196 |
|
197 #ifdef __REGIONS_MACHINE_CODED__ |
|
198 |
|
199 __NAKED__ GLDEF_C void AllocAnotherRect( TRegion * /*aRegion*/ ) |
|
200 { |
|
201 // Returns with Z flag set to indicate error |
|
202 |
|
203 asm("ldr r1, [r0, #4] "); // r1=iError |
|
204 asm("cmp r1, #0 "); |
|
205 asm("bne return_error "); |
|
206 asm("ldr r1, [r0, #8] "); // r1=iAllocedRects |
|
207 asm("ldr r12, [r0] "); // r12=iCount |
|
208 asm("tst r1, #0x40000000 "); // test ERRegionBuf |
|
209 asm("beq allocanother1 "); // don't branch if TRegionFix |
|
210 asm("cmn r1, r12 "); // test if iCount==-iAllocedRects |
|
211 __JUMP(ne,lr); |
|
212 asm("b " CSM_ZN7TRegion10ForceErrorEv); // if so, ForceError() |
|
213 asm("allocanother1: "); |
|
214 asm("cmp r1, #0 "); |
|
215 asm("bpl allocanother3 "); // branch if RRegion, continue if RRegionBuf |
|
216 asm("orr r2, r1, #0x40000000 "); // r2=iAllocedRects|ERRegionBuf |
|
217 asm("cmn r2, r12 "); // check if iCount==(-(iAllocedRects|ERRegionBuf)) |
|
218 __JUMP(ne,lr); |
|
219 asm("ldr r2, [r0, #12] "); // r2=iGranularity |
|
220 asm("add r1, r12, r2 "); // iAllocedRects=iCount+iGranularity - change into RRegion |
|
221 asm("str r1, [r0, #8] "); |
|
222 asm("stmfd sp!, {r0,r1,r12,lr} "); // save registers used in function call |
|
223 asm("mov r0, r1, lsl #4 "); // number of bytes to allocate |
|
224 asm("bl " CSM_ZN4User5AllocEi); // User::Alloc |
|
225 asm("movs r2, r0 "); // returned pointer into r2 |
|
226 asm("ldmfd sp!, {r0,r1,r12,lr} "); // restore registers |
|
227 asm("add r3, r0, #20 "); // r3=address of first rectangle |
|
228 asm("str r2, [r0, #16] "); // iRectangleList=returned pointer |
|
229 asm("beq " CSM_ZN7TRegion10ForceErrorEv); // if pointer null, ForceError() |
|
230 asm("cmp r12, #0 "); |
|
231 asm("beq return_success "); |
|
232 asm("stmfd sp!, {r4,r5} "); |
|
233 asm("allocanother2: "); |
|
234 asm("ldmia r3!, {r0,r1,r4,r5} "); // copy data to new area |
|
235 asm("subs r12, r12, #1 "); |
|
236 asm("stmia r2!, {r0,r1,r4,r5} "); |
|
237 asm("bne allocanother2 "); |
|
238 asm("ldmfd sp!, {r4,r5} "); |
|
239 asm("return_success: "); |
|
240 asm("movs r0, #1 "); // clear Z flag to indicate success |
|
241 __JUMP(,lr); |
|
242 asm("allocanother3: "); // come here if RRegion |
|
243 asm("cmp r1, r12 "); // check if iCount==iAllocedRects |
|
244 __JUMP(ne,lr); |
|
245 asm("ldr r2, [r0, #12] "); // r2 = iGranularity |
|
246 asm("add r1, r1, r2 "); // iAllocedRects+=iGranularity |
|
247 asm("str r1, [r0, #8] "); |
|
248 asm("stmfd sp!, {r0,lr} "); // preserve r0,lr across function call |
|
249 asm("ldr r0, [r0, #16] "); // r0=address of current cell |
|
250 asm("mov r1, r1, lsl #4 "); // r1=number of bytes to allocate |
|
251 asm("mov r2, #0 "); |
|
252 asm("bl " CSM_ZN4User7ReAllocEPvii); // User::ReAlloc |
|
253 asm("movs r2, r0 "); // returned pointer into r2 |
|
254 asm("ldmfd sp!, {r0,lr} "); // restore r0,lr |
|
255 asm("strne r2, [r0, #16] "); // if returned ptr not null, iRectangleList=returned ptr |
|
256 __JUMP(ne,lr); |
|
257 asm("b " CSM_ZN7TRegion10ForceErrorEv); // else ForceError() |
|
258 } |
|
259 |
|
260 |
|
261 __NAKED__ EXPORT_C void TRegion::ForceError() |
|
262 { |
|
263 // Returns with Z flag set to indicate error |
|
264 |
|
265 asm("stmfd sp!, {r0,lr} "); |
|
266 asm("bl " CSM_ZN7TRegion5ClearEv); // Clear() |
|
267 asm("ldmfd sp!, {r0,lr} "); // restore r0,lr |
|
268 asm("mov r1, #1 "); |
|
269 asm("str r1, [r0, #4] "); // iError=ETrue |
|
270 asm("return_error: "); |
|
271 asm("movs r0, #0 "); // set Z flag to indicate error |
|
272 __JUMP(,lr); |
|
273 } |
|
274 |
|
275 |
|
276 |
|
277 __NAKED__ EXPORT_C TRect TRegion::BoundingRect() const |
|
278 /** |
|
279 Gets the minimal rectangle that bounds the entire region. |
|
280 |
|
281 @return The region's minimal bounding rectangle. |
|
282 */ |
|
283 { |
|
284 asm("ldr r2, [r1] "); // r2=iCount |
|
285 asm("cmp r2, #0 "); // list empty? |
|
286 asm("beq boundingrect0 "); // branch if empty |
|
287 asm("ldr r3, [r1, #8] "); // if not empty, r3 points to first rectangle |
|
288 asm("stmfd sp!, {r4-r8,lr} "); |
|
289 asm("cmn r3, r3 "); |
|
290 asm("ldrcc r3, [r1, #16] "); // if RRegion |
|
291 asm("addcs r3, r1, #20 "); // RRegionBuf |
|
292 asm("submi r3, r3, #8 "); // TRegionFix |
|
293 asm("ldmia r3!, {r4-r7} "); // if not empty bounds = first rectangle |
|
294 asm("b boundingrect2 "); // if not empty go and check rest of list |
|
295 asm("boundingrect1: "); |
|
296 asm("ldmia r3!, {r1,r8,r12,lr} "); // fetch next rectangle |
|
297 asm("cmp r1, r4 "); // if next.iTl.iX<bounds.iTl.iX |
|
298 asm("movlt r4, r1 "); // bounds.iTl.iX=next.iTl.iX |
|
299 asm("cmp r8, r5 "); // if next.iTl.iY<bounds.iTl.iY |
|
300 asm("movlt r5, r8 "); // bounds.iTl.iY=next.iTl.iY |
|
301 asm("cmp r12, r6 "); // if next.iBr.iX>bounds.iBr.iX |
|
302 asm("movgt r6, r12 "); // bounds.iBr.iX=next.iBr.iX |
|
303 asm("cmp lr, r7 "); // if next.iBr.iY>bounds.iBr.iY |
|
304 asm("movgt r7, lr "); // bounds.iBr.iY=next.iBr.iY |
|
305 asm("boundingrect2: "); |
|
306 asm("subs r2, r2, #1 "); // decrement count |
|
307 asm("bne boundingrect1 "); // repeat for all rectangles |
|
308 asm("stmia r0, {r4-r7} "); // store result |
|
309 __POPRET("r4-r8,"); |
|
310 |
|
311 asm("boundingrect0: "); |
|
312 asm("mov r1, #0 "); // if list empty, bounds = 0,0,0,0 |
|
313 asm("mov r3, #0 "); |
|
314 asm("mov r12, #0 "); |
|
315 asm("stmia r0, {r1,r2,r3,r12} "); // store result |
|
316 __JUMP(,lr); |
|
317 } |
|
318 |
|
319 |
|
320 |
|
321 |
|
322 __NAKED__ EXPORT_C TBool TRegion::IsContainedBy(const TRect & /*aRect*/) const |
|
323 /** |
|
324 Tests whether the region is fully enclosed within the specified rectangle. |
|
325 |
|
326 @param aRect The specified rectangle. |
|
327 |
|
328 @return True, if the region is fully enclosed within the rectangle (their sides |
|
329 may touch); false, otherwise. |
|
330 */ |
|
331 { |
|
332 asm("ldr r12, [r0, #8] "); // r12 points to first rectangle |
|
333 asm("stmfd sp!, {r4-r7,lr} "); |
|
334 asm("cmn r12, r12 "); |
|
335 asm("ldrcc r12, [r0, #16] "); // if RRegion |
|
336 asm("addcs r12, r0, #20 "); // RRegionBuf |
|
337 asm("submi r12, r12, #8 "); // TRegionFix |
|
338 |
|
339 asm("ldr r0, [r0] "); // r0=iCount |
|
340 asm("ldmia r1, {r4-r7} "); // aRect coordinates into r4-r7 |
|
341 |
|
342 asm("subs r0, r0, #1 "); // decrement it |
|
343 asm("bmi iscontainedby2 "); // if iCount was zero, return TRUE |
|
344 |
|
345 asm("iscontainedby1: "); |
|
346 asm("ldmia r12!, {r1,r2,r3,lr} "); // coordinates of next rectangle |
|
347 asm("cmp r1, r4 "); // compare next.iTl.iX with aRect.iTl.iX |
|
348 asm("cmpge r2, r5 "); // if >=, compare next.iTl.iY with aRect.iTl.iY |
|
349 asm("cmpge r6, r3 "); // if >=, compare aRect.Br.iX with next.iBr.iX |
|
350 asm("cmpge r7, lr "); // if >=, compare aRect.Br.iY with next.iBr.iY |
|
351 asm("subges r0, r0, #1 "); // if >=, next is contained in aRect, so iterate |
|
352 asm("bge iscontainedby1 "); // will drop through if r0<0 or if next exceeds aRect |
|
353 asm("iscontainedby2: "); |
|
354 asm("mov r0, r0, lsr #31 "); // return 1 if r0<0, 0 if r0>=0 |
|
355 __POPRET("r4-r7,"); |
|
356 } |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 __NAKED__ EXPORT_C void TRegion::Copy(const TRegion & /*aRegion*/) |
|
362 /** |
|
363 Copies another region to this region. |
|
364 |
|
365 The state of the specified region's error flag is also copied. |
|
366 |
|
367 @param aRegion The region to be copied. |
|
368 */ |
|
369 { |
|
370 asm("ldr r2, [r1, #4] "); // r2 = aRegion.iError |
|
371 asm("cmp r2, #0 "); |
|
372 asm("bne " CSM_ZN7TRegion10ForceErrorEv); // if (aRegion.iError) ForceError(); |
|
373 asm("ldr r2, [r1] "); // r1 = aRegion.iCount |
|
374 asm("cmp r2, #0 "); |
|
375 asm("beq " CSM_ZN7TRegion5ClearEv); // region to copy is empty so simply clear our buffer |
|
376 asm("stmfd sp!, {r0,r1,r4,r5,r6,lr} "); // preserve r0,r1,lr across function calls |
|
377 asm("mov r4, r1 "); |
|
378 asm("mov r5, r0 "); |
|
379 asm("ldr r2, [r0, #4] "); // r2 = iError |
|
380 asm("cmp r2, #0 "); |
|
381 asm("blne " CSM_ZN7TRegion5ClearEv); // if (iError) Clear(); |
|
382 asm("mov r0, r5 "); |
|
383 asm("ldr r1, [r4] "); // r1 = aRegion.iCount, r0 = this |
|
384 asm("bl " CSM_ZN7TRegion11SetListSizeEi); // SetListSize(aRegion.iCount); |
|
385 asm("cmp r0, #0 "); |
|
386 asm("beq copyregion_end "); |
|
387 asm("ldr r3, [r4] "); // r3 = aRegion.iCount |
|
388 asm("cmp r3, #0 "); |
|
389 asm("str r3, [r5] "); // iCount=aRegion.iCount |
|
390 asm("beq copyregion_end "); |
|
391 asm("ldr r0, [r5, #8] "); // r0 points to first rectangle |
|
392 asm("cmn r0, r0 "); |
|
393 asm("ldrcc r0, [r5, #16] "); // if RRegion |
|
394 asm("addcs r0, r5, #20 "); // RRegionBuf |
|
395 asm("submi r0, r0, #8 "); // TRegionFix |
|
396 asm("ldr r1, [r4, #8] "); // r1 points to first rectangle |
|
397 asm("cmn r1, r1 "); |
|
398 asm("ldrcc r1, [r4, #16] "); // if RRegion |
|
399 asm("addcs r1, r4, #20 "); // RRegionBuf |
|
400 asm("submi r1, r1, #8 "); // TRegionFix |
|
401 asm("copyregion1: "); |
|
402 asm("ldmia r1!, {r2,r4,r5,r12} "); // copy aRegion.iRectangleList to iRectangleList |
|
403 asm("subs r3, r3, #1 "); |
|
404 asm("stmia r0!, {r2,r4,r5,r12} "); |
|
405 asm("bne copyregion1 "); |
|
406 |
|
407 asm("copyregion_end: "); |
|
408 __POPRET("r0,r1,r4,r5,r6,"); |
|
409 } |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 __NAKED__ EXPORT_C void TRegion::Offset(const TPoint & /*anOffset*/) |
|
415 /** |
|
416 Moves the region by adding a TPoint offset to the co-ordinates of its corners. |
|
417 |
|
418 The size of the region is not changed. |
|
419 |
|
420 @param aOffset The offset by which the region is moved. The region is moved |
|
421 horizontally by aOffset.iX pixels and vertically by aOffset.iY pixels. |
|
422 */ |
|
423 { |
|
424 asm("ldmia r1, {r1,r2} "); // r1=anOffset.iX, r2=anOffset.iY |
|
425 // fall through... |
|
426 } |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 __NAKED__ EXPORT_C void TRegion::Offset(TInt /*xOffset*/,TInt /*yOffset*/) |
|
432 /** |
|
433 Moves the region by adding X and Y offsets to the co-ordinates of its corners. |
|
434 |
|
435 The size of the region is not changed. |
|
436 |
|
437 @param aXoffset The number of pixels by which to move the region horizontally. |
|
438 If negative, the region moves leftwards. |
|
439 @param aYoffset The number of pixels by which to move the region vertically. |
|
440 If negative, the region moves upwards. |
|
441 */ |
|
442 { |
|
443 asm("ldr r12, [r0] "); // r12=iCount |
|
444 asm("cmp r12, #0 "); |
|
445 __JUMP(eq,lr); |
|
446 asm("ldr r3, [r0, #8] "); // r0 points to first rectangle |
|
447 asm("cmn r3, r3 "); |
|
448 asm("ldrcc r0, [r0, #16] "); // if RRegion |
|
449 asm("addcs r0, r0, #20 "); // RRegionBuf |
|
450 asm("submi r0, r0, #8 "); // TRegionFix |
|
451 asm("stmfd sp!, {r4,r5,lr} "); |
|
452 asm("offsetregion2: "); |
|
453 asm("ldmia r0, {r3-r5,lr} "); // r3-r5,lr = next rectangle coordinates |
|
454 asm("subs r12, r12, #1 "); |
|
455 asm("add r3, r3, r1 "); // Tl.iX += anOffset.iX |
|
456 asm("add r4, r4, r2 "); // Tl.iY += anOffset.iY |
|
457 asm("add r5, r5, r1 "); // Br.iX += anOffset.iX |
|
458 asm("add lr, lr, r2 "); // Br.iY += anOffset.iY |
|
459 asm("stmia r0!, {r3-r5,lr} "); // store new coordinates |
|
460 asm("bne offsetregion2 "); |
|
461 __POPRET("r4,r5,"); |
|
462 } |
|
463 |
|
464 |
|
465 |
|
466 |
|
467 __NAKED__ EXPORT_C TBool TRegion::Contains(const TPoint & /*aPoint*/) const |
|
468 /** |
|
469 Tests whether a point is located within the region. |
|
470 |
|
471 If the point is located on the top or left hand side of any rectangle in the |
|
472 region, it is considered to be within that rectangle and within the region. |
|
473 |
|
474 If the point is located on the right hand side or bottom of a rectangle, it |
|
475 is considered to be outside that rectangle, and may be outside the region. |
|
476 |
|
477 @param aPoint The specified point. |
|
478 |
|
479 @return True, if the point is within the region; false, otherwise. |
|
480 */ |
|
481 { |
|
482 asm("ldr r12, [r0] "); // r12 = iCount |
|
483 asm("stmfd sp!, {r4,r5,lr} "); |
|
484 asm("cmp r12, #0 "); |
|
485 asm("beq contains0 "); // if iCount=0, return FALSE |
|
486 asm("ldr r3, [r0, #8] "); // r0 points to first rectangle |
|
487 asm("cmn r3, r3 "); |
|
488 asm("ldrcc r0, [r0, #16] "); // if RRegion |
|
489 asm("addcs r0, r0, #20 "); // RRegionBuf |
|
490 asm("submi r0, r0, #8 "); // TRegionFix |
|
491 asm("ldmia r1, {r1, r2} "); // r1=aPoint.iX, r2=aPoint.iY |
|
492 asm("contains1: "); |
|
493 asm("ldmia r0!, {r3-r5,lr} "); // coordinates of next rectangle into r3-r5,lr |
|
494 asm("cmp r3, r1 "); // compare next.iTl.iX with aPoint.iX |
|
495 asm("cmple r4, r2 "); // if <=, compare next.iTl.iY with aPoint.iY |
|
496 asm("bgt contains2 "); // if >, aPoint is not contained in rectangle, so iterate |
|
497 asm("cmp r1, r5 "); // compare aPoint.iX with next.iBr.iX |
|
498 asm("cmplt r2, lr "); // if <, compare aPoint.iY with next.iBr.iY |
|
499 asm("contains2: "); |
|
500 asm("subges r12, r12, #1 "); // if >=, aPoint is not contained in rect, so iterate |
|
501 asm("bgt contains1 "); |
|
502 asm("cmp r12, #0 "); |
|
503 asm("movne r0, #1 "); // if r12 non-zero, return TRUE else FALSE |
|
504 asm("contains0: "); |
|
505 asm("moveq r0, #0 "); |
|
506 __POPRET("r4,r5,"); |
|
507 } |
|
508 |
|
509 |
|
510 |
|
511 |
|
512 __NAKED__ EXPORT_C TBool TRegion::Intersects(const TRect &/*aRect*/) const |
|
513 /** |
|
514 Tests whether where there is any intersection between this region and the specified rectangle. |
|
515 |
|
516 @param aRect The specified rectangle. |
|
517 |
|
518 @return True, if there is an intersection; false, otherwise. |
|
519 */ |
|
520 { |
|
521 asm("ldr r12, [r0] "); // r12 = iCount |
|
522 asm("stmfd sp!, {r4-r7,lr} "); |
|
523 asm("cmp r12, #0 "); |
|
524 asm("beq intersects0 "); // if iCount=0, return FALSE |
|
525 asm("ldr lr, [r0, #8] "); // r0 points to first rectangle |
|
526 asm("ldmia r1, {r1-r4} "); // (load aRect into r1 - r4) |
|
527 asm("cmn lr, lr "); |
|
528 asm("ldrcc r0, [r0, #16] "); // if RRegion |
|
529 asm("addcs r0, r0, #20 "); // RRegionBuf |
|
530 asm("submi r0, r0, #8 "); // TRegionFix |
|
531 asm("cmp r1, r3 "); // check if aRect is empty |
|
532 asm("cmplt r2, r4 "); |
|
533 asm("bge intersects0 "); |
|
534 |
|
535 asm("intersects1: "); |
|
536 asm("ldmia r0!, {r5-r7,lr} "); // coordinates of next rectangle into r5-r7,lr |
|
537 asm("cmp r1, r7 "); // check if they intersect |
|
538 asm("cmplt r2, lr "); |
|
539 asm("cmplt r5, r3 "); |
|
540 asm("cmplt r6, r4 "); |
|
541 asm("subges r12, r12, #1 "); // if not then decrement and loop |
|
542 asm("bgt intersects1 "); |
|
543 |
|
544 asm("intersects0: "); |
|
545 asm("movge r0, #0 "); |
|
546 asm("movlt r0, #1 "); |
|
547 __POPRET("r4-r7,"); |
|
548 } |
|
549 |
|
550 |
|
551 |
|
552 |
|
553 __NAKED__ void TRegion::DeleteRect(TRect * /*aRect*/) |
|
554 // |
|
555 // Delete a specific rectangle in the list. |
|
556 // |
|
557 { |
|
558 asm("ldr r12, [r0] "); // r12=iCount |
|
559 asm("ldr r3, [r0, #8] "); // r0 points to first rectangle |
|
560 asm("subs r12, r12, #1 "); // decrement it |
|
561 asm("str r12, [r0] "); // iCount--; |
|
562 asm("cmn r3, r3 "); |
|
563 asm("ldrcc r0, [r0, #16] "); // if RRegion |
|
564 asm("addcs r0, r0, #20 "); // RRegionBuf |
|
565 asm("submi r0, r0, #8 "); // TRegionFix |
|
566 asm("sub r2, r1, r0 "); // r2=offset of aRect from iRectangleList |
|
567 asm("subs r12, r12, r2, lsr #4 "); // r12 now equals number of rectangles requiring moving |
|
568 __JUMP(eq,lr); |
|
569 asm("add r0, r1, #16 "); // r0 = aRect+1 |
|
570 asm("stmfd sp!, {r4,lr} "); |
|
571 asm("deleterect1: "); |
|
572 asm("ldmia r0!, {r2-r4,lr} "); // move rectangles following aRect back by one place |
|
573 asm("subs r12, r12, #1 "); |
|
574 asm("stmia r1!, {r2-r4,lr} "); |
|
575 asm("bne deleterect1 "); |
|
576 __POPRET("r4,"); |
|
577 } |
|
578 |
|
579 |
|
580 |
|
581 |
|
582 __NAKED__ EXPORT_C void TRegion::ClipRect(const TRect & /*aRect*/) |
|
583 /** |
|
584 Clips the region to the specified rectangle. |
|
585 |
|
586 The resulting region is the area of overlap between the region and the rectangle. |
|
587 If there is no overlap, all rectangles within this region are deleted and |
|
588 the resulting region is empty. |
|
589 |
|
590 @param aRect The rectangle to which this region is to be clipped. |
|
591 */ |
|
592 // Can not fail. |
|
593 { |
|
594 asm("ldr r12, [r0] "); // r12=iCount |
|
595 asm("cmp r12, #0 "); |
|
596 __JUMP(eq,lr); |
|
597 asm("stmfd sp!, {r4-r10,lr} "); |
|
598 asm("ldmia r1, {r2-r5} "); // get coordinates of aRect into r2-r5 |
|
599 asm("ldr r1, [r0, #8] "); // r1 points to first rectangle |
|
600 asm("cmn r1, r1 "); |
|
601 asm("ldrcc r1, [r0, #16] "); // if RRegion |
|
602 asm("addcs r1, r0, #20 "); // RRegionBuf |
|
603 asm("submi r1, r1, #8 "); // TRegionFix |
|
604 |
|
605 asm("cliprect1: "); |
|
606 asm("ldmia r1!, {r6-r9} "); // next rectangle coordinates into r6-r9 |
|
607 asm("cmp r6, r2 "); // clip the rectangle to aRect |
|
608 asm("movlt r6, r2 "); |
|
609 asm("strlt r2, [r1, #-16] "); |
|
610 asm("cmp r7, r3 "); |
|
611 asm("movlt r7, r3 "); |
|
612 asm("strlt r3, [r1, #-12] "); |
|
613 asm("cmp r8, r4 "); |
|
614 asm("movgt r8, r4 "); |
|
615 asm("strgt r4, [r1, #-8] "); |
|
616 asm("cmp r9, r5 "); |
|
617 asm("movgt r9, r5 "); |
|
618 asm("strgt r5, [r1, #-4] "); |
|
619 asm("cmp r6, r8 "); // check if clipped rect is empty |
|
620 asm("cmplt r7, r9 "); // empty if r6>=r8 or r7>=r9 |
|
621 asm("bge cliprect_delete "); // if empty, branch to other loop to delete rect |
|
622 asm("subs r12, r12, #1 "); // decrement loop counter |
|
623 asm("bne cliprect1 "); // loop if any more rectangles to do |
|
624 __POPRET("r4-r10,"); |
|
625 |
|
626 asm("cliprect_delete: "); // (enter loop here) |
|
627 asm("ldr lr, [r0] "); // lr=iCount, updateed if we delete rects |
|
628 asm("sub r10, r1, #16 "); // r1 -> next rect, r10 -> previous deleted rect |
|
629 asm("subs r12, r12, #1 "); // decrement loop counter |
|
630 asm("beq cliprect_move_end "); |
|
631 asm("cliprect_move: "); |
|
632 asm("ldmia r1!, {r6-r9} "); // next rectangle coordinates into r6-r9 |
|
633 asm("cmp r6, r2 "); // clip the rectangle to aRect |
|
634 asm("movlt r6, r2 "); |
|
635 asm("cmp r7, r3 "); |
|
636 asm("movlt r7, r3 "); |
|
637 asm("cmp r8, r4 "); |
|
638 asm("movgt r8, r4 "); |
|
639 asm("cmp r9, r5 "); |
|
640 asm("movgt r9, r5 "); |
|
641 asm("cmp r6, r8 "); // check if clipped rect is empty |
|
642 asm("cmplt r7, r9 "); // empty if r6>=r8 or r7>=r9 |
|
643 asm("stmltia r10!, {r6-r9} "); // if non-empty then store the rect |
|
644 asm("subge lr, lr, #1 "); // else decrement rect count |
|
645 asm("subs r12, r12, #1 "); // decrement loop counter |
|
646 asm("bne cliprect_move "); // loop if any more rectangles to do |
|
647 asm("cliprect_move_end: "); |
|
648 asm("sub lr, lr, #1 "); // decrement count for first deleted rect |
|
649 asm("str lr, [r0] "); // store updated iCount |
|
650 __POPRET("r4-r10,"); |
|
651 } |
|
652 |
|
653 |
|
654 |
|
655 |
|
656 __NAKED__ EXPORT_C void TRegion::SubRect(const TRect& /*aRect*/,TRegion* /*aSubtractedRegion*/) |
|
657 /** |
|
658 Removes a rectangle from this region. |
|
659 |
|
660 If there is no intersection between the rectangle and this region, then this |
|
661 region is unaffected. |
|
662 |
|
663 @param aRect The rectangular area to be removed from this region. |
|
664 @param aSubtractedRegion A pointer to a region. If this is supplied, the |
|
665 removed rectangle is added to it. By default this |
|
666 pointer is NULL. |
|
667 */ |
|
668 { |
|
669 asm("ldr r12, [r0] "); // r12=iCount=limit |
|
670 asm("cmp r12, #0 "); |
|
671 __JUMP(eq,lr); |
|
672 asm("stmfd sp!, {r3-r11,lr} "); |
|
673 asm("ldmia r1, {r4-r7} "); // r4-r7 = coordinates of aRect |
|
674 asm("cmp r4, r6 "); // check if aRect is empty i.e. (r4>=r6 || r5>=r7) |
|
675 asm("cmplt r5, r7 "); |
|
676 asm("bge subrect_end "); // if aRect is empty nothing to do |
|
677 |
|
678 asm("mov r3, #0 "); // r3=index |
|
679 asm("subrect1: "); |
|
680 asm("ldr lr, [r0, #8] "); // lr points to first rectangle |
|
681 asm("cmn lr, lr "); |
|
682 asm("ldrcc lr, [r0, #16] "); // if RRegion |
|
683 asm("addcs lr, r0, #20 "); // RRegionBuf |
|
684 asm("submi lr, lr, #8 "); // TRegionFix |
|
685 asm("add lr, lr, r3, lsl #4 "); // lr=iRectangleList+index |
|
686 // asm("ldmia r1, {r4-r7} "); // r4-r7 = coordinates of aRect |
|
687 asm("ldmia lr, {r8-r11} "); // r8-r11 = coordinates of next rectangle in region |
|
688 asm("cmp r10, r4 "); // compare next.iBr.iX with aRect.iTl.iX |
|
689 asm("cmpgt r11, r5 "); // if >, compare next.iBr.iY with aRect.iTl.iY |
|
690 asm("cmpgt r6, r8 "); // if >, compare aRect.iBr.iX with next.iTl.iX |
|
691 asm("cmpgt r7, r9 "); // if >, compare aRect.iBr.iY with next.iTl.iY |
|
692 asm("addle r3, r3, #1 "); // if empty intersection, increment index |
|
693 asm("ble subrect2 "); // if <=, next and aRect have empty intersection, so skip |
|
694 asm("add r4, lr, #16 "); // r4 = source pointer for copy, lr = dest |
|
695 asm("ldr r5, [r0] "); // r5 = iCount |
|
696 asm("sub r5, r5, #1 "); // decrement iCount |
|
697 asm("str r5, [r0] "); |
|
698 asm("sub r12, r12, #1 "); // decrement limit |
|
699 asm("subs r5, r5, r3 "); // loop count for copy = iCount-index |
|
700 asm("beq subrect4 "); // if loop count zero, skip the copy |
|
701 asm("stmfd sp!, {r8,r9} "); // preserve r8,r9 |
|
702 asm("subrect3: "); |
|
703 asm("ldmia r4!, {r6-r9} "); // remove the current rectangle |
|
704 asm("stmia lr!, {r6-r9} "); |
|
705 asm("subs r5, r5, #1 "); |
|
706 asm("bne subrect3 "); |
|
707 asm("ldmfd sp!, {r8-r9} "); // restore r8,r9 |
|
708 asm("subrect4: "); |
|
709 asm("ldmia r1, {r4-r7} "); // restore coordinates of aRect into r4-r7 |
|
710 asm("cmp r7, r11 "); // compare aRect.iBr.iY with rect.iBr.iY |
|
711 asm("movgt r7, r11 "); // r7=inter.iBr.iY |
|
712 asm("bllt subrectapp1 "); // if <, append 1st subrectangle |
|
713 asm("cmp r5, r9 "); // compare aRect.iTl.iY with rect.iTl.iY |
|
714 asm("movlt r5, r9 "); // r5=inter.iTl.iY |
|
715 asm("blgt subrectapp2 "); // if >, append 2nd subrectangle |
|
716 asm("cmp r6, r10 "); // compare aRect.iBr.iX with rect.iBr.iX |
|
717 asm("movgt r6, r10 "); // r6=inter.iBr.iX |
|
718 asm("bllt subrectapp3 "); // if <, append 3rd subrectangle |
|
719 asm("cmp r4, r8 "); // compare aRect.iTl.iX with rect.iTl.iX |
|
720 asm("movlt r4, r8 "); // r4=inter.iTl.iX |
|
721 asm("blgt subrectapp4 "); // if >, append 4th subrectangle |
|
722 asm("ldr lr, [r0, #4] "); // lr=iError |
|
723 asm("cmp lr, #0 "); // check for an error |
|
724 asm("bne subrect_end "); |
|
725 asm("cmp r2, #0 "); // check if aSubtractedRegion!=NULL |
|
726 asm("blne subrectadd "); // if non-null, add inter to aSubtractedRegion |
|
727 asm("subrect2: "); |
|
728 asm("cmp r3, r12 "); // compare index to limit |
|
729 asm("ldmltia r1, {r4-r7} "); // if index<limit, r4-r7 = coordinates of aRect |
|
730 asm("blt subrect1 "); // if index<limit, loop again |
|
731 |
|
732 asm("subrect_end: "); |
|
733 __POPRET("r3-r11,"); |
|
734 |
|
735 // AppendRect(TRect(rect.iTl.iX,inter.iBr.iY,rect.iBr.iX,rect.iBr.iY)) |
|
736 asm("subrectapp1: "); |
|
737 asm("stmfd sp!, {r0-r3,r12,lr} "); // preserve registers across function call |
|
738 asm("bl " CSM_Z16AllocAnotherRectP7TRegion); |
|
739 asm("ldmfd sp!, {r0-r3} "); |
|
740 asm("beq subrectapp1_end "); // exit if error |
|
741 |
|
742 asm("ldr r12, [r0] "); // r12=iCount |
|
743 asm("ldr lr, [r0, #8] "); // lr points to first rectangle |
|
744 asm("cmn lr, lr "); |
|
745 asm("ldrcc lr, [r0, #16] "); // if RRegion |
|
746 asm("addcs lr, r0, #20 "); // RRegionBuf |
|
747 asm("submi lr, lr, #8 "); // TRegionFix |
|
748 asm("add lr, lr, r12, lsl #4 "); // lr=&(iRectangleList[iCount]) |
|
749 asm("add r12, r12, #1 "); // increment iCount |
|
750 asm("str r12, [r0] "); // |
|
751 asm("stmia lr!, {r8} "); // append rectangle - rect.iTl.iX |
|
752 asm("stmia lr!, {r7,r10,r11} "); // inter.iBr.iY, rect.iBr.iX, rect.iBr.iY |
|
753 asm("subrectapp1_end: "); |
|
754 __POPRET("r12,"); |
|
755 |
|
756 // AppendRect(TRect(rect.iTl.iX,rect.iTl.iY,rect.iBr.iX,inter.iTl.iY)) |
|
757 asm("subrectapp2: "); |
|
758 asm("stmfd sp!, {r0-r3,r12,lr} "); // preserve registers across function call |
|
759 asm("bl " CSM_Z16AllocAnotherRectP7TRegion); |
|
760 asm("ldmfd sp!, {r0-r3} "); |
|
761 asm("beq subrectapp1_end "); // exit if error |
|
762 |
|
763 asm("ldr r12, [r0] "); // r12=iCount |
|
764 asm("ldr lr, [r0, #8] "); // lr points to first rectangle |
|
765 asm("cmn lr, lr "); |
|
766 asm("ldrcc lr, [r0, #16] "); // if RRegion |
|
767 asm("addcs lr, r0, #20 "); // RRegionBuf |
|
768 asm("submi lr, lr, #8 "); // TRegionFix |
|
769 asm("add lr, lr, r12, lsl #4 "); // lr=&(iRectangleList[iCount]) |
|
770 asm("add r12, r12, #1 "); // increment iCount |
|
771 asm("str r12, [r0] "); // |
|
772 asm("stmia lr!, {r8,r9,r10} "); // append rectangle - rect.iTl.iX,rect.iTl.iY,rect.iBr.iX |
|
773 asm("stmia lr!, {r5} "); // inter.iTl.iY |
|
774 __POPRET("r12,"); |
|
775 |
|
776 // AppendRect(TRect(inter.iBr.iX,inter.iTl.iY,rect.iBr.iX,inter.iBr.iY)) |
|
777 asm("subrectapp3: "); |
|
778 asm("stmfd sp!, {r0-r3,r12,lr} "); // preserve registers across function call |
|
779 asm("bl " CSM_Z16AllocAnotherRectP7TRegion); |
|
780 asm("ldmfd sp!, {r0-r3} "); |
|
781 asm("beq subrectapp1_end "); // exit if error |
|
782 asm("ldr r12, [r0] "); // r12=iCount |
|
783 asm("ldr lr, [r0, #8] "); // lr points to first rectangle |
|
784 asm("cmn lr, lr "); |
|
785 asm("ldrcc lr, [r0, #16] "); // if RRegion |
|
786 asm("addcs lr, r0, #20 "); // RRegionBuf |
|
787 asm("submi lr, lr, #8 "); // TRegionFix |
|
788 asm("add lr, lr, r12, lsl #4 "); // lr=&(iRectangleList[iCount]) |
|
789 asm("add r12, r12, #1 "); // increment iCount |
|
790 asm("str r12, [r0] "); // |
|
791 asm("stmia lr!, {r6} "); // append rectangle - inter.iBr.iX |
|
792 asm("stmia lr!, {r5,r10} "); // inter.iTl.iY, rect.iBr.iX |
|
793 asm("stmia lr!, {r7} "); // inter.iBr.iY |
|
794 __POPRET("r12,"); |
|
795 |
|
796 // AppendRect(TRect(rect.iTl.iX,inter.iTl.iY,inter.iTl.iX,inter.iBr.iY)) |
|
797 asm("subrectapp4: "); |
|
798 asm("stmfd sp!, {r0-r3,r12,lr} "); // preserve registers across function call |
|
799 asm("bl " CSM_Z16AllocAnotherRectP7TRegion); |
|
800 asm("ldmfd sp!, {r0-r3} "); |
|
801 asm("beq subrectapp1_end "); // exit if error |
|
802 asm("ldr r12, [r0] "); // r12=iCount |
|
803 asm("ldr lr, [r0, #8] "); // lr points to first rectangle |
|
804 asm("cmn lr, lr "); |
|
805 asm("ldrcc lr, [r0, #16] "); // if RRegion |
|
806 asm("addcs lr, r0, #20 "); // RRegionBuf |
|
807 asm("submi lr, lr, #8 "); // TRegionFix |
|
808 asm("add lr, lr, r12, lsl #4 "); // lr=&(iRectangleList[iCount]) |
|
809 asm("add r12, r12, #1 "); // increment iCount |
|
810 asm("str r12, [r0] "); // |
|
811 asm("stmia lr!, {r8} "); // append rectangle - rect.iTl.iX |
|
812 asm("stmia lr!, {r5} "); // inter.iTl.iY |
|
813 asm("stmia lr!, {r4,r7} "); // inter.iTl.iX, inter.iBr.iY |
|
814 __POPRET("r12,"); |
|
815 |
|
816 // aSubtractedRegion->AddRect(inter) |
|
817 asm("subrectadd: "); |
|
818 asm("stmfd sp!, {r0-r7,r12,lr} "); // preserve registers and put inter onto stack |
|
819 asm("mov r0, r2 "); // this = aSubtractedRegion |
|
820 asm("add r1, sp, #16 "); // inter is 16 bytes above sp |
|
821 asm("bl " CSM_ZN7TRegion7AddRectERK5TRect); // call TRegion::AddRect |
|
822 __POPRET("r0-r7,r12,"); |
|
823 } |
|
824 |
|
825 |
|
826 |
|
827 |
|
828 __NAKED__ EXPORT_C void TRegion::Intersection(const TRegion& /*aRegion1*/,const TRegion& /*aRegion2*/) |
|
829 /** |
|
830 Replaces this region with the area of intersection between two specified regions. |
|
831 |
|
832 Notes: |
|
833 |
|
834 1. If the error flag of either of the two specified regions is set, then this |
|
835 region is cleared and its error flag is set. This frees up allocated memory. |
|
836 |
|
837 2. If this region's error flag is already set, then the function has no effect. |
|
838 |
|
839 @param aRegion1 The first region. |
|
840 @param aRegion2 The second region. |
|
841 */ |
|
842 { |
|
843 // r0=this, r1=&aRegion1, r2=&aRegion2 |
|
844 asm("ldr r3, [r1, #4] "); // r3=aRegion1.iError |
|
845 asm("ldr r12, [r2, #4] "); // r12=aRegion2.iError |
|
846 asm("orrs r3, r3, r12 "); |
|
847 asm("bne " CSM_ZN7TRegion10ForceErrorEv); // if either set, ForceError() |
|
848 asm("str r3, [r0] "); // iCount=0 |
|
849 asm("ldr r3, [r1] "); // r3=aRegion1.iCount |
|
850 asm("ldr r12, [r2] "); // r12=aRegion2.iCount |
|
851 asm("cmp r3, #0 "); |
|
852 asm("cmpne r12, #0 "); |
|
853 __JUMP(eq,lr); |
|
854 asm("stmfd sp!, {r3-r11,lr} "); |
|
855 asm("ldr lr, [r1, #8] "); // r1 points to first rectangle of aRegion1 = pRect1 |
|
856 asm("cmn lr, lr "); |
|
857 asm("ldrcc r1, [r1, #16] "); // if RRegion |
|
858 asm("addcs r1, r1, #20 "); // RRegionBuf |
|
859 asm("submi r1, r1, #8 "); // TRegionFix |
|
860 asm("intersection1: "); |
|
861 asm("ldr lr, [r2, #8] "); // lr points to first rectangle of aRegion2 |
|
862 asm("cmn lr, lr "); |
|
863 asm("ldrcc lr, [r2, #16] "); // if RRegion |
|
864 asm("addcs lr, r2, #20 "); // RRegionBuf |
|
865 asm("submi lr, lr, #8 "); // TRegionFix |
|
866 asm("ldr r12, [r2] "); // r12=aRegion2.iCount |
|
867 asm("intersection2: "); |
|
868 asm("ldmia r1, {r4-r7} "); // r4-r7 = *pRect1 |
|
869 asm("ldmia lr!, {r8-r11} "); // r8-r11 = *pRect2++ |
|
870 asm("cmp r6, r8 "); // compare pRect1->iBr.iX with pRect2->iTl.iX |
|
871 asm("cmpgt r7, r9 "); // if >, compare pRect1->iBr.iY with pRect2->iTl.iY |
|
872 asm("cmpgt r10, r4 "); // if >, compare pRect2->iBr.iX with pRect1->iTl.iX |
|
873 asm("cmpgt r11, r5 "); // if >, compare pRect2->iBr.iY with pRect1->iTl.iY |
|
874 asm("ble intersection3 "); // if <=, rectangles have empty intersection, so iterate |
|
875 asm("cmp r4, r8 "); // compute intersection and place in r8-r11 |
|
876 asm("movgt r8, r4 "); |
|
877 asm("cmp r5, r9 "); |
|
878 asm("movgt r9, r5 "); |
|
879 asm("cmp r6, r10 "); |
|
880 asm("movlt r10, r6 "); |
|
881 asm("cmp r7, r11 "); |
|
882 asm("movlt r11, r7 "); |
|
883 asm("stmfd sp!, {r0-r3,r12,lr} "); // preserve registers across function call |
|
884 asm("bl " CSM_Z16AllocAnotherRectP7TRegion); |
|
885 asm("ldmfd sp!, {r0-r3} "); |
|
886 asm("ldmeqfd sp!, {r12,lr} "); // exit if error |
|
887 asm("beq intersection_end "); |
|
888 |
|
889 asm("ldr r12, [r0] "); // r12=iCount |
|
890 asm("ldr lr, [r0, #8] "); // lr points to first rectangle |
|
891 asm("cmn lr, lr "); |
|
892 asm("ldrcc lr, [r0, #16] "); // if RRegion |
|
893 asm("addcs lr, r0, #20 "); // RRegionBuf |
|
894 asm("submi lr, lr, #8 "); // TRegionFix |
|
895 asm("add lr, lr, r12, lsl #4 "); // lr=&(iRectangleList[iCount]) |
|
896 asm("add r12, r12, #1 "); // increment iCount |
|
897 asm("str r12, [r0] "); // |
|
898 asm("stmia lr!, {r8-r11} "); // append intersection of rectangles |
|
899 asm("ldmfd sp!, {r12,lr} "); // restore registers |
|
900 asm("intersection3: "); |
|
901 asm("subs r12, r12, #1 "); |
|
902 asm("bne intersection2 "); // loop for all values of pRect2 |
|
903 asm("add r1, r1, #16 "); // increment pRect1 |
|
904 asm("subs r3, r3, #1 "); |
|
905 asm("bne intersection1 "); // loop for all values of pRect1 |
|
906 |
|
907 asm("intersection_end: "); |
|
908 __POPRET("r3-r11,"); |
|
909 } |
|
910 |
|
911 #endif |
|
912 |
|
913 |
|
914 |
|
915 |
|
916 #ifdef __COBJECT_MACHINE_CODED__ |
|
917 __NAKED__ EXPORT_C CObject *CObjectIx::At(TInt /*aHandle*/,TInt /*aUniqueID*/) |
|
918 /** |
|
919 Gets a pointer to the reference counting object with the specified handle |
|
920 number and matching unique ID. |
|
921 |
|
922 @param aHandle The handle number of the reference counting object. |
|
923 @param aUniqueID The unique ID. |
|
924 |
|
925 @return A pointer to the reference counting object. If there is no matching |
|
926 object, then this is NULL. |
|
927 */ |
|
928 { |
|
929 // r0=this, r1=aHandle, r2=aUniqueID |
|
930 asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark)); // r3=iHighWaterMark |
|
931 asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects)); // r0=iObjects |
|
932 asm("mov r12, r1, lsl #17 "); // r12=r1<<17 = index(aHandle)<<17 |
|
933 asm("cmp r3, r12, lsr #17 "); // compare iHighWaterMark with index(aHandle) |
|
934 asm("movle r0, #0 "); // if hwm<=index, return NULL |
|
935 __JUMP(le,lr); |
|
936 asm("add r0, r0, r12, lsr #14 "); // r0=iObjects+index(Handle)=pS |
|
937 asm("ldr r3, [r0] "); // r3=pS->uniqueID:pS->instance |
|
938 asm("mov r1, r1, lsl #2 "); // r1=instance(Handle)<<18 |
|
939 asm("mov r1, r1, lsr #18 "); // r1=instance(Handle) |
|
940 asm("orr r1, r1, r2, lsl #16 "); // r1=aUniqueID:instance(Handle) |
|
941 asm("cmp r1, r3 "); // check uniqueID and instance |
|
942 asm("movne r0, #0 "); // if wrong, return 0 |
|
943 asm("ldreq r0, [r0, #4] "); // else return pointer to CObject |
|
944 __JUMP(,lr); |
|
945 } |
|
946 |
|
947 |
|
948 |
|
949 |
|
950 __NAKED__ EXPORT_C CObject *CObjectIx::At(TInt aHandle) |
|
951 /** |
|
952 Gets a pointer to the reference counting object with the specified |
|
953 handle number. |
|
954 |
|
955 @param aHandle The handle number of the reference counting object. |
|
956 |
|
957 @return A pointer to the reference counting object. If there is no matching |
|
958 object, then this is NULL. |
|
959 */ |
|
960 { |
|
961 // r0=this, r1=aHandle |
|
962 asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark)); // r3=iHighWaterMark |
|
963 asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects)); // r0=iObjects |
|
964 asm("mov r12, r1, lsl #17 "); // r12=r1<<17 = index(aHandle)<<17 |
|
965 asm("cmp r3, r12, lsr #17 "); // compare iHighWaterMark with index(aHandle) |
|
966 asm("movle r0, #0 "); // if hwm<=index, return NULL |
|
967 __JUMP(le,lr); |
|
968 asm("add r0, r0, r12, lsr #14 "); // r0=iObjects+index(Handle)=pS |
|
969 asm("ldr r3, [r0] "); // r3=pS->uniqueID:pS->instance |
|
970 asm("ldr r2, __instanceMask "); |
|
971 asm("and r1, r1, r2 "); // r1=instance(Handle)<<16 |
|
972 asm("cmp r1, r3, lsl #16 "); // check instance |
|
973 asm("movne r0, #0 "); // if wrong, return 0 |
|
974 asm("ldreq r0, [r0, #4] "); // else return pointer to CObject |
|
975 __JUMP(,lr); |
|
976 asm("__instanceMask: "); |
|
977 asm(".word 0x3FFF0000 "); |
|
978 } |
|
979 |
|
980 |
|
981 |
|
982 |
|
983 GLREF_C void PanicCObjectIxIndexOutOfRange(void); |
|
984 |
|
985 |
|
986 |
|
987 |
|
988 __NAKED__ EXPORT_C CObject* CObjectIx::operator[](TInt /*anIndex*/) |
|
989 /** |
|
990 Gets a pointer to a reference counting object located at the specified offset |
|
991 within the object index. |
|
992 |
|
993 @param anIndex The offset of the reference counting object within the object |
|
994 index. Offset is relative to zero. |
|
995 |
|
996 @return A pointer to the reference counting object. |
|
997 |
|
998 @panic E32USER-CBase 21 if the value of anIndex is negative or is greater than |
|
999 or equal to the total number of objects held by |
|
1000 the index. |
|
1001 */ |
|
1002 { |
|
1003 // r0=this, r1=anIndex |
|
1004 asm("cmp r1, #0 "); // check anIndex>=0 |
|
1005 asm("ldrge r3, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iHighWaterMark)); // if so, r3=iHighWaterMark |
|
1006 asm("cmpge r3, r1 "); // and compare iHighWaterMark to anIndex |
|
1007 asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectIx,iObjects)); // if OK, r0=iObjects |
|
1008 asm("addgt r0, r0, r1, lsl #3 "); // r0=iObjects+anIndex |
|
1009 asm("ldrgt r0, [r0, #4] "); // r0=pointer to CObject |
|
1010 #ifdef __CPU_ARMV6 |
|
1011 asm("ble 1f "); |
|
1012 __JUMP(,lr); |
|
1013 #else |
|
1014 __JUMP(gt,lr); |
|
1015 #endif |
|
1016 asm("1: "); |
|
1017 asm("b " CSM_Z29PanicCObjectIxIndexOutOfRangev); // if anIndex<0 or iCount<=anIndex, panic |
|
1018 } |
|
1019 |
|
1020 |
|
1021 |
|
1022 |
|
1023 GLREF_C void PanicCObjectConIndexOutOfRange(void); |
|
1024 GLREF_C void PanicCObjectConFindBadHandle(void); |
|
1025 GLREF_C void PanicCObjectConFindIndexOutOfRange(void); |
|
1026 |
|
1027 |
|
1028 |
|
1029 |
|
1030 __NAKED__ EXPORT_C CObject *CObjectCon::operator[](TInt /*anIndex*/) |
|
1031 /** |
|
1032 Gets a pointer to the reference counting object located at the specified offset |
|
1033 within the object container. |
|
1034 |
|
1035 @param anIndex The offset of the reference counting object within the object |
|
1036 container. Offset is relative to zero. |
|
1037 |
|
1038 @return A pointer to the owning reference counting object. |
|
1039 |
|
1040 @panic E32USER-CBase 21 if anIndex is negative or is greater than or equal to |
|
1041 the total number of objects held by the container. |
|
1042 */ |
|
1043 { |
|
1044 // r0=this, r1=anIndex |
|
1045 asm("cmp r1, #0 "); |
|
1046 asm("ldrge r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount)); |
|
1047 asm("cmpge r2, r1 "); |
|
1048 asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects)); |
|
1049 asm("ldrgt r0, [r0, r1, lsl #2] "); |
|
1050 #ifdef __CPU_ARMV6 |
|
1051 asm("ble 1f "); |
|
1052 __JUMP(,lr); |
|
1053 #else |
|
1054 __JUMP(gt,lr); |
|
1055 #endif |
|
1056 asm("1: "); |
|
1057 asm("b " CSM_Z30PanicCObjectConIndexOutOfRangev); |
|
1058 } |
|
1059 |
|
1060 |
|
1061 |
|
1062 |
|
1063 __NAKED__ EXPORT_C CObject *CObjectCon::At(TInt /*aFindHandle*/) const |
|
1064 /** |
|
1065 Gets a pointer to the reference counting object with the specified find-handle |
|
1066 number. |
|
1067 |
|
1068 A find-handle number is an integer which uniquely identifies a reference |
|
1069 counting object with respect to its object container. |
|
1070 |
|
1071 @param aFindHandle The find-handle number of the reference counting object. |
|
1072 The unique Id part of this number must be the same as the |
|
1073 unique Id of this container. |
|
1074 The index part of the find-handle number must be |
|
1075 a valid index. |
|
1076 |
|
1077 @return A pointer to the reference counting object. |
|
1078 |
|
1079 @panic E32User-CBase 38 if the unique Id part of aFindHandle is not the same as |
|
1080 the unique Id of this container. |
|
1081 @panic E32User-CBase 39 if the index part of aFindHandle is negative or greater |
|
1082 than or equal to the total number of reference counting |
|
1083 objects held by this object container. |
|
1084 */ |
|
1085 { |
|
1086 // r0=this, r1=aFindHandle |
|
1087 asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iUniqueID)); |
|
1088 asm("cmp r2, r1, lsr #16 "); |
|
1089 asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount)); |
|
1090 asm("bne " CSM_Z28PanicCObjectConFindBadHandlev); |
|
1091 asm("mov r1, r1, lsl #17 "); |
|
1092 asm("cmp r2, r1, lsr #17 "); |
|
1093 asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects)); |
|
1094 asm("ble " CSM_Z34PanicCObjectConFindIndexOutOfRangev); |
|
1095 asm("ldr r0, [r0, r1, lsr #15] "); |
|
1096 __JUMP(,lr); |
|
1097 } |
|
1098 |
|
1099 |
|
1100 |
|
1101 |
|
1102 __NAKED__ EXPORT_C CObject *CObjectCon::AtL(TInt /*aFindHandle*/) const |
|
1103 /** |
|
1104 Gets a pointer to the reference counting object with the specified find-handle |
|
1105 number, and leaves on error. |
|
1106 |
|
1107 A find-handle number is an integer which uniquely identifies a reference |
|
1108 counting object with respect to its object container. |
|
1109 |
|
1110 @param aFindHandle The find-handle number of the reference counting object. |
|
1111 The unique Id part of this number must be the same as |
|
1112 the unique Id of this container. |
|
1113 The index part of the find-handle number must be |
|
1114 a valid index. |
|
1115 |
|
1116 @return A pointer to the reference counting object. |
|
1117 |
|
1118 @leave KErrBadHandle if the unique Id part of aFindHandle is not the same as |
|
1119 the unique Id of this container. |
|
1120 @leave KErrArgument if the index part of aFindHandle is negative or greater |
|
1121 than or equal to the total number of reference counting |
|
1122 objects held by this object container. |
|
1123 */ |
|
1124 { |
|
1125 // r0=this, r1=aFindHandle |
|
1126 asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iUniqueID)); |
|
1127 asm("cmp r2, r1, lsr #16 "); |
|
1128 asm("ldreq r2, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iCount)); |
|
1129 asm("bne 1f "); |
|
1130 asm("mov r1, r1, lsl #17 "); |
|
1131 asm("cmp r2, r1, lsr #17 "); |
|
1132 asm("ldrgt r0, [r0, #%a0]" : : "i" _FOFF(CObjectCon,iObjects)); |
|
1133 asm("ble 2f "); |
|
1134 asm("ldr r0, [r0, r1, lsr #15] "); |
|
1135 __JUMP(,lr); |
|
1136 // User::Leave tail called, so no annotations required since |
|
1137 // current frame is reused by User::Leave |
|
1138 asm("1: "); |
|
1139 asm("mvn r0, #7 "); // KErrBadHandle |
|
1140 asm("b " CSM_ZN4User5LeaveEi); |
|
1141 asm("2: "); |
|
1142 asm("mvn r0, #5 "); // KErrArgument |
|
1143 asm("b " CSM_ZN4User5LeaveEi); |
|
1144 } |
|
1145 #endif |
|
1146 |
|
1147 #ifdef __CACTIVESCHEDULER_MACHINE_CODED__ |
|
1148 extern "C" void PanicStrayEvent(); |
|
1149 |
|
1150 /** |
|
1151 @internalComponent |
|
1152 |
|
1153 The inner active scheduler loop. This repeatedly waits for a signal and then |
|
1154 dispatches the highest priority ready active object. The loop terminates either |
|
1155 if one of the RunL()s stops the current active scheduler level or leaves. |
|
1156 |
|
1157 Stop when aLoop becomes 'Inactive' |
|
1158 */ |
|
1159 __NAKED__ void CActiveScheduler::DoRunL(TLoopOwner* const volatile& aLoop, CActive* volatile & aCurrentObj, TCleanupBundle* aCleanupBundlePtr) |
|
1160 { |
|
1161 asm("stmfd sp!, {r4-r8,lr} "); |
|
1162 __EH_FRAME_PUSH2(r4-r8,lr) |
|
1163 |
|
1164 #ifdef _DEBUG |
|
1165 // need to copy aCleanupBundlePtr to somewhere else before it's clobbered by the next line. |
|
1166 asm("mov r8, r3 "); // r8 = &aCleanupBundlePtr |
|
1167 #endif |
|
1168 |
|
1169 asm("ldr r3, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_)); // r3 = vptr |
|
1170 asm("add r4, r0, #%a0" : : "i" _FOFF(CActiveScheduler,iActiveQ)); // r4 = &iActiveQ |
|
1171 asm("mov r5, r1 "); // r5 = &aLoop |
|
1172 asm("mov r7, r2 "); // r7 = &aCurrentObj |
|
1173 asm("ldr r6, [r3, #%a0]" : : "i" (_CACTIVESCHEDULER_WAIT_OFFSET_)); // r6 = &WaitForAnyRequest() |
|
1174 |
|
1175 asm("active_scheduler_loop: "); |
|
1176 asm("ldr r1, [r5] "); // r1 = aLoop |
|
1177 asm("adr lr, 1f "); // return address |
|
1178 asm("sub r0, r4, #%a0 " : : "i" _FOFF(CActiveScheduler,iActiveQ)); // this |
|
1179 asm("cmp r1, #0 "); |
|
1180 __JUMP(ne, r6); // call WaitForAnyRequest() if still active |
|
1181 __POPRET("r4-r8,"); // else return |
|
1182 |
|
1183 // get here when WaitForAnyRequest() returns |
|
1184 asm("1: "); |
|
1185 asm("ldr r14, [r4, #0] "); // r14->first active object |
|
1186 |
|
1187 asm("2: "); |
|
1188 asm("cmp r14, r4 "); // end of queue? |
|
1189 asm("sub r0, r14, #%a0" : : "i" _FOFF(CActive,iLink)); // r0->CActive |
|
1190 asm("ldmneda r14, {r2, r12, r14} "); // r2=iStatus, r12=iStatus.iFlags (old iActive), r14 = next object |
|
1191 asm("beq PanicStrayEvent "); // if end of queue, panic |
|
1192 #ifdef _DEBUG |
|
1193 asm("ands r3, r12, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending))); // only active bit and request-pending bit |
|
1194 asm("cmpne r3, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending))); // active bit == request pending bit |
|
1195 asm("bne PanicStrayEvent "); // if active bit != request pending bit, panic |
|
1196 #endif |
|
1197 asm("cmp r2, #%a0" : : "i" ((TInt)KRequestPending)); // test if iStatus!=KRequestPending |
|
1198 asm("andnes r3, r12, #%a0" : : "i" ((TInt)TRequestStatus::EActive)); // if so, test iActive |
|
1199 asm("beq 2b "); // if not active or still pending, do next CActive |
|
1200 |
|
1201 // have an active object to run |
|
1202 #ifdef __SMP__ |
|
1203 __DATA_MEMORY_BARRIER_Z__(r3); // acquire semantics |
|
1204 #endif |
|
1205 asm("ldr r3, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_)); // r3=CActive->vptr |
|
1206 asm("bic r12, r12, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending))); |
|
1207 asm("ldr r3, [r3, #%a0]" : : "i" (_CACTIVE_RUNL_OFFSET_)); // r3 = &CActive::RunL() |
|
1208 asm("str r12, [r0, #%a0]" : : "i" (_FOFF(CActive,iStatus)+_FOFF(TRequestStatus,iFlags))); // iActive=EFalse |
|
1209 asm("str r0, [r7] "); // save active object in aCurrentObj in case RunL leaves |
|
1210 #ifdef _DEBUG |
|
1211 __JUMPL(3); // call RunL() (and continue) |
|
1212 #else |
|
1213 asm("adr lr, active_scheduler_loop "); // set lr (return address) to label, active_scheduler_loop |
|
1214 __JUMP(,r3); // call RunL() (and loop) |
|
1215 #endif |
|
1216 |
|
1217 |
|
1218 #ifdef _DEBUG |
|
1219 //check whether there's a cleanup stack installed: |
|
1220 |
|
1221 asm("cmp r8, #0"); // check CleanupBundle* == NULL |
|
1222 asm("beq active_scheduler_loop "); // If r8 == NULL, branch to label, active_scheduler_loop |
|
1223 asm("ldr r0, [r8, #%a0]" : : "i" _FOFF(TCleanupBundle,iCleanupPtr)); // r0 = CCleanup* (load the CCleanup*) |
|
1224 |
|
1225 //there is a cleanupstack installed: |
|
1226 asm("add r1, r8, #%a0" : : "i" _FOFF(TCleanupBundle,iDummyInt)); // r1 = iDummyInt* (load the TInt*) |
|
1227 asm("adr lr, active_scheduler_loop "); // set lr (return address) to label, active_scheduler_loop |
|
1228 asm("b " CSM_ZN8CCleanup5CheckEPv); // call CCleanup::Check(iDummyInt*) |
|
1229 #endif |
|
1230 |
|
1231 } |
|
1232 #endif |
|
1233 |
|
1234 |
|
1235 #ifdef __CSERVER_MACHINE_CODED__ |
|
1236 __NAKED__ EXPORT_C void CServer2::RunL() |
|
1237 { |
|
1238 asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(CServer2,iMessage.iFunction)); // r2=Message().Function() |
|
1239 asm("stmfd sp!, {r4, lr}"); // save regs |
|
1240 __EH_FRAME_PUSH2(r4,lr) |
|
1241 asm("cmp r2, #0"); // check for Connect/Disconnect message |
|
1242 asm("bmi server2_con_dis"); |
|
1243 |
|
1244 // Service the message |
|
1245 asm("mov r4, r0 "); // r4=this |
|
1246 asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(CServer2,iMessage.iSessionPtr)); // r0=session |
|
1247 asm("add r1, r4, #%a0" : : "i" (_FOFF(CServer2,iMessage))); // r1=&iServer.Message() |
|
1248 asm("cmp r0, #0"); // Check for NULL session |
|
1249 asm("ldrne r12, [r0, #%a0]" : : "i" (_CBASE_VPTR_OFFSET_)); // r12=CSession2::vptr |
|
1250 #ifdef __SUPPORT_THUMB_INTERWORKING |
|
1251 asm("ldrne r3, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_)); // call CSession2::ServiceL(iMessage) |
|
1252 asm("adr lr, server2_run_postamble "); |
|
1253 asm("bxne r3 "); |
|
1254 #else |
|
1255 asm("adr lr, server2_run_postamble "); |
|
1256 asm("ldrne pc, [r12, #%a0]" : : "i" (_CSESSION2_SERVICEL_OFFSET_)); // call CSession2::ServiceL(iMessage) |
|
1257 #endif |
|
1258 asm("mov r0, r1"); |
|
1259 asm("b " CSM_ZN8CServer212NotConnectedERK9RMessage2); // NULL session ptr means not connected |
|
1260 |
|
1261 // Do this after processing any message |
|
1262 asm("server2_run_postamble: "); |
|
1263 asm("ldr r2, [r4, #%a0]" : : "i" (_FOFF(CServer2,iStatus)+_FOFF(TRequestStatus,iFlags))); // r2=iStatus.iFlags (old iActive) |
|
1264 asm("mov r0, #0x80000001 "); // r0=KRequestPending |
|
1265 asm("ands r1, r2, #%a0" : : "i" ((TInt)TRequestStatus::EActive)); |
|
1266 asm("bne server2_run_end "); // if already active, finished |
|
1267 asm("orr r2, r2, #%a0" : : "i" ((TInt)(TRequestStatus::EActive|TRequestStatus::ERequestPending))); |
|
1268 asm("add r1, r4, #%a0" : : "i" _FOFF(CActive,iStatus)); // r1->iStatus |
|
1269 asm("stmia r1, {r0,r2} "); // set iStatus=KRequestPending, set active bit, set request pending bit |
|
1270 asm("add r2, r4, #%a0" : : "i" _FOFF(CServer2,iMessage)); // r2->iServer.Message() |
|
1271 asm("ldr r0, [r4, #%a0]" : : "i" _FOFF(CServer2,iServer)); // r0=iServer.iHandle |
|
1272 asm("bl " CSM_ZN4Exec13ServerReceiveEiR14TRequestStatusPv);// call Exec::ServerReceive |
|
1273 asm("server2_run_end: "); |
|
1274 __POPRET("r4,"); |
|
1275 |
|
1276 // Deal with Connect and Disconnect messages |
|
1277 asm("server2_con_dis:"); |
|
1278 asm("mov r4, r0 "); // r4=this |
|
1279 asm("add r1, r0, #%a0" : : "i" _FOFF(CServer2,iMessage)); // r1=&iServer.Message() |
|
1280 asm("adr lr, server2_run_postamble "); // return address for after any processing |
|
1281 asm("cmp r2, #%a0" : : "i" (RMessage2::EConnect)); |
|
1282 asm("beq " CSM_ZN8CServer27ConnectERK9RMessage2); // Do Connect() |
|
1283 asm("cmp r2, #%a0" : : "i" (RMessage2::EDisConnect)); |
|
1284 asm("beq " CSM_ZN8CServer210DisconnectERK9RMessage2); // Do Disconnect() |
|
1285 asm("mov r0, r1"); |
|
1286 asm("b " CSM_ZN8CServer210BadMessageERK9RMessage2); // Bad message |
|
1287 } |
|
1288 #endif |
|
1289 |
|
1290 EXPORT_C __NAKED__ void RFastLock::Wait() |
|
1291 { |
|
1292 asm("1: "); |
|
1293 asm("add r0, r0, #4 "); // point to iCount |
|
1294 |
|
1295 #ifdef __CPU_ARM_HAS_LDREX_STREX |
|
1296 asm("2: "); |
|
1297 LDREX( 2, 0); // read |
|
1298 asm("subs r1, r2, #1 "); // decrement |
|
1299 STREX( 3, 1, 0); // write |
|
1300 asm("teq r3, #0 "); // success? |
|
1301 asm("bne 2b "); // no! |
|
1302 asm("sub r0, r0, #4 "); // r0 = this |
|
1303 asm("bcs " CSM_ZN10RSemaphore4WaitEv); // if no borrow from decrement wait on semaphore |
|
1304 #ifdef __SMP__ |
|
1305 __DATA_MEMORY_BARRIER__(r3); // no need to wait, but still need acquire barrier |
|
1306 #endif |
|
1307 __JUMP(, lr ); |
|
1308 #else |
|
1309 asm("mov r1, #1 "); // 'looking' value |
|
1310 asm("swp r1, r1, [r0] "); // write looking value, read original |
|
1311 asm("subs r1, r1, #1 "); // decrement count |
|
1312 asm("strlt r1, [r0] "); // if it becomes negative, no-one was looking |
|
1313 __JUMP(cc, lr); // if borrow, was originally zero so we are finished |
|
1314 asm("sub r0, r0, #4 "); // r0=this |
|
1315 asm("blt " CSM_ZN10RSemaphore4WaitEv); // lock held so wait on semaphore |
|
1316 asm("stmfd sp!, {r0,lr} "); // otherwise save registers |
|
1317 asm("mov r0, #1000 "); // someone was looking, so wait 1ms and try again |
|
1318 asm("bl " CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32); |
|
1319 asm("ldmfd sp!, {r0,lr} "); |
|
1320 asm("b 1b "); |
|
1321 #endif |
|
1322 } |
|
1323 |
|
1324 EXPORT_C __NAKED__ void RFastLock::Signal() |
|
1325 { |
|
1326 asm("1: "); |
|
1327 asm("add r0, r0, #4 "); // point to iCount |
|
1328 |
|
1329 #ifdef __CPU_ARM_HAS_LDREX_STREX |
|
1330 #ifdef __SMP__ |
|
1331 __DATA_MEMORY_BARRIER_Z__(r3); // need release barrier |
|
1332 #endif |
|
1333 asm("2: "); |
|
1334 LDREX( 2, 0); // read |
|
1335 asm("adds r1, r2, #1 "); // increment |
|
1336 STREX( 3, 1, 0); // write |
|
1337 asm("teq r3, #0 "); // success? |
|
1338 asm("bne 2b "); // no! |
|
1339 asm("sub r0, r0, #4 "); // r0 = this |
|
1340 asm("bcc " CSM_ZN10RSemaphore6SignalEv); // if no carry from increment, signal semaphore |
|
1341 __JUMP(, lr ); |
|
1342 #else |
|
1343 asm("mov r1, #1 "); // 'looking' value |
|
1344 asm("swp r1, r1, [r0] "); // write looking value, read original |
|
1345 asm("adds r1, r1, #1 "); // increment count |
|
1346 asm("strle r1, [r0] "); // if still <=0, no-one was looking |
|
1347 __JUMP(eq, lr); // if it's now zero, no-one is waiting so we are finished |
|
1348 asm("sub r0, r0, #4 "); // r0=this |
|
1349 asm("blt " CSM_ZN10RSemaphore6SignalEv); // someone is waiting so signal semaphore |
|
1350 asm("stmfd sp!, {r0,lr} "); // otherwise save registers |
|
1351 asm("mov r0, #1000 "); // someone was looking, so wait 1ms and try again |
|
1352 asm("bl " CSM_ZN4User12AfterHighResE27TTimeIntervalMicroSeconds32); |
|
1353 asm("ldmfd sp!, {r0,lr} "); |
|
1354 asm("b 1b "); |
|
1355 #endif |
|
1356 } |
|
1357 |
|
1358 |
|
1359 // Entry point stub to allow EKA1 binaries to be executed under EKA2 |
|
1360 // Only called when process is first loaded |
|
1361 |
|
1362 extern "C" TLinAddr GetEka1ExeEntryPoint(); |
|
1363 |
|
1364 __NAKED__ TInt E32Loader::V7ExeEntryStub() |
|
1365 { |
|
1366 // Process entry point |
|
1367 // R4 = entry reason |
|
1368 // SP points to information block |
|
1369 asm("cmp r4, #%a0" : : "i" ((TInt)KModuleEntryReasonProcessInit) ); |
|
1370 asm("bne " CSM_ZN4User9InvariantEv ); // invalid entry reason |
|
1371 asm("bl GetEka1ExeEntryPoint "); // load the entry stub and return its address |
|
1372 __JUMP(,r0); // jump to the entry stub with R4, SP unchanged |
|
1373 } |
|
1374 |
|
1375 __NAKED__ TInt E32Loader::V7DllEntryStub(TInt) |
|
1376 { |
|
1377 |
|
1378 __JUMP(,lr); |
|
1379 } |
|
1380 |
|
1381 |
|
1382 // Hash an 8 bit string at aPtr, length aLen bytes. |
|
1383 __NAKED__ TUint32 DefaultStringHash(const TUint8* /*aPtr*/, TInt /*aLen*/) |
|
1384 { |
|
1385 asm("ldr r3, one_over_phi "); |
|
1386 asm("subs r1, r1, #4 "); |
|
1387 asm("mov r2, r0 "); |
|
1388 asm("mov r0, #0 "); |
|
1389 asm("blo 1f "); |
|
1390 asm("ands r12, r2, #3 "); |
|
1391 asm("bne hash_unal "); |
|
1392 asm("2: "); |
|
1393 asm("ldr r12, [r2], #4 "); |
|
1394 asm("subs r1, r1, #4 "); |
|
1395 asm("eor r0, r0, r12 "); |
|
1396 asm("umull r0, r12, r3, r0 "); |
|
1397 asm("bcs 2b "); |
|
1398 asm("1: "); |
|
1399 asm("adds r1, r1, #4 "); |
|
1400 __JUMP(eq,lr); |
|
1401 asm("4: "); |
|
1402 asm("ldrb r12, [r2], #1 "); |
|
1403 asm("cmp r1, #2 "); |
|
1404 asm("eor r0, r0, r12 "); |
|
1405 asm("ldrcsb r12, [r2], #1 "); |
|
1406 asm("eorcs r0, r0, r12, lsl #8 "); |
|
1407 asm("ldrhib r12, [r2], #1 "); |
|
1408 asm("eorhi r0, r0, r12, lsl #16 "); |
|
1409 asm("umull r0, r12, r3, r0 "); |
|
1410 __JUMP(,lr); |
|
1411 |
|
1412 asm("hash_unal: "); |
|
1413 asm("bic r2, r2, #3 "); |
|
1414 asm("stmfd sp!, {r4,r5,lr} "); |
|
1415 asm("mov r12, r12, lsl #3 "); |
|
1416 asm("rsb r14, r12, #32 "); |
|
1417 asm("ldr r4, [r2], #4 "); |
|
1418 asm("3: "); |
|
1419 asm("eor r0, r0, r4, lsr r12 "); |
|
1420 asm("ldr r4, [r2], #4 "); |
|
1421 asm("subs r1, r1, #4 "); |
|
1422 asm("eor r0, r0, r4, lsl r14 "); |
|
1423 asm("umull r0, r5, r3, r0 "); |
|
1424 asm("bcs 3b "); |
|
1425 asm("adds r1, r1, #4 "); |
|
1426 asm("ldmfd sp!, {r4,r5,lr} "); |
|
1427 asm("subne r2, r2, #4 "); |
|
1428 asm("addne r2, r2, r12, lsr #3 "); |
|
1429 asm("bne 4b "); |
|
1430 __JUMP(,lr); |
|
1431 } |
|
1432 |
|
1433 // Hash a 16 bit string at aPtr, length aLen bytes. |
|
1434 __NAKED__ TUint32 DefaultWStringHash(const TUint16* /*aPtr*/, TInt /*aLen*/) |
|
1435 { |
|
1436 asm("str lr, [sp, #-4]! "); |
|
1437 asm("ldr r3, one_over_phi "); |
|
1438 asm("subs r1, r1, #8 "); |
|
1439 asm("mov r2, r0 "); |
|
1440 asm("mov r0, #0 "); |
|
1441 asm("blo 1f "); |
|
1442 asm("ands r12, r2, #3 "); |
|
1443 asm("bne whash_unal "); |
|
1444 asm("2: "); |
|
1445 asm("ldmia r2!, {r12,r14} "); |
|
1446 asm("subs r1, r1, #8 "); |
|
1447 asm("eor r0, r0, r12 "); |
|
1448 asm("eor r0, r0, r14, ror #24 "); |
|
1449 asm("umull r0, r12, r3, r0 "); |
|
1450 asm("bcs 2b "); |
|
1451 asm("1: "); |
|
1452 asm("adds r1, r1, #8 "); |
|
1453 asm("beq 8f "); |
|
1454 asm("4: "); |
|
1455 asm("ldrh r12, [r2], #2 "); |
|
1456 asm("cmp r1, #4 "); |
|
1457 asm("eor r0, r0, r12 "); |
|
1458 asm("ldrcsh r12, [r2], #2 "); |
|
1459 asm("eorcs r0, r0, r12, lsl #16 "); |
|
1460 asm("ldrhih r12, [r2], #2 "); |
|
1461 asm("eorhi r0, r0, r12, ror #24 "); |
|
1462 asm("umull r0, r12, r3, r0 "); |
|
1463 asm("8: "); |
|
1464 __POPRET(""); |
|
1465 |
|
1466 asm("whash_unal: "); |
|
1467 asm("add r2, r2, #2 "); // r2 must be 2 mod 4 |
|
1468 asm("ldr r14, [r2, #-4] "); |
|
1469 asm("3: "); |
|
1470 asm("eor r0, r0, r14, lsr #16 "); // char 0 goes into bytes 0,1 |
|
1471 asm("ldmia r2!, {r12,r14} "); |
|
1472 asm("subs r1, r1, #8 "); |
|
1473 asm("eor r0, r0, r12, lsl #16 "); // char 1 goes into bytes 2,3 |
|
1474 asm("mov r12, r12, lsr #16 "); |
|
1475 asm("orr r12, r12, r14, lsl #16 "); // r12 = char3:char2 |
|
1476 asm("eor r0, r0, r12, ror #24 "); // char 2 into bytes 1,2 ; char 3 into bytes 3,0 |
|
1477 asm("umull r0, r12, r3, r0 "); |
|
1478 asm("bcs 3b "); |
|
1479 asm("adds r1, r1, #8 "); |
|
1480 asm("subne r2, r2, #2 "); |
|
1481 asm("bne 4b "); |
|
1482 __POPRET(""); |
|
1483 } |
|
1484 |
|
1485 |
|
1486 /** |
|
1487 @publishedAll |
|
1488 @released |
|
1489 |
|
1490 Calculate a 32 bit hash from a 32 bit integer. |
|
1491 |
|
1492 @param aInt The integer to be hashed. |
|
1493 @return The calculated 32 bit hash value. |
|
1494 */ |
|
1495 EXPORT_C __NAKED__ TUint32 DefaultHash::Integer(const TInt& /*aInt*/) |
|
1496 { |
|
1497 asm("ldr r0, [r0] "); |
|
1498 asm("ldr r1, one_over_phi "); |
|
1499 asm("umull r0, r2, r1, r0 "); |
|
1500 __JUMP(,lr); |
|
1501 asm("one_over_phi: "); |
|
1502 asm(".word 0x9e3779b9 "); |
|
1503 } |
|
1504 |
|
1505 |
|
1506 #ifdef __USERSIDE_THREAD_DATA__ |
|
1507 |
|
1508 /** |
|
1509 @internalComponent |
|
1510 |
|
1511 Get a pointer to the thread local user data stored in the thread ID register. |
|
1512 */ |
|
1513 __NAKED__ TLocalThreadData* LocalThreadData() |
|
1514 { |
|
1515 GET_RWRW_TID(,r0); |
|
1516 __JUMP(,lr); |
|
1517 } |
|
1518 |
|
1519 #endif |