]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
Initial import.
[mirror_edk2.git] / EdkModulePkg / Universal / Ebc / Dxe / Ia32 / Ia32Math.asm
CommitLineData
878ddf1f 1 TITLE Ia32math.asm: Generic math routines for EBC interpreter running on IA32 processor\r
2\r
3;------------------------------------------------------------------------------\r
4;\r
5; Copyright (c) 2006, Intel Corporation \r
6; All rights reserved. This program and the accompanying materials \r
7; are licensed and made available under the terms and conditions of the BSD License \r
8; which accompanies this distribution. The full text of the license may be found at \r
9; http://opensource.org/licenses/bsd-license.php \r
10; \r
11; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13; \r
14; Module Name:\r
15;\r
16; Ia32math.asm\r
17; \r
18; Abstract:\r
19; \r
20; Generic math routines for EBC interpreter running on IA32 processor\r
21;\r
22;------------------------------------------------------------------------------\r
23\r
24 .686P\r
25 .XMM\r
26 .MODEL SMALL\r
27 .CODE\r
28\r
29LeftShiftU64 PROTO C Operand: QWORD, CountIn: QWORD\r
30RightShiftU64 PROTO C Operand: QWORD, CountIn: QWORD\r
31ARightShift64 PROTO C Operand: QWORD, CountIn: QWORD\r
32MulU64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
33MulS64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
34DivU64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD\r
35DivS64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD\r
36\r
37 \r
38LeftShiftU64 PROC C Operand: QWORD, CountIn: QWORD\r
39\r
40;------------------------------------------------------------------------------\r
41; UINT64\r
42; LeftShiftU64 (\r
43; IN UINT64 Operand,\r
44; IN UINT64 CountIn\r
45; )\r
46;\r
47; Routine Description:\r
48; \r
49; Left-shift a 64-bit value.\r
50;\r
51; Arguments:\r
52;\r
53; Operand - the value to shift\r
54; Count - shift count\r
55;\r
56; Returns:\r
57;\r
58; Operand << Count\r
59;------------------------------------------------------------------------------\r
60\r
61 push ecx\r
62 ;\r
63 ; if (CountIn > 63) return 0;\r
64 ;\r
65 cmp dword ptr CountIn[4], 0\r
66 jne _LeftShiftU64_Overflow\r
67 mov ecx, dword ptr CountIn[0]\r
68 cmp ecx, 63\r
69 jbe _LeftShiftU64_Calc\r
70 \r
71_LeftShiftU64_Overflow:\r
72 xor eax, eax\r
73 xor edx, edx\r
74 jmp _LeftShiftU64_Done\r
75 \r
76_LeftShiftU64_Calc:\r
77 mov eax, dword ptr Operand[0]\r
78 mov edx, dword ptr Operand[4]\r
79 \r
80 shld edx, eax, cl\r
81 shl eax, cl\r
82 cmp ecx, 32\r
83 jc short _LeftShiftU64_Done\r
84 \r
85 mov edx, eax\r
86 xor eax, eax\r
87 \r
88_LeftShiftU64_Done:\r
89 pop ecx\r
90 ret\r
91\r
92LeftShiftU64 ENDP\r
93\r
94\r
95RightShiftU64 PROC C Operand: QWORD, CountIn: QWORD\r
96\r
97;------------------------------------------------------------------------------\r
98; UINT64\r
99; RightShiftU64 (\r
100; IN UINT64 Operand,\r
101; IN UINT64 CountIn\r
102; )\r
103;\r
104; Routine Description:\r
105; \r
106; Right-shift an unsigned 64-bit value.\r
107;\r
108; Arguments:\r
109;\r
110; Operand - the value to shift\r
111; Count - shift count\r
112;\r
113; Returns:\r
114;\r
115; Operand >> Count\r
116;------------------------------------------------------------------------------\r
117\r
118 push ecx\r
119 ;\r
120 ; if (CountIn > 63) return 0;\r
121 ;\r
122 cmp dword ptr CountIn[4], 0\r
123 jne _RightShiftU64_Overflow\r
124 mov ecx, dword ptr CountIn[0]\r
125 cmp ecx, 63\r
126 jbe _RightShiftU64_Calc\r
127 \r
128_RightShiftU64_Overflow:\r
129 xor eax, eax\r
130 xor edx, edx\r
131 jmp _RightShiftU64_Done\r
132 \r
133_RightShiftU64_Calc:\r
134 mov eax, dword ptr Operand[0]\r
135 mov edx, dword ptr Operand[4]\r
136 \r
137 shrd edx, eax, cl\r
138 shr eax, cl\r
139 cmp ecx, 32\r
140 jc short _RightShiftU64_Done\r
141 \r
142 mov eax, edx\r
143 xor edx, edx\r
144 \r
145_RightShiftU64_Done:\r
146 pop ecx\r
147 ret\r
148\r
149RightShiftU64 ENDP\r
150\r
151\r
152ARightShift64 PROC C Operand: QWORD, CountIn: QWORD\r
153\r
154;------------------------------------------------------------------------------\r
155; INT64\r
156; ARightShift64 (\r
157; IN INT64 Operand,\r
158; IN UINT64 CountIn\r
159; )\r
160;\r
161; Routine Description:\r
162; \r
163; Arithmatic shift a 64 bit signed value.\r
164;\r
165; Arguments:\r
166;\r
167; Operand - the value to shift\r
168; Count - shift count\r
169;\r
170; Returns:\r
171;\r
172; Operand >> Count\r
173;------------------------------------------------------------------------------\r
174\r
175 push ecx\r
176 ;\r
177 ; If they exceeded the max shift count, then return either 0 or all F's\r
178 ; depending on the sign bit.\r
179 ;\r
180 cmp dword ptr CountIn[4], 0\r
181 jne _ARightShiftU64_Overflow\r
182 mov ecx, dword ptr CountIn[0]\r
183 cmp ecx, 63\r
184 jbe _ARightShiftU64_Calc\r
185 \r
186_ARightShiftU64_Overflow:\r
187 ;\r
188 ; Check the sign bit of Operand\r
189 ;\r
190 bt dword ptr Operand[4], 31\r
191 jnc _ARightShiftU64_Return_Zero\r
192 ;\r
193 ; return -1\r
194 ;\r
195 or eax, 0FFFFFFFFh\r
196 or edx, 0FFFFFFFFh\r
197 jmp _ARightShiftU64_Done\r
198\r
199_ARightShiftU64_Return_Zero:\r
200 xor eax, eax\r
201 xor edx, edx\r
202 jmp _ARightShiftU64_Done\r
203 \r
204_ARightShiftU64_Calc:\r
205 mov eax, dword ptr Operand[0]\r
206 mov edx, dword ptr Operand[4]\r
207\r
208 shrd eax, edx, cl\r
209 sar edx, cl\r
210 cmp ecx, 32\r
211 jc short _ARightShiftU64_Done\r
212\r
213 ;\r
214 ; if ecx >= 32, then eax = edx, and edx = sign bit\r
215 ;\r
216 mov eax, edx\r
217 sar edx, 31\r
218\r
219_ARightShiftU64_Done:\r
220 pop ecx\r
221 ret\r
222\r
223ARightShift64 ENDP\r
224\r
225\r
226MulU64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
227\r
228;------------------------------------------------------------------------------\r
229; UINT64 \r
230; MulU64x64 (\r
231; UINT64 Value1, \r
232; UINT64 Value2, \r
233; UINT64 *ResultHigh\r
234; )\r
235;\r
236; Routine Description:\r
237; \r
238; Multiply two unsigned 64-bit values.\r
239;\r
240; Arguments:\r
241;\r
242; Value1 - first value to multiply\r
243; Value2 - value to multiply by Value1\r
244; ResultHigh - result to flag overflows\r
245;\r
246; Returns:\r
247; \r
248; Value1 * Value2\r
249; The 128-bit result is the concatenation of *ResultHigh and the return value \r
250;------------------------------------------------------------------------------\r
251\r
252 push ebx\r
253 push ecx\r
254 mov ebx, ResultHigh ; ebx points to the high 4 words of result\r
255 ;\r
256 ; The result consists of four double-words.\r
257 ; Here we assume their names from low to high: dw0, dw1, dw2, dw3\r
258 ;\r
259 mov eax, dword ptr Value1[0]\r
260 mul dword ptr Value2[0]\r
261 push eax ; eax contains final result of dw0, push it\r
262 mov ecx, edx ; ecx contains partial result of dw1\r
263 \r
264 mov eax, dword ptr Value1[4]\r
265 mul dword ptr Value2[0]\r
266 add ecx, eax ; add eax to partial result of dw1\r
267 adc edx, 0 \r
268 mov dword ptr [ebx], edx ; lower double-word of ResultHigh contains partial result of dw2\r
269 \r
270 mov eax, dword ptr Value1[0]\r
271 mul dword ptr Value2[4]\r
272 add ecx, eax ; add eax to partial result of dw1\r
273 push ecx ; ecx contains final result of dw1, push it\r
274 adc edx, 0\r
275 mov ecx, edx ; ecx contains partial result of dw2, together with ResultHigh\r
276\r
277 mov eax, dword ptr Value1[4]\r
278 mul dword ptr Value2[4]\r
279 add ecx, eax ; add eax to partial result of dw2\r
280 adc edx, 0\r
281 add dword ptr [ebx], ecx ; lower double-word of ResultHigh contains final result of dw2\r
282 adc edx, 0\r
283 mov dword ptr [ebx + 4], edx ; high double-word of ResultHigh contains final result of dw3\r
284 \r
285 pop edx ; edx contains the final result of dw1\r
286 pop eax ; edx contains the final result of dw0\r
287 pop ecx\r
288 pop ebx\r
289 ret\r
290\r
291MulU64x64 ENDP\r
292\r
293\r
294MulS64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
295\r
296;------------------------------------------------------------------------------\r
297; INT64\r
298; MulS64x64 (\r
299; INT64 Value1,\r
300; INT64 Value2,\r
301; INT64 *ResultHigh\r
302; )\r
303;\r
304; Routine Description:\r
305; \r
306; Multiply two signed 64-bit values.\r
307;\r
308; Arguments:\r
309;\r
310; Value1 - first value to multiply\r
311; Value2 - value to multiply by Value1\r
312; ResultHigh - result to flag overflows\r
313;\r
314; Returns:\r
315;\r
316; Value1 * Value2\r
317; The 128-bit result is the concatenation of *ResultHigh and the return value \r
318;------------------------------------------------------------------------------\r
319\r
320 push ebx\r
321 push ecx\r
322 mov ebx, ResultHigh ; ebx points to the high 4 words of result\r
323 xor ecx, ecx ; the lowest bit of ecx flags the sign\r
324 \r
325 mov edx, dword ptr Value1[4]\r
326 bt edx, 31\r
327 jnc short _MulS64x64_A_Positive\r
328 ;\r
329 ; a is negative\r
330 ;\r
331 mov eax, dword ptr Value1[0]\r
332 not edx\r
333 not eax\r
334 add eax, 1\r
335 adc edx, 0\r
336 mov dword ptr Value1[0], eax\r
337 mov dword ptr Value1[4], edx\r
338 btc ecx, 0\r
339 \r
340_MulS64x64_A_Positive:\r
341 mov edx, dword ptr Value2[4]\r
342 bt edx, 31\r
343 jnc short _MulS64x64_B_Positive\r
344 ;\r
345 ; b is negative\r
346 ;\r
347 mov eax, dword ptr Value2[0]\r
348 not edx\r
349 not eax\r
350 add eax, 1\r
351 adc edx, 0\r
352 mov dword ptr Value2[0], eax\r
353 mov dword ptr Value2[4], edx\r
354 btc ecx, 0\r
355 \r
356_MulS64x64_B_Positive:\r
357 invoke MulU64x64, Value1, Value2, ResultHigh\r
358 bt ecx, 0\r
359 jnc short _MulS64x64_Done\r
360 ;\r
361 ;negate the result\r
362 ;\r
363 not eax\r
364 not edx\r
365 not dword ptr [ebx]\r
366 not dword ptr [ebx + 4]\r
367 add eax, 1\r
368 adc edx, 0\r
369 adc dword ptr [ebx], 0\r
370 adc dword ptr [ebx + 4], 0\r
371 \r
372_MulS64x64_Done:\r
373 pop ecx\r
374 pop ebx\r
375 ret\r
376\r
377MulS64x64 ENDP\r
378\r
379\r
380DivU64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD, \r
381\r
382;------------------------------------------------------------------------------\r
383; UINT64\r
384; DivU64x64 (\r
385; IN UINT64 Dividend,\r
386; IN UINT64 Divisor,\r
387; OUT UINT64 *Remainder OPTIONAL,\r
388; OUT UINT32 *Error\r
389; )\r
390;\r
391; Routine Description:\r
392; \r
393; This routine allows a 64 bit value to be divided with a 64 bit value returns \r
394; 64bit result and the Remainder\r
395;\r
396; Arguments:\r
397;\r
398; Dividend - dividend\r
399; Divisor - divisor\r
400; ResultHigh - result to flag overflows\r
401; Error - flag for error\r
402;\r
403; Returns:\r
404; \r
405; Dividend / Divisor\r
406; Remainder = Dividend mod Divisor\r
407;------------------------------------------------------------------------------\r
408\r
409 push ecx\r
410 \r
411 mov eax, Error\r
412 mov dword ptr [eax], 0 \r
413 \r
414 cmp dword ptr Divisor[0], 0\r
415 jne _DivU64x64_Valid\r
416 cmp dword ptr Divisor[4], 0\r
417 jne _DivU64x64_Valid\r
418 ;\r
419 ; the divisor is zero\r
420 ;\r
421 mov dword ptr [eax], 1 \r
422 cmp Remainder, 0\r
423 je _DivU64x64_Invalid_Return\r
424 ;\r
425 ; fill the remainder if the pointer is not null\r
426 ;\r
427 mov eax, Remainder\r
428 mov dword ptr [eax], 0\r
429 mov dword ptr [eax + 4], 80000000h\r
430 \r
431_DivU64x64_Invalid_Return:\r
432 xor eax, eax\r
433 mov edx, 80000000h\r
434 jmp _DivU64x64_Done\r
435\r
436_DivU64x64_Valid:\r
437 ;\r
438 ; let edx and eax contain the intermediate result of remainder\r
439 ;\r
440 xor edx, edx\r
441 xor eax, eax\r
442 mov ecx, 64\r
443 \r
444_DivU64x64_Wend:\r
445 ;\r
446 ; shift dividend left one\r
447 ;\r
448 shl dword ptr Dividend[0], 1\r
449 rcl dword ptr Dividend[4], 1 \r
450 ;\r
451 ; rotate intermediate result of remainder left one\r
452 ;\r
453 rcl eax, 1\r
454 rcl edx, 1 \r
455 \r
456 cmp edx, dword ptr Divisor[4]\r
457 ja _DivU64x64_Sub_Divisor\r
458 jb _DivU64x64_Cont\r
459 cmp eax, dword ptr Divisor[0]\r
460 jb _DivU64x64_Cont\r
461 \r
462_DivU64x64_Sub_Divisor:\r
463 ;\r
464 ; If intermediate result of remainder is larger than\r
465 ; or equal to divisor, then set the lowest bit of dividend,\r
466 ; and subtract divisor from intermediate remainder\r
467 ;\r
468 bts dword ptr Dividend[0], 0\r
469 sub eax, dword ptr Divisor[0]\r
470 sbb edx, dword ptr Divisor[4]\r
471 \r
472_DivU64x64_Cont:\r
473 loop _DivU64x64_Wend\r
474 \r
475 cmp Remainder, 0\r
476 je _DivU64x64_Assign\r
477 mov ecx, Remainder\r
478 mov dword ptr [ecx], eax\r
479 mov dword ptr [ecx + 4], edx\r
480 \r
481_DivU64x64_Assign:\r
482 mov eax, dword ptr Dividend[0]\r
483 mov edx, dword ptr Dividend[4]\r
484 \r
485_DivU64x64_Done:\r
486 pop ecx\r
487 ret\r
488 \r
489DivU64x64 ENDP\r
490\r
491DivS64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD, \r
492\r
493;------------------------------------------------------------------------------\r
494; INT64\r
495; DivU64x64 (\r
496; IN INT64 Dividend,\r
497; IN INT64 Divisor,\r
498; OUT UINT64 *Remainder OPTIONAL,\r
499; OUT UINT32 *Error\r
500; )\r
501;\r
502; Routine Description:\r
503; \r
504; This routine allows a 64 bit signed value to be divided with a 64 bit \r
505; signed value returns 64bit result and the Remainder.\r
506;\r
507; Arguments:\r
508;\r
509; Dividend - dividend\r
510; Divisor - divisor\r
511; ResultHigh - result to flag overflows\r
512; Error - flag for error\r
513;\r
514; Returns:\r
515; \r
516; Dividend / Divisor\r
517; Remainder = Dividend mod Divisor\r
518;------------------------------------------------------------------------------\r
519\r
520 push ecx\r
521 \r
522 mov eax, Error\r
523 mov dword ptr [eax], 0 \r
524 \r
525 cmp dword ptr Divisor[0], 0\r
526 jne _DivS64x64_Valid\r
527 cmp dword ptr Divisor[4], 0\r
528 jne _DivS64x64_Valid\r
529 ;\r
530 ; the divisor is zero\r
531 ;\r
532 mov dword ptr [eax], 1 \r
533 cmp Remainder, 0\r
534 je _DivS64x64_Invalid_Return\r
535 ;\r
536 ; fill the remainder if the pointer is not null\r
537 ;\r
538 mov eax, Remainder\r
539 mov dword ptr [eax], 0\r
540 mov dword ptr [eax + 4], 80000000h\r
541 \r
542_DivS64x64_Invalid_Return:\r
543 xor eax, eax\r
544 mov edx, 80000000h\r
545 jmp _DivS64x64_Done\r
546\r
547_DivS64x64_Valid:\r
548 ;\r
549 ; The lowest bit of ecx flags the sign of quotient,\r
550 ; The seconde lowest bit flags the sign of remainder\r
551 ;\r
552 xor ecx, ecx \r
553 \r
554 mov edx, dword ptr Dividend[4]\r
555 bt edx, 31\r
556 jnc short _DivS64x64_Dividend_Positive\r
557 ;\r
558 ; dividend is negative\r
559 ;\r
560 mov eax, dword ptr Dividend[0]\r
561 not edx\r
562 not eax\r
563 add eax, 1\r
564 adc edx, 0\r
565 mov dword ptr Dividend[0], eax\r
566 mov dword ptr Dividend[4], edx\r
567 ;\r
568 ; set both the flags for signs of quotient and remainder\r
569 ;\r
570 btc ecx, 0\r
571 btc ecx, 1\r
572 \r
573_DivS64x64_Dividend_Positive:\r
574 mov edx, dword ptr Divisor[4]\r
575 bt edx, 31\r
576 jnc short _DivS64x64_Divisor_Positive\r
577 ;\r
578 ; divisor is negative\r
579 ;\r
580 mov eax, dword ptr Divisor[0]\r
581 not edx\r
582 not eax\r
583 add eax, 1\r
584 adc edx, 0\r
585 mov dword ptr Divisor[0], eax\r
586 mov dword ptr Divisor[4], edx\r
587 ;\r
588 ; just complement the flag for sign of quotient\r
589 ;\r
590 btc ecx, 0\r
591 \r
592_DivS64x64_Divisor_Positive:\r
593 invoke DivU64x64, Dividend, Divisor, Remainder, Error\r
594 bt ecx, 0\r
595 jnc short _DivS64x64_Remainder\r
596 ;\r
597 ; negate the quotient\r
598 ;\r
599 not eax\r
600 not edx\r
601 add eax, 1\r
602 adc edx, 0\r
603 \r
604_DivS64x64_Remainder:\r
605 bt ecx, 1\r
606 jnc short _DivS64x64_Done\r
607 ;\r
608 ; negate the remainder\r
609 ;\r
610 mov ecx, remainder\r
611 not dword ptr [ecx]\r
612 not dword ptr [ecx + 4]\r
613 add dword ptr [ecx], 1\r
614 adc dword ptr [ecx + 4], 0\r
615 \r
616_DivS64x64_Done:\r
617 pop ecx\r
618 ret\r
619\r
620DivS64x64 ENDP\r
621\r
622END