|
1 // Copyright (c) 2007-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 "Symbian Foundation License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\euser\epoc\x86\uc_i64.cia |
|
15 // |
|
16 // |
|
17 |
|
18 #include "u32std.h" |
|
19 #include <e32math.h> |
|
20 |
|
21 extern "C" void UDiv64(); |
|
22 |
|
23 EXPORT_C __NAKED__ void Math::Mul64(Int64 /*aX*/, Int64 /*aY*/, Int64& /*aOutH*/, Uint64& /*aOutL*/) |
|
24 /** |
|
25 Multiply aX by aY to generate a 128 bit result. |
|
26 |
|
27 The high order 64 bits of this calculation are stored in aOutH, |
|
28 and the low order 64 bits are stored in aOutL. |
|
29 |
|
30 @param aX The first 64-bit operand. |
|
31 @param aY The second 64-bit operand. |
|
32 @param aOutH The high order 64 bits of the result. |
|
33 @param aOutL The low order 64 bits of the result. |
|
34 */ |
|
35 { |
|
36 asm("mov eax, [esp+4]"); |
|
37 asm("mul dword ptr [esp+12]"); // edx:eax = x0*y0 |
|
38 asm("push edi"); |
|
39 asm("push esi"); |
|
40 asm("push ebx"); // [esp+16]=&aX, [esp+24]=&aY, [esp+32]=&aOutH, [esp+36]=&aOutL |
|
41 asm("mov ecx, eax"); |
|
42 asm("mov ebx, edx"); // ebx:ecx = x0*y0 |
|
43 asm("mov eax, [esp+16]"); |
|
44 asm("mul dword ptr [esp+28]"); // edx:eax = x0*y1 |
|
45 asm("xor esi, esi"); |
|
46 asm("add ebx, eax"); |
|
47 asm("adc esi, edx"); // esi:ebx:ecx = x0*y |
|
48 asm("mov eax, [esp+20]"); // eax=x1 |
|
49 asm("imul dword ptr [esp+28]"); // edx:eax = x1*y1 |
|
50 asm("mov edi, edx"); |
|
51 asm("add esi, eax"); |
|
52 asm("adc edi, 0"); // partial result in edi:esi:ebx:ecx |
|
53 asm("cmp dword ptr [esp+28],0");// y<0 ? |
|
54 asm("jns mul64_ypos"); |
|
55 asm("sub esi, [esp+16]"); // if so, subtract x0<<64 |
|
56 asm("sbb edi, 0"); |
|
57 asm("mul64_ypos:"); |
|
58 asm("mov eax, [esp+20]"); // eax=x1 |
|
59 asm("cmp eax, 0"); // x<0 ? |
|
60 asm("jns mul64_xpos"); |
|
61 asm("sub esi, [esp+24]"); // if so, subtract y0<<64 |
|
62 asm("sbb edi, 0"); |
|
63 asm("mul64_xpos:"); |
|
64 asm("mul dword ptr [esp+24]"); // edx:eax = x1*y0 |
|
65 asm("add ebx, eax"); |
|
66 asm("mov eax, [esp+32]"); // eax=&aOutH |
|
67 asm("adc esi, edx"); |
|
68 asm("mov edx, [esp+36]"); // edx=&aOutL |
|
69 asm("adc edi, 0"); // full result now in edi:esi:ebx:ecx |
|
70 asm("mov [eax], esi"); |
|
71 asm("mov [eax+4], edi"); // store high 64 |
|
72 asm("mov [edx], ecx"); |
|
73 asm("mov [edx+4], ebx"); // store low 64 |
|
74 asm("pop ebx"); |
|
75 asm("pop esi"); |
|
76 asm("pop edi"); |
|
77 asm("ret"); |
|
78 } |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 EXPORT_C __NAKED__ void Math::UMul64(Uint64 /*aX*/, Uint64 /*aY*/, Uint64& /*aOutH*/, Uint64& /*aOutL*/) |
|
84 /** |
|
85 Multiply aX by aY to generate a 128 bit result. |
|
86 |
|
87 The high order 64 bits of this calculation are stored in aOutH, |
|
88 and the low order 64 bits are stored in aOutL. |
|
89 |
|
90 @param aX The first 64-bit operand. |
|
91 @param aY The second 64-bit operand. |
|
92 @param aOutH The high order 64 bits of the result. |
|
93 @param aOutL The low order 64 bits of the result. |
|
94 */ |
|
95 { |
|
96 asm("mov eax, [esp+4]"); |
|
97 asm("mul dword ptr [esp+12]"); // edx:eax = x0*y0 |
|
98 asm("push edi"); |
|
99 asm("push esi"); |
|
100 asm("push ebx"); // [esp+16]=&aX, [esp+24]=&aY, [esp+32]=&aOutH, [esp+36]=&aOutL |
|
101 asm("mov ecx, eax"); |
|
102 asm("mov ebx, edx"); // ebx:ecx = x0*y0 |
|
103 asm("mov eax, [esp+16]"); |
|
104 asm("mul dword ptr [esp+28]"); // edx:eax = x0*y1 |
|
105 asm("xor esi, esi"); |
|
106 asm("add ebx, eax"); |
|
107 asm("adc esi, edx"); // esi:ebx:ecx = x0*y |
|
108 asm("mov eax, [esp+20]"); // eax=x1 |
|
109 asm("mul dword ptr [esp+28]"); // edx:eax = x1*y1 |
|
110 asm("mov edi, edx"); |
|
111 asm("add esi, eax"); |
|
112 asm("adc edi, 0"); // partial result in edi:esi:ebx:ecx |
|
113 asm("mov eax, [esp+20]"); |
|
114 asm("mul dword ptr [esp+24]"); // edx:eax = x1*y0 |
|
115 asm("add ebx, eax"); |
|
116 asm("mov eax, [esp+32]"); // eax=&aOutH |
|
117 asm("adc esi, edx"); |
|
118 asm("mov edx, [esp+36]"); // edx=&aOutL |
|
119 asm("adc edi, 0"); // full result now in edi:esi:ebx:ecx |
|
120 asm("mov [eax], esi"); |
|
121 asm("mov [eax+4], edi"); // store high 64 |
|
122 asm("mov [edx], ecx"); |
|
123 asm("mov [edx+4], ebx"); // store low 64 |
|
124 asm("pop ebx"); |
|
125 asm("pop esi"); |
|
126 asm("pop edi"); |
|
127 asm("ret"); |
|
128 } |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 EXPORT_C __NAKED__ Int64 Math::DivMod64(Int64 /*aDividend*/, Int64 /*aDivisor*/, Int64& /*aRemainder*/) |
|
134 /** |
|
135 Divides aDividend by aDivisor. |
|
136 |
|
137 The quotient is returned, and the remainder is stored in aRemainder. |
|
138 The remainder has same sign as the dividend. |
|
139 |
|
140 @param aDividend The 64-bit dividend. |
|
141 @param aDivisor The 64-bit divisor. |
|
142 @param aRemainder The 64-bit remainder. |
|
143 |
|
144 @return The 64-bit quotient. |
|
145 */ |
|
146 { |
|
147 asm("mov eax, [esp+4]"); |
|
148 asm("mov edx, [esp+8]"); // edx:eax = dividend |
|
149 asm("cmp edx, 0"); |
|
150 asm("jns divmod64_0"); |
|
151 asm("neg edx"); |
|
152 asm("neg eax"); |
|
153 asm("sbb edx, 0"); |
|
154 |
|
155 asm("divmod64_0:"); // edx:eax = ABS{dividend} |
|
156 asm("push edi"); |
|
157 asm("push esi"); |
|
158 asm("push ebx"); |
|
159 asm("push ebp"); |
|
160 asm("mov esi, [esp+28]"); |
|
161 asm("mov edi, [esp+32]"); // edi:esi = dividend |
|
162 asm("cmp edi, 0"); |
|
163 asm("jns divmod64_1"); |
|
164 asm("neg edi"); |
|
165 asm("neg esi"); |
|
166 asm("sbb edi, 0"); // edi:esi = ABS{dividend} |
|
167 |
|
168 asm("divmod64_1:"); |
|
169 asm("call %a0": : "i"(&UDiv64)); // do division, quotient in ebx:eax remainder in edi:edx |
|
170 asm("xchg ebx, edx"); // quotient in edx:eax, remainder in edi:ebx |
|
171 asm("mov ecx, [esp+24]"); // ecx=dividend high |
|
172 asm("xor ecx, [esp+32]"); // ecx=dividend high ^ divisor high |
|
173 asm("jns divmod64_2"); |
|
174 asm("neg edx"); |
|
175 asm("neg eax"); |
|
176 asm("sbb edx, 0"); |
|
177 |
|
178 asm("divmod64_2:"); // edx:eax = quotient with correct sign |
|
179 asm("cmp dword ptr [esp+24], 0"); |
|
180 asm("jns divmod64_3"); |
|
181 asm("neg edi"); |
|
182 asm("neg ebx"); |
|
183 asm("sbb edi, 0"); |
|
184 |
|
185 asm("divmod64_3:"); // edi:ebx = remainder with correct sign |
|
186 asm("mov ecx, [esp+36]"); // ecx=&aRemainder |
|
187 asm("mov [ecx], ebx"); |
|
188 asm("mov [ecx+4], edi"); |
|
189 asm("pop ebp"); |
|
190 asm("pop ebx"); |
|
191 asm("pop esi"); |
|
192 asm("pop edi"); |
|
193 asm("ret"); |
|
194 } |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 EXPORT_C __NAKED__ Uint64 Math::UDivMod64(Uint64 /*aDividend*/, Uint64 /*aDivisor*/, Uint64& /*aRemainder*/) |
|
200 /** |
|
201 Divides aDividend by aDivisor. |
|
202 |
|
203 The quotient is returned, and the remainder is stored in aRemainder. |
|
204 |
|
205 @param aDividend The 64-bit dividend. |
|
206 @param aDivisor The 64-bit divisor. |
|
207 @param aRemainder The 64-bit remainder. |
|
208 |
|
209 @return The 64-bit quotient. |
|
210 */ |
|
211 { |
|
212 asm("mov eax, [esp+4]"); |
|
213 asm("mov edx, [esp+8]"); // edx:eax = dividend |
|
214 asm("push edi"); |
|
215 asm("push esi"); |
|
216 asm("push ebx"); |
|
217 asm("push ebp"); |
|
218 asm("mov esi, [esp+28]"); |
|
219 asm("mov edi, [esp+32]"); // edi:esi = dividend |
|
220 asm("call %a0": : "i"(&UDiv64)); // do division, quotient in ebx:eax remainder in edi:edx |
|
221 asm("xchg ebx, edx"); // quotient in edx:eax, remainder in edi:ebx |
|
222 asm("mov ecx, [esp+36]"); // ecx=&aRemainder |
|
223 asm("mov [ecx], ebx"); |
|
224 asm("mov [ecx+4], edi"); |
|
225 asm("pop ebp"); |
|
226 asm("pop ebx"); |
|
227 asm("pop esi"); |
|
228 asm("pop edi"); |
|
229 asm("ret"); |
|
230 } |
|
231 |
|
232 |
|
233 |