- TITLE Ia32math.asm: Generic math routines for EBC interpreter running on IA32 processor\r
-\r
-;------------------------------------------------------------------------------\r
-;\r
-; Copyright (c) 2006, Intel Corporation \r
-; All rights reserved. This program and the accompanying materials \r
-; are licensed and made available under the terms and conditions of the BSD License \r
-; which accompanies this distribution. The full text of the license may be found at \r
-; http://opensource.org/licenses/bsd-license.php \r
-; \r
-; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-; \r
-; Module Name:\r
-;\r
-; Ia32math.asm\r
-; \r
-; Abstract:\r
-; \r
-; Generic math routines for EBC interpreter running on IA32 processor\r
-;\r
-;------------------------------------------------------------------------------\r
-\r
- .686P\r
- .XMM\r
- .MODEL SMALL\r
- .CODE\r
-\r
-LeftShiftU64 PROTO C Operand: QWORD, CountIn: QWORD\r
-RightShiftU64 PROTO C Operand: QWORD, CountIn: QWORD\r
-ARightShift64 PROTO C Operand: QWORD, CountIn: QWORD\r
-MulU64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
-MulS64x64 PROTO C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
-DivU64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD\r
-DivS64x64 PROTO C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD\r
-\r
- \r
-LeftShiftU64 PROC C Operand: QWORD, CountIn: QWORD\r
-\r
-;------------------------------------------------------------------------------\r
-; UINT64\r
-; LeftShiftU64 (\r
-; IN UINT64 Operand,\r
-; IN UINT64 CountIn\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; Left-shift a 64-bit value.\r
-;\r
-; Arguments:\r
-;\r
-; Operand - the value to shift\r
-; Count - shift count\r
-;\r
-; Returns:\r
-;\r
-; Operand << Count\r
-;------------------------------------------------------------------------------\r
-\r
- push ecx\r
- ;\r
- ; if (CountIn > 63) return 0;\r
- ;\r
- cmp dword ptr CountIn[4], 0\r
- jne _LeftShiftU64_Overflow\r
- mov ecx, dword ptr CountIn[0]\r
- cmp ecx, 63\r
- jbe _LeftShiftU64_Calc\r
- \r
-_LeftShiftU64_Overflow:\r
- xor eax, eax\r
- xor edx, edx\r
- jmp _LeftShiftU64_Done\r
- \r
-_LeftShiftU64_Calc:\r
- mov eax, dword ptr Operand[0]\r
- mov edx, dword ptr Operand[4]\r
- \r
- shld edx, eax, cl\r
- shl eax, cl\r
- cmp ecx, 32\r
- jc short _LeftShiftU64_Done\r
- \r
- mov edx, eax\r
- xor eax, eax\r
- \r
-_LeftShiftU64_Done:\r
- pop ecx\r
- ret\r
-\r
-LeftShiftU64 ENDP\r
-\r
-\r
-RightShiftU64 PROC C Operand: QWORD, CountIn: QWORD\r
-\r
-;------------------------------------------------------------------------------\r
-; UINT64\r
-; RightShiftU64 (\r
-; IN UINT64 Operand,\r
-; IN UINT64 CountIn\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; Right-shift an unsigned 64-bit value.\r
-;\r
-; Arguments:\r
-;\r
-; Operand - the value to shift\r
-; Count - shift count\r
-;\r
-; Returns:\r
-;\r
-; Operand >> Count\r
-;------------------------------------------------------------------------------\r
-\r
- push ecx\r
- ;\r
- ; if (CountIn > 63) return 0;\r
- ;\r
- cmp dword ptr CountIn[4], 0\r
- jne _RightShiftU64_Overflow\r
- mov ecx, dword ptr CountIn[0]\r
- cmp ecx, 63\r
- jbe _RightShiftU64_Calc\r
- \r
-_RightShiftU64_Overflow:\r
- xor eax, eax\r
- xor edx, edx\r
- jmp _RightShiftU64_Done\r
- \r
-_RightShiftU64_Calc:\r
- mov eax, dword ptr Operand[0]\r
- mov edx, dword ptr Operand[4]\r
- \r
- shrd eax, edx, cl\r
- shr edx, cl\r
- cmp ecx, 32\r
- jc short _RightShiftU64_Done\r
- \r
- mov eax, edx\r
- xor edx, edx\r
- \r
-_RightShiftU64_Done:\r
- pop ecx\r
- ret\r
-\r
-RightShiftU64 ENDP\r
-\r
-\r
-ARightShift64 PROC C Operand: QWORD, CountIn: QWORD\r
-\r
-;------------------------------------------------------------------------------\r
-; INT64\r
-; ARightShift64 (\r
-; IN INT64 Operand,\r
-; IN UINT64 CountIn\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; Arithmatic shift a 64 bit signed value.\r
-;\r
-; Arguments:\r
-;\r
-; Operand - the value to shift\r
-; Count - shift count\r
-;\r
-; Returns:\r
-;\r
-; Operand >> Count\r
-;------------------------------------------------------------------------------\r
-\r
- push ecx\r
- ;\r
- ; If they exceeded the max shift count, then return either 0 or all F's\r
- ; depending on the sign bit.\r
- ;\r
- cmp dword ptr CountIn[4], 0\r
- jne _ARightShiftU64_Overflow\r
- mov ecx, dword ptr CountIn[0]\r
- cmp ecx, 63\r
- jbe _ARightShiftU64_Calc\r
- \r
-_ARightShiftU64_Overflow:\r
- ;\r
- ; Check the sign bit of Operand\r
- ;\r
- bt dword ptr Operand[4], 31\r
- jnc _ARightShiftU64_Return_Zero\r
- ;\r
- ; return -1\r
- ;\r
- or eax, 0FFFFFFFFh\r
- or edx, 0FFFFFFFFh\r
- jmp _ARightShiftU64_Done\r
-\r
-_ARightShiftU64_Return_Zero:\r
- xor eax, eax\r
- xor edx, edx\r
- jmp _ARightShiftU64_Done\r
- \r
-_ARightShiftU64_Calc:\r
- mov eax, dword ptr Operand[0]\r
- mov edx, dword ptr Operand[4]\r
-\r
- shrd eax, edx, cl\r
- sar edx, cl\r
- cmp ecx, 32\r
- jc short _ARightShiftU64_Done\r
-\r
- ;\r
- ; if ecx >= 32, then eax = edx, and edx = sign bit\r
- ;\r
- mov eax, edx\r
- sar edx, 31\r
-\r
-_ARightShiftU64_Done:\r
- pop ecx\r
- ret\r
-\r
-ARightShift64 ENDP\r
-\r
-\r
-MulU64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
-\r
-;------------------------------------------------------------------------------\r
-; UINT64 \r
-; MulU64x64 (\r
-; UINT64 Value1, \r
-; UINT64 Value2, \r
-; UINT64 *ResultHigh\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; Multiply two unsigned 64-bit values.\r
-;\r
-; Arguments:\r
-;\r
-; Value1 - first value to multiply\r
-; Value2 - value to multiply by Value1\r
-; ResultHigh - result to flag overflows\r
-;\r
-; Returns:\r
-; \r
-; Value1 * Value2\r
-; The 128-bit result is the concatenation of *ResultHigh and the return value \r
-;------------------------------------------------------------------------------\r
-\r
- push ebx\r
- push ecx\r
- mov ebx, ResultHigh ; ebx points to the high 4 words of result\r
- ;\r
- ; The result consists of four double-words.\r
- ; Here we assume their names from low to high: dw0, dw1, dw2, dw3\r
- ;\r
- mov eax, dword ptr Value1[0]\r
- mul dword ptr Value2[0]\r
- push eax ; eax contains final result of dw0, push it\r
- mov ecx, edx ; ecx contains partial result of dw1\r
- \r
- mov eax, dword ptr Value1[4]\r
- mul dword ptr Value2[0]\r
- add ecx, eax ; add eax to partial result of dw1\r
- adc edx, 0 \r
- mov dword ptr [ebx], edx ; lower double-word of ResultHigh contains partial result of dw2\r
- \r
- mov eax, dword ptr Value1[0]\r
- mul dword ptr Value2[4]\r
- add ecx, eax ; add eax to partial result of dw1\r
- push ecx ; ecx contains final result of dw1, push it\r
- adc edx, 0\r
- mov ecx, edx ; ecx contains partial result of dw2, together with ResultHigh\r
-\r
- mov eax, dword ptr Value1[4]\r
- mul dword ptr Value2[4]\r
- add ecx, eax ; add eax to partial result of dw2\r
- adc edx, 0\r
- add dword ptr [ebx], ecx ; lower double-word of ResultHigh contains final result of dw2\r
- adc edx, 0\r
- mov dword ptr [ebx + 4], edx ; high double-word of ResultHigh contains final result of dw3\r
- \r
- pop edx ; edx contains the final result of dw1\r
- pop eax ; edx contains the final result of dw0\r
- pop ecx\r
- pop ebx\r
- ret\r
-\r
-MulU64x64 ENDP\r
-\r
-\r
-MulS64x64 PROC C Value1: QWORD, Value2: QWORD, ResultHigh: DWORD\r
-\r
-;------------------------------------------------------------------------------\r
-; INT64\r
-; MulS64x64 (\r
-; INT64 Value1,\r
-; INT64 Value2,\r
-; INT64 *ResultHigh\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; Multiply two signed 64-bit values.\r
-;\r
-; Arguments:\r
-;\r
-; Value1 - first value to multiply\r
-; Value2 - value to multiply by Value1\r
-; ResultHigh - result to flag overflows\r
-;\r
-; Returns:\r
-;\r
-; Value1 * Value2\r
-; The 128-bit result is the concatenation of *ResultHigh and the return value \r
-;------------------------------------------------------------------------------\r
-\r
- push ebx\r
- push ecx\r
- mov ebx, ResultHigh ; ebx points to the high 4 words of result\r
- xor ecx, ecx ; the lowest bit of ecx flags the sign\r
- \r
- mov edx, dword ptr Value1[4]\r
- bt edx, 31\r
- jnc short _MulS64x64_A_Positive\r
- ;\r
- ; a is negative\r
- ;\r
- mov eax, dword ptr Value1[0]\r
- not edx\r
- not eax\r
- add eax, 1\r
- adc edx, 0\r
- mov dword ptr Value1[0], eax\r
- mov dword ptr Value1[4], edx\r
- btc ecx, 0\r
- \r
-_MulS64x64_A_Positive:\r
- mov edx, dword ptr Value2[4]\r
- bt edx, 31\r
- jnc short _MulS64x64_B_Positive\r
- ;\r
- ; b is negative\r
- ;\r
- mov eax, dword ptr Value2[0]\r
- not edx\r
- not eax\r
- add eax, 1\r
- adc edx, 0\r
- mov dword ptr Value2[0], eax\r
- mov dword ptr Value2[4], edx\r
- btc ecx, 0\r
- \r
-_MulS64x64_B_Positive:\r
- invoke MulU64x64, Value1, Value2, ResultHigh\r
- bt ecx, 0\r
- jnc short _MulS64x64_Done\r
- ;\r
- ;negate the result\r
- ;\r
- not eax\r
- not edx\r
- not dword ptr [ebx]\r
- not dword ptr [ebx + 4]\r
- add eax, 1\r
- adc edx, 0\r
- adc dword ptr [ebx], 0\r
- adc dword ptr [ebx + 4], 0\r
- \r
-_MulS64x64_Done:\r
- pop ecx\r
- pop ebx\r
- ret\r
-\r
-MulS64x64 ENDP\r
-\r
-\r
-DivU64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD, \r
-\r
-;------------------------------------------------------------------------------\r
-; UINT64\r
-; DivU64x64 (\r
-; IN UINT64 Dividend,\r
-; IN UINT64 Divisor,\r
-; OUT UINT64 *Remainder OPTIONAL,\r
-; OUT UINT32 *Error\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; This routine allows a 64 bit value to be divided with a 64 bit value returns \r
-; 64bit result and the Remainder\r
-;\r
-; Arguments:\r
-;\r
-; Dividend - dividend\r
-; Divisor - divisor\r
-; ResultHigh - result to flag overflows\r
-; Error - flag for error\r
-;\r
-; Returns:\r
-; \r
-; Dividend / Divisor\r
-; Remainder = Dividend mod Divisor\r
-;------------------------------------------------------------------------------\r
-\r
- push ecx\r
- \r
- mov eax, Error\r
- mov dword ptr [eax], 0 \r
- \r
- cmp dword ptr Divisor[0], 0\r
- jne _DivU64x64_Valid\r
- cmp dword ptr Divisor[4], 0\r
- jne _DivU64x64_Valid\r
- ;\r
- ; the divisor is zero\r
- ;\r
- mov dword ptr [eax], 1 \r
- cmp Remainder, 0\r
- je _DivU64x64_Invalid_Return\r
- ;\r
- ; fill the remainder if the pointer is not null\r
- ;\r
- mov eax, Remainder\r
- mov dword ptr [eax], 0\r
- mov dword ptr [eax + 4], 80000000h\r
- \r
-_DivU64x64_Invalid_Return:\r
- xor eax, eax\r
- mov edx, 80000000h\r
- jmp _DivU64x64_Done\r
-\r
-_DivU64x64_Valid:\r
- ;\r
- ; let edx and eax contain the intermediate result of remainder\r
- ;\r
- xor edx, edx\r
- xor eax, eax\r
- mov ecx, 64\r
- \r
-_DivU64x64_Wend:\r
- ;\r
- ; shift dividend left one\r
- ;\r
- shl dword ptr Dividend[0], 1\r
- rcl dword ptr Dividend[4], 1 \r
- ;\r
- ; rotate intermediate result of remainder left one\r
- ;\r
- rcl eax, 1\r
- rcl edx, 1 \r
- \r
- cmp edx, dword ptr Divisor[4]\r
- ja _DivU64x64_Sub_Divisor\r
- jb _DivU64x64_Cont\r
- cmp eax, dword ptr Divisor[0]\r
- jb _DivU64x64_Cont\r
- \r
-_DivU64x64_Sub_Divisor:\r
- ;\r
- ; If intermediate result of remainder is larger than\r
- ; or equal to divisor, then set the lowest bit of dividend,\r
- ; and subtract divisor from intermediate remainder\r
- ;\r
- bts dword ptr Dividend[0], 0\r
- sub eax, dword ptr Divisor[0]\r
- sbb edx, dword ptr Divisor[4]\r
- \r
-_DivU64x64_Cont:\r
- loop _DivU64x64_Wend\r
- \r
- cmp Remainder, 0\r
- je _DivU64x64_Assign\r
- mov ecx, Remainder\r
- mov dword ptr [ecx], eax\r
- mov dword ptr [ecx + 4], edx\r
- \r
-_DivU64x64_Assign:\r
- mov eax, dword ptr Dividend[0]\r
- mov edx, dword ptr Dividend[4]\r
- \r
-_DivU64x64_Done:\r
- pop ecx\r
- ret\r
- \r
-DivU64x64 ENDP\r
-\r
-DivS64x64 PROC C Dividend: QWORD, Divisor: QWORD, Remainder: DWORD, Error: DWORD, \r
-\r
-;------------------------------------------------------------------------------\r
-; INT64\r
-; DivU64x64 (\r
-; IN INT64 Dividend,\r
-; IN INT64 Divisor,\r
-; OUT UINT64 *Remainder OPTIONAL,\r
-; OUT UINT32 *Error\r
-; )\r
-;\r
-; Routine Description:\r
-; \r
-; This routine allows a 64 bit signed value to be divided with a 64 bit \r
-; signed value returns 64bit result and the Remainder.\r
-;\r
-; Arguments:\r
-;\r
-; Dividend - dividend\r
-; Divisor - divisor\r
-; ResultHigh - result to flag overflows\r
-; Error - flag for error\r
-;\r
-; Returns:\r
-; \r
-; Dividend / Divisor\r
-; Remainder = Dividend mod Divisor\r
-;------------------------------------------------------------------------------\r
-\r
- push ecx\r
- \r
- mov eax, Error\r
- mov dword ptr [eax], 0 \r
- \r
- cmp dword ptr Divisor[0], 0\r
- jne _DivS64x64_Valid\r
- cmp dword ptr Divisor[4], 0\r
- jne _DivS64x64_Valid\r
- ;\r
- ; the divisor is zero\r
- ;\r
- mov dword ptr [eax], 1 \r
- cmp Remainder, 0\r
- je _DivS64x64_Invalid_Return\r
- ;\r
- ; fill the remainder if the pointer is not null\r
- ;\r
- mov eax, Remainder\r
- mov dword ptr [eax], 0\r
- mov dword ptr [eax + 4], 80000000h\r
- \r
-_DivS64x64_Invalid_Return:\r
- xor eax, eax\r
- mov edx, 80000000h\r
- jmp _DivS64x64_Done\r
-\r
-_DivS64x64_Valid:\r
- ;\r
- ; The lowest bit of ecx flags the sign of quotient,\r
- ; The seconde lowest bit flags the sign of remainder\r
- ;\r
- xor ecx, ecx \r
- \r
- mov edx, dword ptr Dividend[4]\r
- bt edx, 31\r
- jnc short _DivS64x64_Dividend_Positive\r
- ;\r
- ; dividend is negative\r
- ;\r
- mov eax, dword ptr Dividend[0]\r
- not edx\r
- not eax\r
- add eax, 1\r
- adc edx, 0\r
- mov dword ptr Dividend[0], eax\r
- mov dword ptr Dividend[4], edx\r
- ;\r
- ; set both the flags for signs of quotient and remainder\r
- ;\r
- btc ecx, 0\r
- btc ecx, 1\r
- \r
-_DivS64x64_Dividend_Positive:\r
- mov edx, dword ptr Divisor[4]\r
- bt edx, 31\r
- jnc short _DivS64x64_Divisor_Positive\r
- ;\r
- ; divisor is negative\r
- ;\r
- mov eax, dword ptr Divisor[0]\r
- not edx\r
- not eax\r
- add eax, 1\r
- adc edx, 0\r
- mov dword ptr Divisor[0], eax\r
- mov dword ptr Divisor[4], edx\r
- ;\r
- ; just complement the flag for sign of quotient\r
- ;\r
- btc ecx, 0\r
- \r
-_DivS64x64_Divisor_Positive:\r
- invoke DivU64x64, Dividend, Divisor, Remainder, Error\r
- bt ecx, 0\r
- jnc short _DivS64x64_Remainder\r
- ;\r
- ; negate the quotient\r
- ;\r
- not eax\r
- not edx\r
- add eax, 1\r
- adc edx, 0\r
- \r
-_DivS64x64_Remainder:\r
- bt ecx, 1\r
- jnc short _DivS64x64_Done\r
- ;\r
- ; negate the remainder\r
- ;\r
- mov ecx, remainder\r
- not dword ptr [ecx]\r
- not dword ptr [ecx + 4]\r
- add dword ptr [ecx], 1\r
- adc dword ptr [ecx + 4], 0\r
- \r
-_DivS64x64_Done:\r
- pop ecx\r
- ret\r
-\r
-DivS64x64 ENDP\r
-\r
-END
\ No newline at end of file