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