317 lines
8 KiB
C
317 lines
8 KiB
C
|
#include <limits.h>
|
||
|
|
||
|
#include "lsidefs.h"
|
||
|
#include "zqfromza.h"
|
||
|
|
||
|
|
||
|
#ifdef _X86_
|
||
|
|
||
|
/* =========================================================== */
|
||
|
/* */
|
||
|
/* Functions implemented on Intel X86 Assember */
|
||
|
/* */
|
||
|
/* =========================================================== */
|
||
|
|
||
|
#define HIWORD(x) DWORD PTR [x+4]
|
||
|
#define LOWORD(x) DWORD PTR [x]
|
||
|
|
||
|
|
||
|
long ZqFromZa_Asm (long dzqInch, long za)
|
||
|
{
|
||
|
long result;
|
||
|
__asm
|
||
|
{
|
||
|
mov eax, za;
|
||
|
cmp eax, 0
|
||
|
jge POSITIVE
|
||
|
|
||
|
neg eax
|
||
|
mul dzqInch;
|
||
|
add eax, czaUnitInch / 2
|
||
|
mov ecx, czaUnitInch
|
||
|
adc edx, 0
|
||
|
div ecx;
|
||
|
neg eax
|
||
|
jmp RETURN
|
||
|
|
||
|
POSITIVE:
|
||
|
|
||
|
mul dzqInch;
|
||
|
add eax, czaUnitInch / 2
|
||
|
mov ecx, czaUnitInch
|
||
|
adc edx, 0
|
||
|
div ecx;
|
||
|
|
||
|
RETURN:
|
||
|
|
||
|
mov result, eax
|
||
|
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
Assert (result == ZqFromZa_C (dzqInch, za));
|
||
|
*/
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/* D I V 6 4 _ A S M */
|
||
|
/*----------------------------------------------------------------------------
|
||
|
%%Function: Div64_Asm
|
||
|
%%Contact: antons
|
||
|
|
||
|
Intel assembler implementation of 64-bit division. The
|
||
|
orignal code was taken from lldiv.asm (VC++ 6.0).
|
||
|
|
||
|
----------------------------------------------------------------------------*/
|
||
|
|
||
|
__int64 Div64_Asm (__int64 DVND, __int64 DVSR)
|
||
|
{
|
||
|
__int64 result;
|
||
|
|
||
|
__asm {
|
||
|
|
||
|
xor edi,edi // result sign assumed positive
|
||
|
|
||
|
mov eax,HIWORD(DVND) // hi word of a
|
||
|
or eax,eax // test to see if signed
|
||
|
jge L1 // skip rest if a is already positive
|
||
|
inc edi // complement result sign flag
|
||
|
mov edx,LOWORD(DVND) // lo word of a
|
||
|
neg eax // make a positive
|
||
|
neg edx
|
||
|
sbb eax,0
|
||
|
mov HIWORD(DVND),eax // save positive value
|
||
|
mov LOWORD(DVND),edx
|
||
|
L1:
|
||
|
mov eax,HIWORD(DVSR) // hi word of b
|
||
|
or eax,eax // test to see if signed
|
||
|
jge L2 // skip rest if b is already positive
|
||
|
inc edi // complement the result sign flag
|
||
|
mov edx,LOWORD(DVSR) // lo word of a
|
||
|
neg eax // make b positive
|
||
|
neg edx
|
||
|
sbb eax,0
|
||
|
mov HIWORD(DVSR),eax // save positive value
|
||
|
mov LOWORD(DVSR),edx
|
||
|
L2:
|
||
|
|
||
|
// Now do the divide. First look to see if the divisor is less than 4194304K.
|
||
|
// If so, then we can use a simple algorithm with word divides, otherwise
|
||
|
// things get a little more complex.
|
||
|
//
|
||
|
// NOTE - eax currently contains the high order word of DVSR
|
||
|
|
||
|
or eax,eax // check to see if divisor < 4194304K
|
||
|
jnz L3 // nope, gotta do this the hard way
|
||
|
mov ecx,LOWORD(DVSR) // load divisor
|
||
|
mov eax,HIWORD(DVND) // load high word of dividend
|
||
|
xor edx,edx
|
||
|
div ecx // eax <- high order bits of quotient
|
||
|
mov ebx,eax // save high bits of quotient
|
||
|
mov eax,LOWORD(DVND) // edx:eax <- remainder:lo word of dividend
|
||
|
div ecx // eax <- low order bits of quotient
|
||
|
mov edx,ebx // edx:eax <- quotient
|
||
|
jmp L4 // set sign, restore stack and return
|
||
|
|
||
|
//
|
||
|
// Here we do it the hard way. Remember, eax contains the high word of DVSR
|
||
|
//
|
||
|
|
||
|
L3:
|
||
|
mov ebx,eax // ebx:ecx <- divisor
|
||
|
mov ecx,LOWORD(DVSR)
|
||
|
mov edx,HIWORD(DVND) // edx:eax <- dividend
|
||
|
mov eax,LOWORD(DVND)
|
||
|
L5:
|
||
|
shr ebx,1 // shift divisor right one bit
|
||
|
rcr ecx,1
|
||
|
shr edx,1 // shift dividend right one bit
|
||
|
rcr eax,1
|
||
|
or ebx,ebx
|
||
|
jnz L5 // loop until divisor < 4194304K
|
||
|
div ecx // now divide, ignore remainder
|
||
|
mov esi,eax // save quotient
|
||
|
|
||
|
/*
|
||
|
// We may be off by one, so to check, we will multiply the quotient
|
||
|
// by the divisor and check the result against the orignal dividend
|
||
|
// Note that we must also check for overflow, which can occur if the
|
||
|
// dividend is close to 2**64 and the quotient is off by 1.
|
||
|
|
||
|
*/
|
||
|
|
||
|
mul HIWORD(DVSR) // QUOT * HIWORD(DVSR)
|
||
|
mov ecx,eax
|
||
|
mov eax,LOWORD(DVSR)
|
||
|
mul esi // QUOT * LOWORD(DVSR)
|
||
|
add edx,ecx // EDX:EAX = QUOT * DVSR
|
||
|
jc L6 // carry means Quotient is off by 1
|
||
|
|
||
|
//
|
||
|
// do long compare here between original dividend and the result of the
|
||
|
// multiply in edx:eax. If original is larger or equal, we are ok, otherwise
|
||
|
// subtract one (1) from the quotient.
|
||
|
//
|
||
|
|
||
|
cmp edx,HIWORD(DVND) // compare hi words of result and original
|
||
|
ja L6 // if result > original, do subtract
|
||
|
jb L7 // if result < original, we are ok
|
||
|
cmp eax,LOWORD(DVND) // hi words are equal, compare lo words
|
||
|
jbe L7 // if less or equal we are ok, else subtract
|
||
|
L6:
|
||
|
dec esi // subtract 1 from quotient
|
||
|
L7:
|
||
|
xor edx,edx // edx:eax <- quotient
|
||
|
mov eax,esi
|
||
|
|
||
|
//
|
||
|
// Just the cleanup left to do. edx:eax contains the quotient. Set the sign
|
||
|
// according to the save value, cleanup the stack, and return.
|
||
|
//
|
||
|
|
||
|
L4:
|
||
|
dec edi // check to see if result is negative
|
||
|
jnz L8 // if EDI == 0, result should be negative
|
||
|
neg edx // otherwise, negate the result
|
||
|
neg eax
|
||
|
sbb edx,0
|
||
|
|
||
|
//
|
||
|
// Restore the saved registers and return.
|
||
|
//
|
||
|
|
||
|
L8:
|
||
|
mov HIWORD(result),edx
|
||
|
mov LOWORD(result),eax
|
||
|
|
||
|
}; /* ASM */
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* M U L 6 4 _ A S M */
|
||
|
/*----------------------------------------------------------------------------
|
||
|
%%Function: Mul64_Asm
|
||
|
%%Contact: antons
|
||
|
|
||
|
Intel assembler implementation of 64-bit multiplication. The
|
||
|
orignal code was taken from llmul.asm (VC++ 6.0).
|
||
|
|
||
|
----------------------------------------------------------------------------*/
|
||
|
|
||
|
__int64 Mul64_Asm (__int64 A, __int64 B)
|
||
|
{
|
||
|
__int64 result;
|
||
|
|
||
|
__asm {
|
||
|
|
||
|
mov eax,HIWORD(A)
|
||
|
mov ecx,LOWORD(B)
|
||
|
|
||
|
mul ecx // eax has AHI, ecx has BLO, so AHI * BLO
|
||
|
mov esi,eax // save result
|
||
|
|
||
|
mov eax,LOWORD(A)
|
||
|
mul HIWORD(B) // ALO * BHI
|
||
|
add esi,eax // ebx = ((ALO * BHI) + (AHI * BLO))
|
||
|
|
||
|
mov eax,LOWORD(A) // ecx = BLO
|
||
|
mul ecx // so edx:eax = ALO*BLO
|
||
|
add edx,esi // now edx has all the LO*HI stuff
|
||
|
|
||
|
mov HIWORD(result),edx
|
||
|
mov LOWORD(result),eax
|
||
|
|
||
|
}; /* ASM */
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/* =========================================================== */
|
||
|
/* */
|
||
|
/* End of Assembler functions */
|
||
|
/* */
|
||
|
/* =========================================================== */
|
||
|
|
||
|
#endif /* _X86_ */
|
||
|
|
||
|
|
||
|
long ZqFromZa_C (long dzqInch, long za)
|
||
|
{
|
||
|
long cInches;
|
||
|
long zaExtra;
|
||
|
|
||
|
if (za < 0)
|
||
|
{
|
||
|
Assert (((long) -za) > 0); /* Check for overflow */
|
||
|
return -ZqFromZa_C (dzqInch, -za);
|
||
|
};
|
||
|
|
||
|
Assert(0 <= za);
|
||
|
Assert(0 < dzqInch && dzqInch < zqLim);
|
||
|
Assert(0 < czaUnitInch);
|
||
|
|
||
|
cInches = za / czaUnitInch;
|
||
|
zaExtra = za % czaUnitInch;
|
||
|
|
||
|
return (cInches * dzqInch) +
|
||
|
((zaExtra * dzqInch) + (czaUnitInch/2)) / czaUnitInch;
|
||
|
}
|
||
|
|
||
|
long ZaFromZq(long dzqInch, long zq)
|
||
|
{
|
||
|
long cInches;
|
||
|
long zqExtra;
|
||
|
|
||
|
if (zq < 0)
|
||
|
return -ZaFromZq(dzqInch, -zq);
|
||
|
|
||
|
Assert(0 <= zq);
|
||
|
Assert(0 < dzqInch && dzqInch < zqLim);
|
||
|
Assert(0 < czaUnitInch);
|
||
|
|
||
|
cInches = zq / dzqInch;
|
||
|
zqExtra = zq % dzqInch;
|
||
|
|
||
|
return (cInches * czaUnitInch) +
|
||
|
((zqExtra * czaUnitInch) + ((unsigned long) dzqInch/2)) / dzqInch;
|
||
|
}
|
||
|
|
||
|
|
||
|
long LsLwMultDivR(long l, long lNumer, long lDenom)
|
||
|
{
|
||
|
__int64 llT;
|
||
|
|
||
|
Assert(lDenom != 0);
|
||
|
if (lDenom == 0) /* this is really sloppy! Don't depend on this! */
|
||
|
return LONG_MAX;
|
||
|
|
||
|
if (l == 0)
|
||
|
return 0;
|
||
|
|
||
|
if (lNumer == lDenom)
|
||
|
return l;
|
||
|
|
||
|
llT = Mul64 (l, lNumer);
|
||
|
|
||
|
if ( (l ^ lNumer ^ lDenom) < 0) /* xor sign bits to give result sign */
|
||
|
llT -= lDenom / 2;
|
||
|
else
|
||
|
llT += lDenom / 2;
|
||
|
|
||
|
if ((__int64)(long)llT == llT) /* Did the multiply fit in 32-bits */
|
||
|
return ( ((long)llT) / lDenom); /* If so, do a 32-bit divide. */
|
||
|
|
||
|
llT = Div64 (llT, lDenom);
|
||
|
|
||
|
if (llT > LONG_MAX)
|
||
|
return LONG_MAX;
|
||
|
else if (llT < LONG_MIN)
|
||
|
return LONG_MIN;
|
||
|
else
|
||
|
return (long) llT;
|
||
|
|
||
|
}
|