audk/EdkModulePkg/Universal/Ebc/Dxe/Ia32/Ia32Math.asm

622 lines
15 KiB
NASM

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