mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 18:35:32 +00:00
1144 lines
29 KiB
ArmAsm
1144 lines
29 KiB
ArmAsm
/*
|
|
* COPYRIGHT: LGPL, see LGPL.txt in the top level directory
|
|
* PROJECT: ReactOS Win32 subsystem
|
|
* PURPOSE: FLOATOBJ floating point emulation functions for x86
|
|
* FILE: win32ss/gdi/eng/i386/floatobj.S
|
|
* PROGRAMMER: Timo Kreuzer
|
|
*/
|
|
|
|
#include <asm.inc>
|
|
|
|
.code
|
|
/*******************************************************************************
|
|
* IEEE 754-1985 single precision floating point
|
|
*
|
|
* | 31 | 30...23 | 22...0 |
|
|
* |sign| exponent | fraction |
|
|
*
|
|
* mantissa = 1 + (fraction / 2^23)
|
|
* f = (-1)^sign * mantissa * 2 ^ (exponent - bias)
|
|
* bias = 127
|
|
*
|
|
*******************************************************************************
|
|
* win32k x86 floating point emulation
|
|
*
|
|
* struct _EFLOAT
|
|
= {
|
|
* LONG lMant;
|
|
* LONG lExp;
|
|
* };
|
|
*
|
|
* f = (lMant / 0x40000000) * 2 ^ (lExp - 2)
|
|
* = lMant * 2 ^ (lExp - 32)
|
|
*
|
|
*******************************************************************************
|
|
* Optimization notes:
|
|
*
|
|
* - shld is slow (4 cycles) and not pairable, mov + shl is faster
|
|
* - esp is used, because it's available earlier
|
|
* - bsr is very slow on old cpus (up to 72 cycles on a p1) while being much
|
|
* faster on modern cpus (2-11 cycles). Workarounds using branch trees or
|
|
* table lookups are of no use nowadays.
|
|
*******************************************************************************
|
|
* Compatibility notes:
|
|
* - There are issues with very large size values near integer overflow.
|
|
* Floating point values are behaving different there. This behavior isn't
|
|
* simulated yet. Difference is < 10^-5 %
|
|
* - The result of a multiplication can differ from Windows result in the
|
|
* least significant bit, that is a difference of 1 / 2^30 or ~10^-9
|
|
*******************************************************************************
|
|
* Implementation status:
|
|
*
|
|
* FLOATOBJ_SetFloat - implemented, tested
|
|
* FLOATOBJ_SetLong - implemented, tested
|
|
* FLOATOBJ_GetFloat - implemented, tested
|
|
* FLOATOBJ_GetLong - implemented in C
|
|
* FLOATOBJ_Equal - implemented, tested
|
|
* FLOATOBJ_EqualLong - implemented
|
|
* FLOATOBJ_GreaterThan - implemented
|
|
* FLOATOBJ_GreaterThanLong - wrapper
|
|
* FLOATOBJ_LessThan - implemented
|
|
* FLOATOBJ_LessThanLong - wrapper
|
|
* FLOATOBJ_Neg - implemented
|
|
* FLOATOBJ_Mul - implemented, tested, optimized
|
|
* FLOATOBJ_MulFloat - wrapper
|
|
* FLOATOBJ_MulLong - wrapper, could really need optimization
|
|
* FLOATOBJ_Div - implemented
|
|
* FLOATOBJ_DivFloat - wrapper
|
|
* FLOATOBJ_DivLong - wrapper
|
|
* FLOATOBJ_Add - implemented, tested
|
|
* FLOATOBJ_AddFloat - wrapper
|
|
* FLOATOBJ_AddLong - wrapper
|
|
* FLOATOBJ_Sub - implemented, tested
|
|
* FLOATOBJ_SubFloat - wrapper
|
|
* FLOATOBJ_SubLong - wrapper
|
|
*/
|
|
|
|
#define lMant 0
|
|
#define lExp 4
|
|
|
|
#define PARAM1 8
|
|
#define PARAM2 12
|
|
|
|
/** Globals **/
|
|
/* extern const FLOATOBJ gef0; */
|
|
PUBLIC _gef0
|
|
_gef0:
|
|
.long 0, 0
|
|
|
|
/* extern const FLOATOBJ gef1; */
|
|
PUBLIC _gef1
|
|
_gef1:
|
|
.long HEX(40000000), HEX(00000002)
|
|
|
|
/* extern const FLOATOBJ gef2; */
|
|
PUBLIC _gef2
|
|
_gef2:
|
|
.long HEX(40000000), HEX(00000003)
|
|
|
|
/* extern const FLOATOBJ gef16; */
|
|
PUBLIC _gef16
|
|
_gef16:
|
|
.long HEX(40000000), HEX(00000006)
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_SetFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
|
|
*/
|
|
_FLOATOBJ_SetFloat@8:
|
|
PUBLIC _FLOATOBJ_SetFloat@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov ecx, [esp + PARAM2] /* Load the float into ecx */
|
|
mov eax, ecx /* Copy float to eax for later */
|
|
|
|
test ecx, HEX(7f800000) /* Check for zero exponent - 0 or denormal */
|
|
jz SetFloat0 /* If it's all zero, ... */
|
|
|
|
shl ecx, 7 /* Put the bits for the mantissa in place */
|
|
|
|
cdq /* Fill edx with the sign from the FLOATL in eax */
|
|
and ecx, HEX(7fffffff) /* Mask out invalid field in the mantissa */
|
|
|
|
shr eax, 23 /* Shift the exponent in eax in place */
|
|
or ecx, HEX(40000000) /* Set bit for 1 in the mantissa */
|
|
and eax, HEX(0ff) /* Mask out invalid fields in the exponent in eax */
|
|
|
|
xor ecx, edx /* Make use of the sign bit expanded to full edx */
|
|
|
|
sub eax, 125 /* Adjust exonent bias */
|
|
|
|
sub ecx, edx /* Substract -1 or add 1 if sign was set */
|
|
|
|
mov edx, [esp + PARAM1] /* Load pf into edx */
|
|
mov [edx + lMant], ecx /* Save back mantissa */
|
|
mov [edx + lExp], eax /* Save back exponent */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
SetFloat0:
|
|
mov edx, [esp + PARAM1] /* Load pf into edx */
|
|
|
|
mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */
|
|
mov dword ptr [edx + lExp], 0
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
|
|
/*******************************************************************************
|
|
* LONG
|
|
* APIENTRY
|
|
* FLOATOBJ_GetFloat(IN PFLOATOBJ pf);
|
|
*
|
|
*/
|
|
_FLOATOBJ_GetFloat@4:
|
|
PUBLIC _FLOATOBJ_GetFloat@4
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov edx, [esp + PARAM1] /* Load pf into edx */
|
|
mov eax, [edx + lMant] /* Load mantissa into eax */
|
|
mov ecx, [edx + lExp] /* Load exponent into ecx */
|
|
|
|
cdq /* Calculate abs(mantissa) */
|
|
xor eax, edx
|
|
|
|
add ecx, 125
|
|
|
|
sub eax, edx
|
|
jz GetFloatRet
|
|
|
|
and ecx, HEX(0ff) /* Mask out invalid fields in the exponent */
|
|
and eax, HEX(3fffffff) /* Mask out invalid fields in mantissa */
|
|
|
|
shl ecx, 23 /* Shift exponent in place */
|
|
shr eax, 7 /* Shift mantissa in place */
|
|
|
|
and edx, HEX(80000000) /* Reduce edx to sign bit only */
|
|
|
|
or eax, ecx /* Set exponent in result */
|
|
or eax, edx /* Set sign bit in result */
|
|
|
|
GetFloatRet:
|
|
/* Return */
|
|
pop ebp
|
|
ret 4
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_SetLong(OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Instead of using abs(l), which is 3 + 2 instructions, use a branch.
|
|
*/
|
|
_FLOATOBJ_SetLong@8:
|
|
PUBLIC _FLOATOBJ_SetLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov eax, [esp + PARAM2] /* Load l into eax */
|
|
mov edx, [esp + PARAM1] /* Load pf into edx */
|
|
|
|
test eax, eax /* different handling for <0, =0 and >0 */
|
|
js SetLongNeg
|
|
jz SetLong0
|
|
|
|
bsr ecx, eax /* Get number of most significant bit aka log2(l) */
|
|
mov [edx + lExp], ecx /* Safe log2(l) into exponent */
|
|
|
|
neg ecx /* Calculate necessary shift */
|
|
add ecx, 30
|
|
|
|
add dword ptr [edx + lExp], 2 /* Adjust exponent */
|
|
|
|
shl eax, cl /* Shift mantissa in place */
|
|
mov [edx + lMant], eax /* Save mantissa */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
SetLongNeg:
|
|
neg eax /* Get absolute value of l */
|
|
bsr ecx, eax /* Get number of most significant bit aka log2(l) */
|
|
neg eax /* Back to negative */
|
|
|
|
mov [edx + lExp], ecx /* Safe log2(-l) into exponent */
|
|
|
|
neg ecx /* Calculate necessary shift */
|
|
add ecx, 30
|
|
|
|
add dword ptr [edx + lExp], 2 /* Adjust exponent */
|
|
|
|
shl eax, cl /* Shift mantissa in place */
|
|
mov [edx + lMant], eax /* Save mantissa */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
SetLong0:
|
|
mov dword ptr [edx + lMant], 0 /* Set mantissa and exponent to 0 */
|
|
mov dword ptr [edx + lExp], 0
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* BOOL
|
|
* APIENTRY
|
|
* FLOATOBJ_Equal(IN PFLOATOBJ pf1, IN PFLOATOBJ pf2);
|
|
*/
|
|
_FLOATOBJ_Equal@8:
|
|
PUBLIC _FLOATOBJ_Equal@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
|
|
mov eax, [esp + PARAM2] /* Load pf2 into ecx */
|
|
|
|
mov edx, [ecx + lExp] /* Get float1 in ecx, edx */
|
|
mov ecx, [ecx + lMant]
|
|
|
|
sub edx, [eax + lExp] /* Calculate diference to float2 */
|
|
sub ecx, [eax + lMant]
|
|
|
|
or edx, ecx /* Combine */
|
|
|
|
mov eax, 0 /* Set eax if combination is 0 */
|
|
setz al
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* BOOL
|
|
* APIENTRY
|
|
* FLOATOBJ_EqualLong(IN PFLOATOBJ pf, IN LONG l);
|
|
*/
|
|
_FLOATOBJ_EqualLong@8:
|
|
PUBLIC _FLOATOBJ_EqualLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov eax, [esp + PARAM1] /* Load pf into eax */
|
|
mov ecx, 32 /* Load (32 - lExp) into ecx */
|
|
sub ecx, [eax + lExp]
|
|
mov edx, [eax + lMant] /* Load mantissa into edx */
|
|
sar edx, cl /* Signed shift mantissa according to exponent */
|
|
shl edx, cl /* Shift the mantissa back */
|
|
cmp edx, [eax + lMant] /* Check whether bits were killed by shifting */
|
|
jnz EqualLongFalse /* We have truncated the mantissa, return 0 */
|
|
|
|
sar edx, cl /* Shift the mantissa again */
|
|
xor eax, eax /* Set return value ... */
|
|
cmp edx, [esp + PARAM2] /* TRUE if shifted mantissa equals the LONG */
|
|
setz al
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
EqualLongFalse:
|
|
xor eax, eax /* Return FALSE */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* BOOL
|
|
* APIENTRY
|
|
* FLOATOBJ_GreaterThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1);
|
|
*
|
|
*/
|
|
_FLOATOBJ_GreaterThan@8:
|
|
PUBLIC _FLOATOBJ_GreaterThan@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov eax, [ebp + PARAM1] /* Load pointer to efloat1 in eax */
|
|
mov edx, [ebp + PARAM2] /* Load pointer to efloat2 in edx */
|
|
|
|
mov ecx, [eax + lMant] /* Load mantissa1 in ecx */
|
|
mov edx, [edx + lMant] /* Load mantissa2 in edx */
|
|
|
|
sar ecx, 31 /* Calculate sign(lMant1) in ecx */
|
|
sar edx, 31 /* Calculate sign(lMant2) in edx */
|
|
|
|
cmp ecx, edx /* Branch if both have the same sign */
|
|
je GreaterThan_2
|
|
|
|
/* Mantissae have different sign */
|
|
mov eax, 0 /* Return (sign(lMant1) > sign(lMant2)) */
|
|
setg al
|
|
pop ebp
|
|
ret 8
|
|
|
|
GreaterThan_2:
|
|
/* Mantissae have the same sign */
|
|
|
|
mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */
|
|
test ecx, ecx /* Branch if sign is negative */
|
|
js GreaterThan_neg
|
|
|
|
/* Both mantissae are positive or 0 */
|
|
|
|
or ecx, [edx + lMant] /* Branch if one mantissa is 0 */
|
|
jz GreaterThan_pos2
|
|
|
|
/* Both mantissae are positive */
|
|
|
|
mov ecx, [eax + lExp] /* Branch if exponents are equal */
|
|
cmp ecx, [edx + lExp]
|
|
je GreaterThan_pos2
|
|
|
|
mov eax, 0 /* Return (lExp1 > lExp2) */
|
|
setg al
|
|
pop ebp
|
|
ret 8
|
|
|
|
GreaterThan_pos2:
|
|
/* Exponents are equal or one mantissa is 0 */
|
|
|
|
mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */
|
|
cmp ecx, [edx + lMant]
|
|
mov eax, 0
|
|
setg al
|
|
pop ebp
|
|
ret 8
|
|
|
|
GreaterThan_neg:
|
|
/* Both mantissae are negative */
|
|
|
|
mov ecx, [eax + lExp] /* Branch if exponents are equal */
|
|
cmp ecx, [edx + lExp]
|
|
je GreaterThan_neg2
|
|
|
|
/* Both mantissae negative, exponents are different */
|
|
|
|
mov eax, 0 /* Return (lExp1 < lExp2) */
|
|
setl al
|
|
pop ebp
|
|
ret 8
|
|
|
|
GreaterThan_neg2:
|
|
/* Both mantissae negative, exponents are equal */
|
|
|
|
mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */
|
|
cmp ecx, [edx + lMant]
|
|
mov eax, 0
|
|
setl al
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_GreaterThanLong(IN OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetLong and
|
|
* LOATOBJ_GreaterThan
|
|
*/
|
|
_FLOATOBJ_GreaterThanLong@8:
|
|
PUBLIC _FLOATOBJ_GreaterThanLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
mov eax, [ebp + PARAM2] /* Load LONG into eax */
|
|
|
|
lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
|
|
|
|
push eax /* Push LONG on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
|
|
|
|
lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_GreaterThan@8 /* Compare */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* BOOL
|
|
* APIENTRY
|
|
* FLOATOBJ_LessThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1);
|
|
*
|
|
*/
|
|
_FLOATOBJ_LessThan@8:
|
|
PUBLIC _FLOATOBJ_LessThan@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and edx */
|
|
mov edx, [ebp + PARAM2]
|
|
|
|
mov ecx, [eax + lMant] /* Load mantissae in ecx and edx */
|
|
mov edx, [edx + lMant]
|
|
|
|
sar ecx, 31 /* Calculate sign(lMant1) and sign(lMant2) */
|
|
sar edx, 31
|
|
|
|
cmp ecx, edx /* Branch if both have the same sign */
|
|
je LessThan_2
|
|
|
|
/* Mantissae have different sign */
|
|
|
|
mov eax, 0 /* Return (sign(lMant1) < sign(lMant2)) */
|
|
setl al
|
|
pop ebp
|
|
ret 8
|
|
|
|
LessThan_2:
|
|
/* Mantissae have the same sign */
|
|
|
|
|
|
mov edx, [ebp + PARAM2] /* Reload pointer to float2 in edx */
|
|
|
|
test ecx, ecx /* Branch if sign is negative */
|
|
js LessThan_neg
|
|
|
|
/* Both mantissae are positive or 0 */
|
|
|
|
or ecx, [edx + lMant] /* Branch if one mantissa is 0 */
|
|
jz LessThan_pos2
|
|
|
|
/* Both mantissae are positive */
|
|
|
|
mov ecx, [eax + lExp] /* Branch if exponents are equal */
|
|
cmp ecx, [edx + lExp]
|
|
je LessThan_pos2
|
|
|
|
mov eax, 0 /* Return (lExp1 < lExp2) */
|
|
setl al
|
|
pop ebp
|
|
ret 8
|
|
|
|
LessThan_pos2:
|
|
/* Exponents are equal or one mantissa is 0 */
|
|
|
|
mov ecx, [eax + lMant] /* Return (lMant1 < lMant2) */
|
|
cmp ecx, [edx + lMant]
|
|
mov eax, 0
|
|
setl al
|
|
pop ebp
|
|
ret 8
|
|
|
|
LessThan_neg:
|
|
/* Both mantissae are negative */
|
|
|
|
mov ecx, [eax + lExp] /* Branch if exponents are equal */
|
|
cmp ecx, [edx + lExp]
|
|
je LessThan_neg2
|
|
|
|
/* Both mantissae negative, exponents are different */
|
|
|
|
mov eax, 0 /* Return (lExp1 > lExp2) */
|
|
setg al
|
|
pop ebp
|
|
ret 8
|
|
|
|
LessThan_neg2:
|
|
/* Both mantissae negative, exponents are equal */
|
|
|
|
mov ecx, [eax + lMant] /* Return (lMant1 > lMant2) */
|
|
cmp ecx, [edx + lMant]
|
|
mov eax, 0
|
|
setg al
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_LessThanLong(IN OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_LessThan
|
|
*/
|
|
_FLOATOBJ_LessThanLong@8:
|
|
PUBLIC _FLOATOBJ_LessThanLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
mov eax, [ebp + PARAM2] /* Load LONG into eax */
|
|
|
|
lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push LONG on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
|
|
|
|
lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_LessThan@8 /* Compare */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_Mul(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
|
|
*
|
|
* (mant1 * 2^exp1) * (mant2 * 2^exp2) = (mant1 * mant2) * 2^(exp1 + exp2)
|
|
* or mant = mant1 * mant2 and exp = exp1 + exp2
|
|
* No special handling for 0, where mantissa is 0
|
|
*/
|
|
_FLOATOBJ_Mul@8:
|
|
PUBLIC _FLOATOBJ_Mul@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov edx, [esp + PARAM1] /* Load pf1 into edx */
|
|
mov ecx, [esp + PARAM2] /* Load pf2 into ecx */
|
|
mov eax, [ecx + lMant] /* Load mantissa2 into eax */
|
|
mov ecx, [ecx + lExp] /* Load exponent2 into ecx */
|
|
|
|
imul dword ptr [edx + lMant] /* Multiply eax with mantissa 1 */
|
|
|
|
test edx, edx /* Special handling for result < 0 */
|
|
js MulNeg
|
|
|
|
shl edx, 2 /* Get new mantissa from bits 30 to 62 */
|
|
shr eax, 30 /* of edx:eax into edx */
|
|
or eax, edx
|
|
|
|
mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */
|
|
mov ecx, 0 /* Check for highest bit */
|
|
sets cl
|
|
shr eax, cl /* Normalize mantissa in eax */
|
|
|
|
jz Mul0 /* All 0? */
|
|
|
|
lea edx, [edx + ecx -2] /* Normalize exponent in edx */
|
|
|
|
|
|
mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
|
|
mov [ecx + lMant], eax /* Save back mantissa */
|
|
add [ecx + lExp], edx /* Save back exponent */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
MulNeg:
|
|
|
|
shl edx, 2 /* Get new mantissa from bits 30 to 62 */
|
|
shr eax, 30 /* of edx:eax into edx */
|
|
or eax, edx
|
|
|
|
mov edx, ecx /* Need ecx for the shift, safe exp2 to free edx */
|
|
|
|
mov ecx, 0 /* Check for highest bit */
|
|
setns cl
|
|
shr eax, cl /* Normalize mantissa in eax */
|
|
|
|
jz Mul0 /* All 0? */
|
|
|
|
|
|
lea edx, [edx + ecx -2] /* Normalize exponent in edx */
|
|
or eax, HEX(80000000) /* Set sign bit */
|
|
|
|
mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
|
|
mov [ecx + lMant], eax /* Save back mantissa */
|
|
add [ecx + lExp], edx /* Save back exponent */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
Mul0:
|
|
mov ecx, [esp + PARAM1] /* Load pf1 into ecx */
|
|
mov [ecx + lMant], eax /* Store 0 in mantissa */
|
|
mov [ecx + lExp], eax /* Store 0 in exponent */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_MulFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Mul
|
|
*/
|
|
_FLOATOBJ_MulFloat@8:
|
|
PUBLIC _FLOATOBJ_MulFloat@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
mov eax, [ebp + PARAM2] /* Load f into eax */
|
|
lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push f on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
|
|
|
|
lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Mul@8 /* Multiply */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_MulLong(IN OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Mul
|
|
*/
|
|
_FLOATOBJ_MulLong@8:
|
|
PUBLIC _FLOATOBJ_MulLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
mov eax, [ebp + PARAM2] /* Load l into eax */
|
|
lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push l on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
|
|
|
|
lea ecx, [ebp -8] /* Push pointer to local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Mul@8 /* Multiply */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/*******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_Div(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
|
|
*
|
|
*/
|
|
_FLOATOBJ_Div@8:
|
|
PUBLIC _FLOATOBJ_Div@8
|
|
push ebp
|
|
mov ebp, esp
|
|
push ebx
|
|
|
|
mov eax, [ebp + PARAM2] /* Load lMant2 into eax */
|
|
mov eax, [eax + lMant]
|
|
|
|
cdq /* Calculate abs(lMant2) */
|
|
xor eax, edx
|
|
sub eax, edx
|
|
jz DivError /* Divide by zero error! */
|
|
|
|
mov ebx, edx /* Copy sign(lMant2) to ebx */
|
|
mov ecx, eax /* Copy abs(lMant2) to ecx */
|
|
|
|
mov eax, [ebp + PARAM1] /* Load lMant1 into eax */
|
|
mov eax, [eax + lMant]
|
|
|
|
cdq /* Calculate abs(lMant1) */
|
|
xor eax, edx
|
|
sub eax, edx
|
|
|
|
jz Div0 /* Dividend is 0? */
|
|
|
|
xor ebx, edx /* combine both signs in ebx */
|
|
|
|
mov edx, eax /* Prepare edx:eax for integer divide */
|
|
xor eax, eax
|
|
shr edx, 1
|
|
div ecx /* Do an unsigned divide */
|
|
|
|
xor ecx, ecx /* Adjust result */
|
|
test eax, HEX(80000000)
|
|
setnz cl
|
|
shr eax, cl
|
|
|
|
xor eax, ebx /* Correct the result's sign */
|
|
sub eax, ebx
|
|
|
|
mov edx, [ebp + PARAM1] /* Load pf1 into edx */
|
|
mov [edx + lMant], eax /* Safe back the mantissa */
|
|
mov ebx, [ebp + PARAM2] /* Load pf2 into ebx */
|
|
sub ecx, [ebx + lExp] /* Calculate exponent offset */
|
|
inc ecx
|
|
add [edx + lExp], ecx /* Safe back exponent */
|
|
|
|
pop ebx /* Return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
DivError:
|
|
Div0:
|
|
mov edx, [ebp + PARAM1] /* Load pf into edx */
|
|
mov [edx + lMant], eax /* Store 0 in mantissa */
|
|
mov [edx + lExp], eax /* Store 0 in exponent */
|
|
|
|
pop ebx /* Return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_DivFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Div
|
|
*/
|
|
_FLOATOBJ_DivFloat@8:
|
|
PUBLIC _FLOATOBJ_DivFloat@8
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
|
|
mov eax, [ebp + PARAM2] /* Load f into eax */
|
|
lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push f on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
|
|
|
|
lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Div@8 /* Divide */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_DivLong(IN OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Div
|
|
*/
|
|
_FLOATOBJ_DivLong@8:
|
|
PUBLIC _FLOATOBJ_DivLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
|
|
mov eax, [ebp + PARAM2] /* Load l into eax */
|
|
lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push l on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
|
|
|
|
lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Div@8 /* Divide */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
/*******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_Add(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
|
|
*
|
|
*/
|
|
_FLOATOBJ_Add@8:
|
|
PUBLIC _FLOATOBJ_Add@8
|
|
push ebp
|
|
mov ebp, esp
|
|
push ebx
|
|
|
|
mov eax, [ebp + PARAM1] /* Load pointer to pf1 in eax */
|
|
mov ebx, [ebp + PARAM2] /* Load pointer to pf2 in ebx */
|
|
|
|
mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) */
|
|
mov edx, [ebx + lExp]
|
|
mov eax, [eax + lMant] /* Load float2 in (ebx,edx) */
|
|
mov ebx, [ebx + lMant]
|
|
|
|
cmp ecx, edx /* Check which one has the bigger lExp */
|
|
jl Add2
|
|
|
|
sub ecx, edx /* Calculate lExp1 - lExp2 */
|
|
sar eax, 1 /* Shift both mantissae 1 bit right */
|
|
sar ebx, 1
|
|
sar ebx, cl /* Shift lMant2 according to exponent difference */
|
|
|
|
add eax, ebx /* Add the manrissae */
|
|
jz AddIs0
|
|
|
|
cdq /* Calculate abs(mantissa) */
|
|
xor eax, edx
|
|
sub eax, edx
|
|
|
|
bsr ecx, eax /* Find most significant bit */
|
|
neg ecx /* and calculate needed normalize shift */
|
|
add ecx, 30
|
|
shl eax, cl
|
|
dec ecx
|
|
|
|
xor eax, edx /* Go back to original sign */
|
|
sub eax, edx
|
|
|
|
mov edx, [ebp + PARAM1] /* Reload pointer to float1 */
|
|
|
|
pop ebx
|
|
|
|
mov dword ptr [edx + lMant], eax /* Safe mantissa */
|
|
sub [edx + lExp], ecx /* Adjust exponent */
|
|
|
|
pop ebp /* Return */
|
|
ret 8
|
|
|
|
Add2:
|
|
sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */
|
|
mov ecx, edx
|
|
|
|
sar ebx, 1 /* Shift both mantissae 1 bit right */
|
|
sar eax, 1
|
|
sar eax, cl /* Shift lMant2 according to exponent difference */
|
|
|
|
add eax, ebx /* Add the manrissae */
|
|
jz AddIs0
|
|
|
|
mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */
|
|
add [ebx + lExp], ecx /* Adjust exponent part 1 */
|
|
|
|
cdq /* Calculate abs(mantissa) */
|
|
xor eax, edx
|
|
sub eax, edx
|
|
|
|
bsr ecx, eax /* Find most significant bit */
|
|
neg ecx /* and calculate needed normalize shift */
|
|
add ecx, 30
|
|
shl eax, cl
|
|
dec ecx
|
|
|
|
xor eax, edx /* Go back to original sign */
|
|
sub eax, edx
|
|
|
|
mov dword ptr [ebx + lMant], eax /* Safe mantissa and adjust exponent */
|
|
sub [ebx + lExp], ecx
|
|
|
|
pop ebx /* Return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
AddIs0:
|
|
/* Mantissa is 0, so float to (0,0) */
|
|
mov eax, [ebp + PARAM1]
|
|
pop ebx
|
|
mov dword ptr [eax + lMant], 0
|
|
mov dword ptr [eax + lExp], 0
|
|
pop ebp
|
|
ret 8
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_AddFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Add
|
|
*/
|
|
_FLOATOBJ_AddFloat@8:
|
|
PUBLIC _FLOATOBJ_AddFloat@8
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
|
|
mov eax, [ebp + PARAM2] /* Load f into eax */
|
|
lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push f on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
|
|
|
|
lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Add@8 /* Add */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_AddLong(IN OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Add
|
|
*/
|
|
_FLOATOBJ_AddLong@8:
|
|
PUBLIC _FLOATOBJ_AddLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
|
|
mov eax, [ebp + PARAM2] /* Load l into eax */
|
|
lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push l on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
|
|
|
|
lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Add@8 /* Add */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
/*******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_Sub(IN OUT PFLOATOBJ pf, IN PFLOATOBJ pf1);
|
|
*
|
|
*/
|
|
_FLOATOBJ_Sub@8:
|
|
PUBLIC _FLOATOBJ_Sub@8
|
|
push ebp
|
|
mov ebp, esp
|
|
push ebx
|
|
|
|
mov eax, [ebp + PARAM1] /* Load pointer to floats in eax and ebx */
|
|
mov ebx, [ebp + PARAM2]
|
|
|
|
mov ecx, [eax + lExp] /* Load float1 in (eax,ecx) and float2 in (ebx,edx) */
|
|
mov edx, [ebx + lExp]
|
|
mov eax, [eax + lMant]
|
|
mov ebx, [ebx + lMant]
|
|
|
|
cmp ecx, edx /* Check which one has the bigger lExp */
|
|
jl Sub2
|
|
|
|
sub ecx, edx /* Calculate lExp1 - lExp2 */
|
|
sar eax, 1 /* Shift both mantissae 1 bit right */
|
|
sar ebx, 1
|
|
sar ebx, cl /* Shift lMant2 according to exponent difference */
|
|
|
|
sub eax, ebx /* Substract the manrissae */
|
|
jz SubIs0
|
|
|
|
cdq /* Calculate abs(mantissa) */
|
|
xor eax, edx
|
|
sub eax, edx
|
|
|
|
bsr ecx, eax /* Find most significant bit */
|
|
neg ecx /* and calculate needed normalize shift */
|
|
add ecx, 30
|
|
shl eax, cl
|
|
dec ecx
|
|
|
|
xor eax, edx /* Go back to original sign */
|
|
sub eax, edx
|
|
|
|
mov edx, [ebp + PARAM1] /* Reload pointer to float1 */
|
|
|
|
pop ebx
|
|
|
|
mov dword ptr [edx + lMant], eax /* Safe mantissa and adjust exponent */
|
|
sub [edx + lExp], ecx
|
|
|
|
pop ebp
|
|
ret 8
|
|
|
|
Sub2:
|
|
sub edx, ecx /* Calculate lExp2 - lExp1 and put it into ecx */
|
|
mov ecx, edx
|
|
|
|
sar ebx, 1 /* Shift both mantissae 1 bit right */
|
|
sar eax, 1
|
|
sar eax, cl /* Shift lMant2 according to exponent difference */
|
|
|
|
sub eax, ebx /* Substract the manrissae */
|
|
jz AddIs0
|
|
|
|
mov ebx, [ebp + PARAM1] /* Reload pointer to float1 */
|
|
add [ebx + lExp], ecx /* Adjust exponent part 1 */
|
|
|
|
cdq /* Calculate abs(mantissa) */
|
|
xor eax, edx
|
|
sub eax, edx
|
|
|
|
bsr ecx, eax /* Find most significant bit */
|
|
neg ecx /* and calculate needed normalize shift */
|
|
add ecx, 30
|
|
shl eax, cl
|
|
dec ecx
|
|
|
|
xor eax, edx /* Go back to original sign */
|
|
sub eax, edx
|
|
|
|
mov dword ptr [ebx + lMant], eax /* Safe mantissa */
|
|
sub [ebx + lExp], ecx /* Adjust exponent */
|
|
|
|
pop ebx /* Return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
SubIs0:
|
|
/* Mantissa is 0, so float to (0,0) */
|
|
mov eax, [ebp + PARAM1]
|
|
pop ebx
|
|
mov dword ptr [eax + lMant], 0
|
|
mov dword ptr [eax + lExp], 0
|
|
pop ebp
|
|
ret 8
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_SubFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Sub
|
|
*/
|
|
_FLOATOBJ_SubFloat@8:
|
|
PUBLIC _FLOATOBJ_SubFloat@8
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
|
|
mov eax, [ebp + PARAM2] /* Load f into eax */
|
|
lea ecx, [ebp -4] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push f on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetFloat@8 /* Set the FLOATOBJ */
|
|
|
|
lea ecx, [ebp -4] /* Push pointer to local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Sub@8 /* Substract */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_SubLong(IN OUT PFLOATOBJ pf, IN LONG l);
|
|
*
|
|
* Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Sub
|
|
*/
|
|
_FLOATOBJ_SubLong@8:
|
|
PUBLIC _FLOATOBJ_SubLong@8
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 8 /* Make room for a FLOATOBJ on the stack */
|
|
|
|
mov eax, [ebp + PARAM2] /* Load l into eax */
|
|
lea ecx, [ebp -8] /* Load pointer to local FLOATOBJ into ecx */
|
|
push eax /* Push l on the stack */
|
|
push ecx /* Push pointer to local FLOATOBJ on the stack */
|
|
call _FLOATOBJ_SetLong@8 /* Set the local FLOATOBJ */
|
|
|
|
lea ecx, [ebp -8] /* Push pointer to the local FLOATOBJ on the stack */
|
|
push ecx
|
|
push [ebp + PARAM1] /* Push the FLOATOBJ param on the stack */
|
|
call _FLOATOBJ_Sub@8 /* Substract */
|
|
|
|
mov esp, ebp /* Cleanup and return */
|
|
pop ebp
|
|
ret 8
|
|
|
|
|
|
/*******************************************************************************
|
|
* VOID
|
|
* APIENTRY
|
|
* FLOATOBJ_Neg(IN OUT PFLOATOBJ pf);
|
|
*
|
|
*/
|
|
_FLOATOBJ_Neg@4:
|
|
PUBLIC _FLOATOBJ_Neg@4
|
|
push ebp
|
|
mov ebp, esp
|
|
|
|
mov ecx, [esp + PARAM1] /* Load pf into ecx */
|
|
neg dword ptr [ecx + lMant] /* Negate lMant1 */
|
|
|
|
pop ebp /* Return */
|
|
ret 4
|
|
|
|
END
|
|
/* EOF */
|