summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
diff options
context:
space:
mode:
Diffstat (limited to 'EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm')
-rw-r--r--EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm622
1 files changed, 622 insertions, 0 deletions
diff --git a/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
new file mode 100644
index 0000000000..4c91a2730b
--- /dev/null
+++ b/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm
@@ -0,0 +1,622 @@
+ 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 \ No newline at end of file