1 TITLE Ia32math.asm: Generic math routines for EBC interpreter running on IA32 processor
3 ;------------------------------------------------------------------------------
5 ; Copyright (c) 2006, Intel Corporation
6 ; All rights reserved. This program and the accompanying materials
7 ; are licensed and made available under the terms and conditions of the BSD License
8 ; which accompanies this distribution. The full text of the license may be found at
9 ; http://opensource.org/licenses/bsd-license.php
11 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 ; Generic math routines for EBC interpreter running on IA32 processor
22 ;------------------------------------------------------------------------------
29 LeftShiftU64 PROTO C Operand: QWORD, CountIn: QWORD
30 RightShiftU64 PROTO C Operand: QWORD, CountIn: QWORD
31 ARightShift64 PROTO C Operand: QWORD, CountIn: QWORD
32 MulU64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
33 MulS64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
34 DivU64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD
35 DivS64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD
38 LeftShiftU64 PROC C Operand: QWORD, CountIn: QWORD
40 ;------------------------------------------------------------------------------
47 ; Routine Description:
49 ; Left-shift a 64-bit value.
53 ; Operand - the value to shift
59 ;------------------------------------------------------------------------------
63 ; if (CountIn > 63) return 0;
65 cmp dword ptr CountIn[4], 0
66 jne _LeftShiftU64_Overflow
67 mov ecx, dword ptr CountIn[0]
69 jbe _LeftShiftU64_Calc
71 _LeftShiftU64_Overflow:
74 jmp _LeftShiftU64_Done
77 mov eax, dword ptr Operand[0]
78 mov edx, dword ptr Operand[4]
83 jc short _LeftShiftU64_Done
95 RightShiftU64 PROC C Operand: QWORD, CountIn: QWORD
97 ;------------------------------------------------------------------------------
104 ; Routine Description:
106 ; Right-shift an unsigned 64-bit value.
110 ; Operand - the value to shift
111 ; Count - shift count
116 ;------------------------------------------------------------------------------
120 ; if (CountIn > 63) return 0;
122 cmp dword ptr CountIn[4], 0
123 jne _RightShiftU64_Overflow
124 mov ecx, dword ptr CountIn[0]
126 jbe _RightShiftU64_Calc
128 _RightShiftU64_Overflow:
131 jmp _RightShiftU64_Done
134 mov eax, dword ptr Operand[0]
135 mov edx, dword ptr Operand[4]
140 jc short _RightShiftU64_Done
152 ARightShift64 PROC C Operand: QWORD, CountIn: QWORD
154 ;------------------------------------------------------------------------------
161 ; Routine Description:
163 ; Arithmatic shift a 64 bit signed value.
167 ; Operand - the value to shift
168 ; Count - shift count
173 ;------------------------------------------------------------------------------
177 ; If they exceeded the max shift count, then return either 0 or all F's
178 ; depending on the sign bit.
180 cmp dword ptr CountIn[4], 0
181 jne _ARightShiftU64_Overflow
182 mov ecx, dword ptr CountIn[0]
184 jbe _ARightShiftU64_Calc
186 _ARightShiftU64_Overflow:
188 ; Check the sign bit of Operand
190 bt dword ptr Operand[4], 31
191 jnc _ARightShiftU64_Return_Zero
197 jmp _ARightShiftU64_Done
199 _ARightShiftU64_Return_Zero:
202 jmp _ARightShiftU64_Done
204 _ARightShiftU64_Calc:
205 mov eax, dword ptr Operand[0]
206 mov edx, dword ptr Operand[4]
211 jc short _ARightShiftU64_Done
214 ; if ecx >= 32, then eax = edx, and edx = sign bit
219 _ARightShiftU64_Done:
226 MulU64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
228 ;------------------------------------------------------------------------------
236 ; Routine Description:
238 ; Multiply two unsigned 64-bit values.
242 ; Value1 - first value to multiply
243 ; Value2 - value to multiply by Value1
244 ; ResultHigh - result to flag overflows
249 ; The 128-bit result is the concatenation of *ResultHigh and the return value
250 ;------------------------------------------------------------------------------
254 mov ebx, ResultHigh ; ebx points to the high 4 words of result
256 ; The result consists of four double-words.
257 ; Here we assume their names from low to high: dw0, dw1, dw2, dw3
259 mov eax, dword ptr Value1[0]
260 mul dword ptr Value2[0]
261 push eax ; eax contains final result of dw0, push it
262 mov ecx, edx ; ecx contains partial result of dw1
264 mov eax, dword ptr Value1[4]
265 mul dword ptr Value2[0]
266 add ecx, eax ; add eax to partial result of dw1
268 mov dword ptr [ebx], edx ; lower double-word of ResultHigh contains partial result of dw2
270 mov eax, dword ptr Value1[0]
271 mul dword ptr Value2[4]
272 add ecx, eax ; add eax to partial result of dw1
273 push ecx ; ecx contains final result of dw1, push it
275 mov ecx, edx ; ecx contains partial result of dw2, together with ResultHigh
277 mov eax, dword ptr Value1[4]
278 mul dword ptr Value2[4]
279 add ecx, eax ; add eax to partial result of dw2
281 add dword ptr [ebx], ecx ; lower double-word of ResultHigh contains final result of dw2
283 mov dword ptr [ebx + 4], edx ; high double-word of ResultHigh contains final result of dw3
285 pop edx ; edx contains the final result of dw1
286 pop eax ; edx contains the final result of dw0
294 MulS64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD
296 ;------------------------------------------------------------------------------
304 ; Routine Description:
306 ; Multiply two signed 64-bit values.
310 ; Value1 - first value to multiply
311 ; Value2 - value to multiply by Value1
312 ; ResultHigh - result to flag overflows
317 ; The 128-bit result is the concatenation of *ResultHigh and the return value
318 ;------------------------------------------------------------------------------
322 mov ebx, ResultHigh ; ebx points to the high 4 words of result
323 xor ecx, ecx ; the lowest bit of ecx flags the sign
325 mov edx, dword ptr Value1[4]
327 jnc short _MulS64x64_A_Positive
331 mov eax, dword ptr Value1[0]
336 mov dword ptr Value1[0], eax
337 mov dword ptr Value1[4], edx
340 _MulS64x64_A_Positive:
341 mov edx, dword ptr Value2[4]
343 jnc short _MulS64x64_B_Positive
347 mov eax, dword ptr Value2[0]
352 mov dword ptr Value2[0], eax
353 mov dword ptr Value2[4], edx
356 _MulS64x64_B_Positive:
357 invoke MulU64x64, Value1, Value2, ResultHigh
359 jnc short _MulS64x64_Done
366 not dword ptr [ebx + 4]
369 adc dword ptr [ebx], 0
370 adc dword ptr [ebx + 4], 0
380 DivU64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD,
382 ;------------------------------------------------------------------------------
385 ; IN UINT64 Dividend,
387 ; OUT UINT64 *Remainder OPTIONAL,
391 ; Routine Description:
393 ; This routine allows a 64 bit value to be divided with a 64 bit value returns
394 ; 64bit result and the Remainder
398 ; Dividend - dividend
400 ; ResultHigh - result to flag overflows
401 ; Error - flag for error
406 ; Remainder = Dividend mod Divisor
407 ;------------------------------------------------------------------------------
412 mov dword ptr [eax], 0
414 cmp dword ptr Divisor[0], 0
416 cmp dword ptr Divisor[4], 0
419 ; the divisor is zero
421 mov dword ptr [eax], 1
423 je _DivU64x64_Invalid_Return
425 ; fill the remainder if the pointer is not null
428 mov dword ptr [eax], 0
429 mov dword ptr [eax + 4], 80000000h
431 _DivU64x64_Invalid_Return:
438 ; let edx and eax contain the intermediate result of remainder
446 ; shift dividend left one
448 shl dword ptr Dividend[0], 1
449 rcl dword ptr Dividend[4], 1
451 ; rotate intermediate result of remainder left one
456 cmp edx, dword ptr Divisor[4]
457 ja _DivU64x64_Sub_Divisor
459 cmp eax, dword ptr Divisor[0]
462 _DivU64x64_Sub_Divisor:
464 ; If intermediate result of remainder is larger than
465 ; or equal to divisor, then set the lowest bit of dividend,
466 ; and subtract divisor from intermediate remainder
468 bts dword ptr Dividend[0], 0
469 sub eax, dword ptr Divisor[0]
470 sbb edx, dword ptr Divisor[4]
478 mov dword ptr [ecx], eax
479 mov dword ptr [ecx + 4], edx
482 mov eax, dword ptr Dividend[0]
483 mov edx, dword ptr Dividend[4]
491 DivS64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD,
493 ;------------------------------------------------------------------------------
498 ; OUT UINT64 *Remainder OPTIONAL,
502 ; Routine Description:
504 ; This routine allows a 64 bit signed value to be divided with a 64 bit
505 ; signed value returns 64bit result and the Remainder.
509 ; Dividend - dividend
511 ; ResultHigh - result to flag overflows
512 ; Error - flag for error
517 ; Remainder = Dividend mod Divisor
518 ;------------------------------------------------------------------------------
523 mov dword ptr [eax], 0
525 cmp dword ptr Divisor[0], 0
527 cmp dword ptr Divisor[4], 0
530 ; the divisor is zero
532 mov dword ptr [eax], 1
534 je _DivS64x64_Invalid_Return
536 ; fill the remainder if the pointer is not null
539 mov dword ptr [eax], 0
540 mov dword ptr [eax + 4], 80000000h
542 _DivS64x64_Invalid_Return:
549 ; The lowest bit of ecx flags the sign of quotient,
550 ; The seconde lowest bit flags the sign of remainder
554 mov edx, dword ptr Dividend[4]
556 jnc short _DivS64x64_Dividend_Positive
558 ; dividend is negative
560 mov eax, dword ptr Dividend[0]
565 mov dword ptr Dividend[0], eax
566 mov dword ptr Dividend[4], edx
568 ; set both the flags for signs of quotient and remainder
573 _DivS64x64_Dividend_Positive:
574 mov edx, dword ptr Divisor[4]
576 jnc short _DivS64x64_Divisor_Positive
578 ; divisor is negative
580 mov eax, dword ptr Divisor[0]
585 mov dword ptr Divisor[0], eax
586 mov dword ptr Divisor[4], edx
588 ; just complement the flag for sign of quotient
592 _DivS64x64_Divisor_Positive:
593 invoke DivU64x64, Dividend, Divisor, Remainder, Error
595 jnc short _DivS64x64_Remainder
597 ; negate the quotient
604 _DivS64x64_Remainder:
606 jnc short _DivS64x64_Done
608 ; negate the remainder
612 not dword ptr [ecx + 4]
613 add dword ptr [ecx], 1
614 adc dword ptr [ecx + 4], 0