diff --git a/reactos/subsystems/win32/win32k/eng/i386/floatobj.S b/reactos/subsystems/win32/win32k/eng/i386/floatobj.S new file mode 100644 index 00000000000..268db69023c --- /dev/null +++ b/reactos/subsystems/win32/win32k/eng/i386/floatobj.S @@ -0,0 +1,1155 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Win32 subsystem + * PURPOSE: FLOATOBJ floating point emulation functions for x86 + * FILE: subsystems/win32/win32k/objects/i386/floatobj.S + * PROGRAMMER: Timo Kreuzer + */ + + +/******************************************************************************* + * 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, beacuse 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, tested + * 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 + */ + +.intel_syntax noprefix +.text + +#define lMant 0 +#define lExp 4 + +#define PARAM1 8 +#define PARAM2 12 + +/****************************************************************************** + * VOID + * APIENTRY + * FLOATOBJ_SetFloat(IN OUT PFLOATOBJ pf, IN FLOATL f); + */ +_FLOATOBJ_SetFloat@8: +.global _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, 0x7f800000 /* 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, 0x7fffffff /* Mask out invalid field in the mantissa */ + + shr eax, 23 /* Shift the exponent in eax in place */ + or ecx, 0x40000000 /* Set bit for 1 in the mantissa */ + and eax, 0xff /* 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: +.global _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, 0xff /* Mask out invalid fields in the exponent */ + and eax, 0x3fffffff /* Mask out invalid fields in mantissa */ + + shl ecx, 23 /* Shift exponent in place */ + shr eax, 7 /* Shift mantissa in place */ + + and edx, 0x80000000 /* 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: +.global _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 + + +/******************************************************************************* + * LONG + * APIENTRY + * FLOATOBJ_GetLong(IN PFLOATOBJ pf); + * + */ +_FLOATOBJ_GetLong@4: +.global _FLOATOBJ_GetLong@4 + push ebp + mov ebp, esp + + mov edx, [ebp + PARAM1] /* Load pf into edx */ + mov ecx, 32 /* Load (32 - lExp) into ecx */ + sub ecx, [edx + lExp] + jle short GetLong2 /* Check for Overflow */ + + mov eax, [edx + lMant] /* Load mantissa into eax */ + sar eax, cl /* Signed shift mantissa according to exponent */ + + pop ebp /* Return */ + ret 4 + +GetLong2: + xor eax, eax /* Overflow, return 0 */ + pop ebp + ret 4 + + +/****************************************************************************** + * BOOL + * APIENTRY + * FLOATOBJ_Equal(IN PFLOATOBJ pf1, IN PFLOATOBJ pf2); + */ +_FLOATOBJ_Equal@8: +.global _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: +.global _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: +.global _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: +.global _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: +.global _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: +.global _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: +.global _FLOATOBJ_Mul@8 +//jmp _FLOATOBJ_Mul2@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, 0x80000000 /* 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: +.global _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: +.global _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: +.global _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, 0x80000000 + 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: +.global _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: +.global _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 */ + + pop ebp /* Cleanup and return */ + ret 8 + + +/******************************************************************************* + * VOID + * APIENTRY + * FLOATOBJ_Add(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2); + * + */ +_FLOATOBJ_Add@8: +.global _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: +.global _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: +.global _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: +.global _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: +.global _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: +.global _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: +.global _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 + + +/* EOF */