Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\mmu\t_imb.cia
23 __NAKED__ TInt Sqrt(TReal& /*aDest*/, const TReal& /*aSrc*/)
25 // r0=address of aDest, r1=address of aSrc
26 asm("stmfd sp!, {r4-r10,lr} ");
27 #ifdef __DOUBLE_WORDS_SWAPPED__
28 asm("ldmia r1, {r3,r4} "); // low mant into r4, sign:exp:high mant into r3
30 asm("ldr r3, [r1, #4] ");
31 asm("ldr r4, [r1, #0] ");
33 asm("bic r5, r3, #0xFF000000 ");
34 asm("bic r5, r5, #0x00F00000 "); // high word of mantissa into r5
35 asm("mov r2, r3, lsr #20 ");
36 asm("bics r2, r2, #0x800 "); // exponent now in r2
37 asm("beq fastsqrt1 "); // branch if exponent zero (zero or denormal)
38 asm("mov r6, #0xFF ");
39 asm("orr r6, r6, #0x700 ");
40 asm("cmp r2, r6 "); // check for infinity or NaN
41 asm("beq fastsqrt2 "); // branch if infinity or NaN
42 asm("movs r3, r3 "); // test sign
43 asm("bmi fastsqrtn "); // branch if negative
44 asm("sub r2, r2, #0xFF "); // unbias the exponent
45 asm("sub r2, r2, #0x300 "); //
47 asm("mov r1, #0x40000000 "); // value for comparison
48 asm("mov r3, #27 "); // loop counter (number of bits/2)
49 asm("movs r2, r2, asr #1 "); // divide exponent by 2, LSB into CF
50 asm("movcs r7, r5, lsl #11 "); // mantissa into r6,r7 with MSB in MSB of r7
51 asm("orrcs r7, r7, r4, lsr #21 ");
52 asm("movcs r6, r4, lsl #11 ");
53 asm("movcs r4, #0 "); // r4, r5 will hold result mantissa
54 asm("orrcs r7, r7, #0x80000000 "); // if exponent odd, restore MSB of mantissa
55 asm("movcc r7, r5, lsl #12 "); // mantissa into r6,r7 with MSB in MSB of r7
56 asm("orrcc r7, r7, r4, lsr #20 "); // if exponent even, shift mantissa left an extra
57 asm("movcc r6, r4, lsl #12 "); // place, lose top bit, and
58 asm("movcc r4, #1 "); // set MSB of result, and
59 asm("mov r5, #0 "); // r4, r5 will hold result mantissa
60 asm("mov r8, #0 "); // r8, r9 will be comparison accumulator
62 asm("bcc fastsqrt4 "); // if exponent even, calculate one less bit
63 // as result MSB already known
65 // Main mantissa square-root loop
66 asm("fastsqrt3: "); // START OF MAIN LOOP
67 asm("subs r10, r7, r1 "); // subtract result:01 from acc:mant
68 asm("sbcs r12, r8, r4 "); // result into r14:r12:r10
69 asm("sbcs r14, r9, r5 ");
70 asm("movcs r7, r10 "); // if no borrow replace accumulator with result
71 asm("movcs r8, r12 ");
72 asm("movcs r9, r14 ");
73 asm("adcs r4, r4, r4 "); // shift result left one, putting in next bit
74 asm("adcs r5, r5, r5 ");
75 asm("mov r9, r9, lsl #2 "); // shift acc:mant left by 2 bits
76 asm("orr r9, r9, r8, lsr #30 ");
77 asm("mov r8, r8, lsl #2 ");
78 asm("orr r8, r8, r7, lsr #30 ");
79 asm("mov r7, r7, lsl #2 ");
80 asm("orr r7, r7, r6, lsr #30 ");
81 asm("mov r6, r6, lsl #2 ");
82 asm("fastsqrt4: "); // Come in here if we need to do one less iteration
83 asm("subs r10, r7, r1 "); // subtract result:01 from acc:mant
84 asm("sbcs r12, r8, r4 "); // result into r14:r12:r10
85 asm("sbcs r14, r9, r5 ");
86 asm("movcs r7, r10 "); // if no borrow replace accumulator with result
87 asm("movcs r8, r12 ");
88 asm("movcs r9, r14 ");
89 asm("adcs r4, r4, r4 "); // shift result left one, putting in next bit
90 asm("adcs r5, r5, r5 ");
91 asm("mov r9, r9, lsl #2 "); // shift acc:mant left by 2 bits
92 asm("orr r9, r9, r8, lsr #30 ");
93 asm("mov r8, r8, lsl #2 ");
94 asm("orr r8, r8, r7, lsr #30 ");
95 asm("mov r7, r7, lsl #2 ");
96 asm("orr r7, r7, r6, lsr #30 ");
97 asm("mov r6, r6, lsl #2 ");
98 asm("subs r3, r3, #1 "); // decrement loop counter
99 asm("bne fastsqrt3 "); // do necessary number of iterations
101 asm("movs r4, r4, lsr #1 "); // shift result mantissa right 1 place
102 asm("orr r4, r4, r5, lsl #31 "); // LSB (=rounding bit) into carry
103 asm("mov r5, r5, lsr #1 ");
104 asm("adcs r4, r4, #0 "); // round the mantissa to 53 bits
105 asm("adcs r5, r5, #0 ");
106 asm("cmp r5, #0x00200000 "); // check for mantissa overflow
107 asm("addeq r2, r2, #1 "); // if so, increment exponent - can never overflow
108 asm("bic r5, r5, #0x00300000 "); // remove top bit of mantissa - it is implicit
109 asm("add r2, r2, #0xFF "); // re-bias the exponent
110 asm("add r3, r2, #0x300 "); // and move into r3
111 asm("orr r3, r5, r3, lsl #20 "); // r3 now contains exponent + top of mantissa
112 asm("fastsqrt_ok: ");
113 #ifdef __DOUBLE_WORDS_SWAPPED__
114 asm("stmia r0, {r3,r4} "); // store the result
116 asm("str r3, [r0, #4] ");
117 asm("str r4, [r0, #0] ");
119 asm("mov r0, #0 "); // error code KErrNone
123 asm("orrs r6, r5, r4 "); // exponent zero - test mantissa
124 asm("beq fastsqrt_ok "); // if zero, return 0
126 asm("movs r3, r3 "); // denormal - test sign
127 asm("bmi fastsqrtn "); // branch out if negative
128 asm("sub r2, r2, #0xFE "); // unbias the exponent
129 asm("sub r2, r2, #0x300 "); //
131 asm("adds r4, r4, r4 "); // shift mantissa left
132 asm("adcs r5, r5, r5 ");
133 asm("sub r2, r2, #1 "); // and decrement exponent
134 asm("tst r5, #0x00100000 "); // test if normalised
135 asm("beq fastsqrtd "); // loop until normalised
136 asm("b fastsqrtd1 "); // now treat as a normalised number
137 asm("fastsqrt2: "); // get here if infinity or NaN
138 asm("orrs r6, r5, r4 "); // if mantissa zero, infinity
139 asm("bne fastsqrtnan "); // branch if not - must be NaN
140 asm("movs r3, r3 "); // test sign of infinity
141 asm("bmi fastsqrtn "); // branch if -ve
142 #ifdef __DOUBLE_WORDS_SWAPPED__
143 asm("stmia r0, {r3,r4} "); // store the result
145 asm("str r3, [r0, #4] ");
146 asm("str r4, [r0, #0] ");
148 asm("mov r0, #-9 "); // return KErrOverflow
149 asm("b fastsqrt_end ");
151 asm("fastsqrtn: "); // get here if negative or QNaN operand
152 asm("mov r3, #0xFF000000 "); // generate "real indefinite" QNaN
153 asm("orr r3, r3, #0x00F80000 "); // sign=1, exp=7FF, mantissa = 1000...0
156 #ifdef __DOUBLE_WORDS_SWAPPED__
157 asm("stmia r0, {r3,r4} "); // store the result
159 asm("str r3, [r0, #4] ");
160 asm("str r4, [r0, #0] ");
162 asm("mov r0, #-6 "); // return KErrArgument
163 asm("fastsqrt_end: ");
166 asm("fastsqrtnan: "); // operand is a NaN
167 asm("tst r5, #0x00080000 "); // test MSB of mantissa
168 asm("bne fastsqrtn "); // if set it is a QNaN - so return "real indefinite"
169 asm("bic r3, r3, #0x00080000 "); // else convert SNaN to QNaN
170 asm("b fastsqrtxa "); // and return KErrArgument
172 asm("Sqrt__FRdRCd_end: ");
176 __NAKED__ TUint Sqrt_Length()
178 asm("adr r0, Sqrt__FRdRCd_end ");
179 asm("adr r1, Sqrt__FRdRCd ");
180 asm("sub r0, r0, r1 ");
184 __NAKED__ TInt Divide(TRealX& /*aDividend*/, const TRealX& /*aDivisor*/)
186 asm("stmfd sp!, {r0,r4-r9,lr} ");
187 asm("ldmia r1, {r4,r5,r6} ");
188 asm("ldmia r0, {r1,r2,r3} ");
189 asm("bl TRealXDivide ");
190 asm("ldmfd sp!, {r0,r4-r9,lr} ");
191 asm("stmia r0, {r1,r2,r3} ");
195 // TRealX division r1,r2,r3 / r4,r5,r6 result in r1,r2,r3
196 // Error code returned in r12
197 // Registers r0-r9,r12 modified
198 // NB This function is purely internal to EUSER and therefore IS ONLY EVER CALLED IN ARM MODE.
199 asm("TRealXDivide: ");
200 asm("mov r12, #0 "); // initialise return value to KErrNone
201 asm("bic r3, r3, #0x300 "); // clear rounding flags
203 asm("eorne r3, r3, #1 "); // Exclusive-OR signs
204 asm("cmn r3, #0x10000 "); // check if dividend is NaN or infinity
205 asm("bcs TRealXDivide1 "); // branch if it is
206 asm("cmn r6, #0x10000 "); // check if divisor is NaN or infinity
207 asm("bcs TRealXDivide2 "); // branch if it is
208 asm("cmp r6, #0x10000 "); // check if divisor zero
209 asm("bcc TRealXDivide3 "); // branch if it is
210 asm("cmp r3, #0x10000 "); // check if dividend zero
211 __JUMP(cc,lr); // if zero, exit
213 asm("orrne lr, lr, #1 "); // save sign in bottom bit of lr
215 // calculate result exponent
216 asm("mov r0, r3, lsr #16 "); // r0=dividend exponent
217 asm("sub r0, r0, r6, lsr #16 "); // r0=dividend exponent - divisor exponent
218 asm("add r0, r0, #0x7F00 ");
219 asm("add r0, r0, #0x00FF "); // r0 now contains result exponent
220 asm("mov r6, r1 "); // move dividend into r6,r7,r8
222 asm("mov r8, #0 "); // use r8 to hold extra bit shifted up
223 // r2:r1 will hold result mantissa
224 asm("mov r2, #1 "); // we will make sure first bit is 1
225 asm("cmp r7, r5 "); // compare dividend mantissa to divisor mantissa
226 asm("cmpeq r6, r4 ");
227 asm("bcs TRealXDivide4 "); // branch if dividend >= divisor
228 asm("adds r6, r6, r6 "); // else shift dividend left one
229 asm("adcs r7, r7, r7 "); // ignore carry here
230 asm("sub r0, r0, #1 "); // decrement result exponent by one
231 asm("TRealXDivide4: ");
232 asm("subs r6, r6, r4 "); // subtract divisor from dividend
233 asm("sbcs r7, r7, r5 ");
235 // Main mantissa division code
236 // First calculate the top 32 bits of the result
237 // Top bit is 1, do 10 lots of 3 bits the one more bit
238 asm("mov r12, #10 ");
239 asm("TRealXDivide5: ");
240 asm("adds r6, r6, r6 "); // shift accumulator left by one
241 asm("adcs r7, r7, r7 ");
242 asm("adcs r8, r8, r8 ");
243 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
244 asm("sbcs r3, r7, r5 ");
245 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
246 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
247 asm("movcs r7, r3 ");
248 asm("adcs r2, r2, r2 "); // shift in new result bit
249 asm("adds r6, r6, r6 "); // shift accumulator left by one
250 asm("adcs r7, r7, r7 ");
251 asm("adcs r8, r8, r8 ");
252 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
253 asm("sbcs r3, r7, r5 ");
254 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
255 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
256 asm("movcs r7, r3 ");
257 asm("adcs r2, r2, r2 "); // shift in new result bit
258 asm("adds r6, r6, r6 "); // shift accumulator left by one
259 asm("adcs r7, r7, r7 ");
260 asm("adcs r8, r8, r8 ");
261 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
262 asm("sbcs r3, r7, r5 ");
263 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
264 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
265 asm("movcs r7, r3 ");
266 asm("adcs r2, r2, r2 "); // shift in new result bit
267 asm("subs r12, r12, #1 ");
268 asm("bne TRealXDivide5 "); // iterate the loop
269 asm("adds r6, r6, r6 "); // shift accumulator left by one
270 asm("adcs r7, r7, r7 ");
271 asm("adcs r8, r8, r8 ");
272 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
273 asm("sbcs r3, r7, r5 ");
274 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
275 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
276 asm("movcs r7, r3 ");
277 asm("adcs r2, r2, r2 "); // shift in new result bit - now have 32 bits
279 // Now calculate the bottom 32 bits of the result
280 // Do 8 lots of 4 bits
282 asm("TRealXDivide5a: ");
283 asm("adds r6, r6, r6 "); // shift accumulator left by one
284 asm("adcs r7, r7, r7 ");
285 asm("adcs r8, r8, r8 ");
286 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
287 asm("sbcs r3, r7, r5 ");
288 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
289 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
290 asm("movcs r7, r3 ");
291 asm("adcs r1, r1, r1 "); // shift in new result bit
292 asm("adds r6, r6, r6 "); // shift accumulator left by one
293 asm("adcs r7, r7, r7 ");
294 asm("adcs r8, r8, r8 ");
295 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
296 asm("sbcs r3, r7, r5 ");
297 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
298 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
299 asm("movcs r7, r3 ");
300 asm("adcs r1, r1, r1 "); // shift in new result bit
301 asm("adds r6, r6, r6 "); // shift accumulator left by one
302 asm("adcs r7, r7, r7 ");
303 asm("adcs r8, r8, r8 ");
304 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
305 asm("sbcs r3, r7, r5 ");
306 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
307 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
308 asm("movcs r7, r3 ");
309 asm("adcs r1, r1, r1 "); // shift in new result bit
310 asm("adds r6, r6, r6 "); // shift accumulator left by one
311 asm("adcs r7, r7, r7 ");
312 asm("adcs r8, r8, r8 ");
313 asm("subs r9, r6, r4 "); // subtract divisor from accumulator, result in r9,r3
314 asm("sbcs r3, r7, r5 ");
315 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
316 asm("movcs r6, r9 "); // if no borrow, replace accumulator with result
317 asm("movcs r7, r3 ");
318 asm("adcs r1, r1, r1 "); // shift in new result bit
319 asm("subs r12, r12, #1 ");
320 asm("bne TRealXDivide5a "); // iterate the loop
322 // r2:r1 now contains a 64-bit normalised mantissa
323 // need to do rounding now
324 asm("and r3, lr, #1 "); // result sign back into r3
325 asm("orrs r9, r6, r7 "); // check if accumulator zero
326 asm("beq TRealXDivide6 "); // if it is, result is exact, else generate next bit
327 asm("adds r6, r6, r6 "); // shift accumulator left by one
328 asm("adcs r7, r7, r7 ");
329 asm("adcs r8, r8, r8 ");
330 asm("subs r6, r6, r4 "); // subtract divisor from accumulator
331 asm("sbcs r7, r7, r5 ");
332 asm("movccs r8, r8, lsr #1 "); // if borrow, check for carry from shift
333 asm("orrcc r3, r3, #0x100 "); // if borrow, round down and set round-down flag
334 asm("bcc TRealXDivide6 ");
335 asm("orrs r9, r6, r7 "); // if no borrow, check if exactly half-way
336 asm("moveqs r9, r1, lsr #1 "); // if exactly half-way, round to even
337 asm("orrcc r3, r3, #0x100 "); // if C=0, round result down and set round-down flag
338 asm("bcc TRealXDivide6 ");
339 asm("orr r3, r3, #0x200 "); // else set round-up flag
340 asm("adds r1, r1, #1 "); // and round mantissa up
341 asm("adcs r2, r2, #0 ");
342 asm("movcs r2, #0x80000000 "); // if carry, mantissa = 80000000 00000000
343 asm("addcs r0, r0, #1 "); // and increment exponent
345 // check for overflow or underflow and assemble final result
346 asm("TRealXDivide6: ");
347 asm("add r4, r0, #1 "); // need to add 1 to get usable threshold
348 asm("cmp r4, #0x10000 "); // check if exponent >= 0xFFFF
349 asm("bge TRealXMultiply6 "); // if so, overflow
350 asm("cmp r0, #0 "); // check for underflow
351 asm("orrgt r3, r3, r0, lsl #16 "); // if no underflow, result exponent into r3, ...
352 asm("movgt r12, #0 "); // ... return KErrNone ...
356 asm("and r3, r3, #1 "); // set exponent=0, keep sign
357 asm("mvn r12, #9 "); // return KErrUnderflow
360 // come here if divisor is zero, dividend finite
361 asm("TRealXDivide3: ");
362 asm("cmp r3, #0x10000 "); // check if dividend also zero
363 asm("bcc TRealXRealIndefinite "); // if so, return 'real indefinite'
364 asm("orr r3, r3, #0xFF000000 "); // else return infinity with xor sign
365 asm("orr r3, r3, #0x00FF0000 ");
366 asm("mov r2, #0x80000000 ");
368 asm("mvn r12, #40 "); // return KErrDivideByZero
371 // Dividend is NaN or infinity
372 asm("TRealXDivide1: ");
373 asm("cmp r2, #0x80000000 "); // check for infinity
374 asm("cmpeq r1, #0 ");
375 asm("bne TRealXBinOpNan "); // branch if NaN
376 asm("cmn r6, #0x10000 "); // check 2nd operand for NaN/infinity
377 asm("mvncc r12, #8 "); // if not, return KErrOverflow
380 // Dividend=infinity, divisor=NaN or infinity
381 asm("cmp r5, #0x80000000 "); // check 2nd operand for infinity
382 asm("cmpeq r4, #0 ");
383 asm("bne TRealXBinOpNan "); // branch if NaN
384 asm("b TRealXRealIndefinite "); // else return 'real indefinite'
386 // Divisor is NaN or infinity, dividend finite
387 asm("TRealXDivide2: ");
388 asm("cmp r5, #0x80000000 "); // check for infinity
389 asm("cmpeq r4, #0 ");
390 asm("bne TRealXBinOpNan "); // branch if NaN
391 asm("and r3, r3, #1 "); // else return zero with xor sign
394 asm("TRealXBinOpNan: "); // generic routine to process NaNs in binary
396 asm("cmn r3, #0x10000 "); // check if first operand is NaN
397 asm("movcc r0, r1 "); // if not, swap the operands
398 asm("movcc r1, r4 ");
399 asm("movcc r4, r0 ");
400 asm("movcc r0, r2 ");
401 asm("movcc r2, r5 ");
402 asm("movcc r5, r0 ");
403 asm("movcc r0, r3 ");
404 asm("movcc r3, r6 ");
405 asm("movcc r6, r0 ");
406 asm("cmn r6, #0x10000 "); // both operands NaNs?
407 asm("bcc TRealXBinOpNan1 "); // skip if not
408 asm("cmp r2, r5 "); // if so, compare the significands
409 asm("cmpeq r1, r4 ");
410 asm("movcc r1, r4 "); // r1,r2,r3 will get NaN with larger significand
411 asm("movcc r2, r5 ");
412 asm("movcc r3, r6 ");
413 asm("TRealXBinOpNan1: ");
414 asm("orr r2, r2, #0x40000000 "); // convert an SNaN to a QNaN
415 asm("mvn r12, #5 "); // return KErrArgument
418 // Return 'real indefinite'
419 asm("TRealXRealIndefinite: ");
420 asm("ldr r3, __RealIndefiniteExponent ");
421 asm("mov r2, #0xC0000000 ");
423 asm("mvn r12, #5 "); // return KErrArgument
427 asm("TRealXMultiply6: ");
428 asm("bic r3, r3, #0x0000FF00 "); // clear rounding flags
429 asm("orr r3, r3, #0xFF000000 "); // make exponent FFFF for infinity
430 asm("orr r3, r3, #0x00FF0000 ");
431 asm("mov r2, #0x80000000 "); // mantissa = 80000000 00000000
433 asm("mvn r12, #8 "); // return KErrOverflow
436 asm("__RealIndefiniteExponent: ");
437 asm(".word 0xFFFF0001 ");
439 asm("Divide__FR6TRealXRC6TRealX_end: ");
442 __NAKED__ TUint Divide_Length()
444 asm("adr r0, Divide__FR6TRealXRC6TRealX_end ");
445 asm("adr r1, Divide__FR6TRealXRC6TRealX ");
446 asm("sub r0, r0, r1 ");
450 __NAKED__ TInt SDummy(TInt)
453 asm("SDummy__Fi_end: ");
456 __NAKED__ TUint SDummy_Length()
458 asm("adr r0, SDummy__Fi_end ");
459 asm("adr r1, SDummy__Fi ");
460 asm("sub r0, r0, r1 ");
464 __NAKED__ TInt Increment(TInt)
466 asm("add r0, r0, #1 ");
468 asm("Increment__Fi_end: ");
471 __NAKED__ TUint Increment_Length()
473 asm("adr r0, Increment__Fi_end ");
474 asm("adr r1, Increment__Fi ");
475 asm("sub r0, r0, r1 ");