mirror of https://github.com/acidanthera/audk.git
622 lines
15 KiB
NASM
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 eax, edx, cl
|
|
shr edx, 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 |