1600 lines
44 KiB
C
1600 lines
44 KiB
C
/*****************************************************************************/
|
|
/* SISCO SOFTWARE MODULE HEADER **********************************************/
|
|
/*****************************************************************************/
|
|
/* (c) Copyright Systems Integration Specialists Company, Inc., */
|
|
/* 2005 All Rights Reserved */
|
|
/* */
|
|
/* MODULE NAME : QuadLib.c */
|
|
/* PRODUCT(S) : Standard Time Management Library */
|
|
/* */
|
|
/* MODULE DESCRIPTION: */
|
|
/* 64-bit Math Simulation Library. */
|
|
/* Provided for platforms without native 64-bit support. */
|
|
/* */
|
|
/* MODIFICATION LOG: */
|
|
/* Date Who Rev Comments */
|
|
/* -------- --- --- ----------------------------------------------------- */
|
|
/* 06/07/06 RLH 02 Numerous features added, see stdtime.doc */
|
|
/* 01/18/06 RLH 01 Created */
|
|
/*****************************************************************************/
|
|
|
|
#include "stdtime.h"
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
int32_t QuadLibU64Cmp (QUADLIB_U64 x, QUADLIB_U64 y)
|
|
{
|
|
if (x.hi.u < y.hi.u) return -1;
|
|
if (x.hi.u > y.hi.u) return 1;
|
|
|
|
if (x.lo.u < y.lo.u) return -1;
|
|
if (x.lo.u > y.lo.u) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t QuadLibI64Cmp (QUADLIB_I64 x, QUADLIB_I64 y)
|
|
{
|
|
if (x.hi.i < y.hi.i) return -1;
|
|
if (x.hi.i > y.hi.i) return 1;
|
|
|
|
/* the unsigned compare on lo.u works correctly if x.hi.i == y.hi.i */
|
|
/* in case of negative numbers, when lo increases in unsigned */
|
|
/* magnitude, the 64-bit value is less negative, and so is a */
|
|
/* greater signed value, so nothing special needs to be done */
|
|
|
|
if (x.lo.u < y.lo.u) return -1;
|
|
if (x.lo.u > y.lo.u) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* GET/SET */
|
|
/*****************************************************************************/
|
|
|
|
|
|
#ifndef QUADLIB_ENABLED
|
|
|
|
/* get hi value of a 64-bit value when host has native support */
|
|
|
|
QUADLIB_STATIC int32_t QuadLibI64GetHi (QUADLIB_I64 x)
|
|
{
|
|
return (int32_t) QUADLIB_I64_HI(x);
|
|
|
|
} /* QuadLibI64GetHi */
|
|
|
|
QUADLIB_STATIC uint32_t QuadLibU64GetHi (QUADLIB_U64 x)
|
|
{
|
|
return (uint32_t) QUADLIB_U64_HI(x);
|
|
|
|
} /* QuadLibU64GetHi */
|
|
|
|
/* get lo value of a 64-bit value when host has native support */
|
|
|
|
QUADLIB_STATIC int32_t QuadLibI64GetLo (QUADLIB_I64 x)
|
|
{
|
|
return (int32_t) QUADLIB_I64_LO(x);
|
|
|
|
} /* QuadLibI64GetLo */
|
|
|
|
QUADLIB_STATIC uint32_t QuadLibU64GetLo (QUADLIB_U64 x)
|
|
{
|
|
return (uint32_t) QUADLIB_U64_LO(x);
|
|
|
|
} /* QuadLibU64GetLo */
|
|
|
|
|
|
/* set hi value of a 64-bit value when host has native support */
|
|
|
|
void QuadLibI64SetHi (QUADLIB_I64 *x, int32_t y)
|
|
{
|
|
(*(QUADLIB_I64_TYPE *)(x)).hi.i = y;
|
|
|
|
} /* QuadLibI64SetHi */
|
|
|
|
void QuadLibU64SetHi (QUADLIB_U64 *x, uint32_t y)
|
|
{
|
|
(*(QUADLIB_I64_TYPE *)(x)).hi.u = y;
|
|
|
|
} /* QuadLibU64SetHi */
|
|
|
|
/* set lo value of a 64-bit value when host has native support */
|
|
|
|
void QuadLibI64SetLo (QUADLIB_I64 *x, int32_t y)
|
|
{
|
|
(*(QUADLIB_I64_TYPE *)(x)).lo.i = y;
|
|
|
|
} /* QuadLibI64SetLo */
|
|
|
|
void QuadLibU64SetLo (QUADLIB_U64 *x, uint32_t y)
|
|
{
|
|
(*(QUADLIB_I64_TYPE *)(x)).lo.u = y;
|
|
|
|
} /* QuadLibU64SetLo */
|
|
|
|
#endif /* not QUADLIB_ENABLED */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* CAST */
|
|
/*****************************************************************************/
|
|
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
|
|
/* 64-bit to 64-bit conversions */
|
|
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64CastI64N(void * x, size_t n)
|
|
{
|
|
QUADLIB_I64 result;
|
|
|
|
/* determine type of cast based on sizeof(x) */
|
|
|
|
switch (n)
|
|
{
|
|
case 8:
|
|
QUADLIB_I64_HI(result) = QUADLIB_I64_HI(x);
|
|
QUADLIB_I64_LO(result) = QUADLIB_I64_LO(x);
|
|
break;
|
|
|
|
case 2:
|
|
QUADLIB_I64_HI(result) =
|
|
QUADLIB_I64_LO(result) = (*(short *)(&x));
|
|
QUADLIB_I64_HI(result) >>= 31; /* sign propagation */
|
|
break;
|
|
|
|
case 1:
|
|
QUADLIB_I64_HI(result) =
|
|
QUADLIB_I64_LO(result) = (*(char *)(&x));
|
|
QUADLIB_I64_HI(result) >>= 31; /* sign propagation */
|
|
break;
|
|
|
|
default:
|
|
/* assume length 4 */
|
|
QUADLIB_I64_HI(result) =
|
|
QUADLIB_I64_LO(result) = (*(long *)(&x));
|
|
QUADLIB_I64_HI(result) >>= 31; /* sign propagation */
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibI64CastI64N */
|
|
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64CastU64N(void * x, size_t n)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
/* determine type of cast based on sizeof(x) */
|
|
|
|
switch (n)
|
|
{
|
|
case 8:
|
|
QUADLIB_I64_HI(result) = QUADLIB_I64_HI(x);
|
|
QUADLIB_I64_LO(result) = QUADLIB_I64_LO(x);
|
|
break;
|
|
|
|
case 2:
|
|
QUADLIB_I64_HI(result) = 0;
|
|
QUADLIB_I64_LO(result) = (*(unsigned short *)(&x));
|
|
break;
|
|
|
|
case 1:
|
|
QUADLIB_I64_HI(result) = 0;
|
|
QUADLIB_I64_LO(result) = (*(unsigned char *)(&x));
|
|
break;
|
|
|
|
default:
|
|
/* assume length 4 */
|
|
QUADLIB_I64_HI(result) = 0;
|
|
QUADLIB_I64_LO(result) = (*(unsigned long *)(&x));
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibU64CastU64N */
|
|
|
|
|
|
QUADLIB_STATIC QUADLIB_I64N QuadLibI64NCastI64(QUADLIB_I64 x)
|
|
{
|
|
QUADLIB_I64N result;
|
|
|
|
#ifdef QUADLIB_NATIVE64_ENABLED
|
|
QUADLIB_I64_HI(result) = QUADLIB_I64_HI(x);
|
|
QUADLIB_I64_LO(result) = QUADLIB_I64_LO(x);
|
|
|
|
#else
|
|
/* x is a 32-bit value, so we can only return 32 bits of I64 value */
|
|
result = (QUADLIB_I64N) QUADLIB_I64_LO(x);
|
|
|
|
#endif
|
|
return result;
|
|
|
|
} /* QuadLibI64NCastI64 */
|
|
|
|
|
|
QUADLIB_STATIC QUADLIB_U64N QuadLibU64NCastU64(QUADLIB_U64 x)
|
|
{
|
|
QUADLIB_U64N result;
|
|
|
|
#ifdef QUADLIB_NATIVE64_ENABLED
|
|
QUADLIB_U64_HI(result) = QUADLIB_U64_HI(x);
|
|
QUADLIB_U64_LO(result) = QUADLIB_U64_LO(x);
|
|
|
|
#else
|
|
/* x is a 32-bit value, so we can only return 32 bits of I64 value */
|
|
result = (QUADLIB_U64N) QUADLIB_U64_LO(x);
|
|
|
|
#endif
|
|
return result;
|
|
|
|
} /* QuadLibU64NCastU64 */
|
|
|
|
|
|
/* upsize casts: 32 to 64 bit */
|
|
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64CastI32 (int32_t x)
|
|
{
|
|
QUADLIB_I64 result;
|
|
|
|
result.lo.i = x;
|
|
result.hi.i = x;
|
|
result.hi.i >>= 31; /* for signed, x propagation */
|
|
|
|
return result;
|
|
} /* QuadLibI64CastI32 */
|
|
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64CastU32 (uint32_t x)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = 0; /* for unsigned, 0 propagation */
|
|
result.lo.u = x;
|
|
|
|
return result;
|
|
} /* QuadLibU64CastU32 */
|
|
|
|
|
|
/* downsize casts: 64 to 32 bit */
|
|
|
|
|
|
QUADLIB_STATIC int32_t QuadLibI32CastI64 (QUADLIB_I64 x)
|
|
{
|
|
return x.lo.i;
|
|
} /* QuadLibI32CastI64 */
|
|
|
|
|
|
QUADLIB_STATIC uint32_t QuadLibU32CastU64 (QUADLIB_U64 x)
|
|
{
|
|
return x.lo.u;
|
|
} /* QuadLibU32CastU64 */
|
|
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Not */
|
|
/* form 1's complement of 64-bit value */
|
|
/*****************************************************************************/
|
|
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Not (QUADLIB_U64 x)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = ~(x.hi.u);
|
|
result.lo.u = ~(x.lo.u);
|
|
return result;
|
|
}
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Neg */
|
|
/* form 2's complement of 64-bit value */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Neg (QUADLIB_U64 x)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = ~(x.hi.u);
|
|
result.lo.u = (~(x.lo.u)) + 1;
|
|
|
|
/* if x.lo.u came in as 0, its complement is 0xFFFFFFFF */
|
|
/* if we then increment it, it will become 0 again */
|
|
/* so, if result.lo.u is zero now, there was a carry */
|
|
|
|
if (result.lo.u == 0)
|
|
{
|
|
result.hi.u++;
|
|
}
|
|
|
|
return result;
|
|
} /* QuadLibU64Neg */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Abs */
|
|
/* form absolute value of 64-bit value */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Abs (QUADLIB_U64 x)
|
|
{
|
|
if (x.hi.i < 0) /* value is negative */
|
|
{
|
|
return QUADLIB_U64_NEG (x);
|
|
}
|
|
|
|
return x; /* value is positive, do not negate */
|
|
|
|
} /* QuadLibU64Abs */
|
|
|
|
#else /* not QUADLIB_ENABLED */
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Abs (QUADLIB_U64 x)
|
|
{
|
|
if (x < 0) /* value is negative */
|
|
{
|
|
return (QUADLIB_U64) (-(QUADLIB_I64) x);
|
|
/* negate native I64 value */
|
|
}
|
|
|
|
return x; /* value is positive, do not negate */
|
|
|
|
} /* QuadLibU64Abs */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Mul */
|
|
/* multiply two unsigned 64-bit values. */
|
|
/* form partial products from 16-bit values to limit results to 32 bits. */
|
|
/* */
|
|
/* method: let ABCD mean four 16-bit values with 'one', and WXYZ in 'two' */
|
|
/* then, one * two = ABCD * WXYZ. in "long-hand" this means: */
|
|
/* */
|
|
/* (let xxL mean the Left 16 bits of a word, and xxR the Right 16 bits) */
|
|
/* */
|
|
/* A B C D */
|
|
/* W X Y Z */
|
|
/* -------------- */
|
|
/* AZ BZ CZ DZ */
|
|
/* AY BY CY DY */
|
|
/* AX BX CX DX */
|
|
/* AW BW CW DW */
|
|
/* */
|
|
/* express the partial sums as split L/R pairs, and discard partial sums */
|
|
/* that exceed the 64-bit result capacity. ("discard" means discard from */
|
|
/* the explanation; the discarded values are not actually calculated.) */
|
|
/* */
|
|
/* A B C D */
|
|
/* W X Y Z */
|
|
/* -------------- */
|
|
/* AZR BZR CZR DZR */
|
|
/* BZL CZL DZL */
|
|
/* BYR CYR DYR */
|
|
/* CYL DYL */
|
|
/* CXR DXR */
|
|
/* DXL */
|
|
/* DWR */
|
|
/* */
|
|
/* since there is no carry out of the left 32-bit value (the AB column), */
|
|
/* there is no need to split the left-most (AB column) 32-bit values into */
|
|
/* 16/16. so, we optimize the list of partial sums as follows, (where */
|
|
/* (xxL:xxR represents an unsplit 32-bit value), and reorganize the */
|
|
/* diagram to show the left/right relationships better: */
|
|
/* */
|
|
/* A B C D */
|
|
/* W X Y Z */
|
|
/* -------------- */
|
|
/* AZR */
|
|
/* bzL:bzR */
|
|
/* CZL CZR */
|
|
/* DZL DZR */
|
|
/* -------------- */
|
|
/* BYR */
|
|
/* cyL:cyR */
|
|
/* DYL DYR */
|
|
/* -------------- */
|
|
/* CXR */
|
|
/* dxL:dxR */
|
|
/* -------------- */
|
|
/* DWR */
|
|
/* */
|
|
/* finally, add up the columns, and store the sums in a 64-bit value */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
#define QUADLIB_U32_LWORD(x) ( ((uint32_t)(x)) >> 16)
|
|
#define QUADLIB_U32_RWORD(x) ((x) & 0xFFFF)
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Mul (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
uint32_t a, b, c, d, w, x, y, z;
|
|
uint32_t ab, bc, cd;
|
|
uint32_t az, bz, cz, dz;
|
|
uint32_t by, cy, dy;
|
|
uint32_t cx, dx;
|
|
uint32_t dw;
|
|
|
|
uint32_t azr, czr, dzr;
|
|
uint32_t czl, dzl;
|
|
uint32_t byr, dyr;
|
|
uint32_t dyl;
|
|
uint32_t cxr;
|
|
uint32_t dwr;
|
|
|
|
|
|
a = QUADLIB_U32_LWORD(one.hi.u);
|
|
b = QUADLIB_U32_RWORD(one.hi.u);
|
|
c = QUADLIB_U32_LWORD(one.lo.u);
|
|
d = QUADLIB_U32_RWORD(one.lo.u);
|
|
|
|
w = QUADLIB_U32_LWORD(two.hi.u);
|
|
x = QUADLIB_U32_RWORD(two.hi.u);
|
|
y = QUADLIB_U32_LWORD(two.lo.u);
|
|
z = QUADLIB_U32_RWORD(two.lo.u);
|
|
|
|
|
|
az = a * z; bz = b * z; cz = c * z; dz = d * z;
|
|
by = b * y; cy = c * y; dy = d * y;
|
|
cx = c * x; dx = d * x;
|
|
dw = d * w;
|
|
azr = QUADLIB_U32_RWORD(az);
|
|
czr = QUADLIB_U32_RWORD(cz);
|
|
dzr = QUADLIB_U32_RWORD(dz);
|
|
czl = QUADLIB_U32_LWORD(cz);
|
|
dzl = QUADLIB_U32_LWORD(dz);
|
|
byr = QUADLIB_U32_RWORD(by);
|
|
dyr = QUADLIB_U32_RWORD(dy);
|
|
dyl = QUADLIB_U32_LWORD(dy);
|
|
cxr = QUADLIB_U32_RWORD(cx);
|
|
dwr = QUADLIB_U32_RWORD(dw);
|
|
|
|
bc = czr + dzl + dyr;
|
|
|
|
ab = bc >> 16;
|
|
cd = bc << 16;
|
|
|
|
result.lo.u = cd + dzr;
|
|
|
|
result.hi.u = ab + bz + cy + dx
|
|
+ czl + dyl
|
|
+ ((azr + byr + cxr + dwr) << 16);
|
|
|
|
return result;
|
|
|
|
} /* QuadLibU64Mul */
|
|
|
|
#undef QUADLIB_U32_LWORD
|
|
#undef QUADLIB_U32_RWORD
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Add */
|
|
/* add two unsigned 64-bit values */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Add (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 sum;
|
|
uint32_t carry;
|
|
|
|
sum.lo.u = one.lo.u + two.lo.u;
|
|
sum.hi.u = one.hi.u + two.hi.u;
|
|
|
|
/* calculate carry using boolean algebra */
|
|
|
|
carry =
|
|
( (one.lo.u & two.lo.u) | ((one.lo.u ^ two.lo.u) & (~sum.lo.u)) ) >> 31;
|
|
|
|
sum.hi.u += carry;
|
|
|
|
return sum;
|
|
|
|
} /* QuadLibU64Add */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Sub */
|
|
/* subtract two unsigned 64-bit values */
|
|
/* method: negate second operand, and then add values */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Sub (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
return QuadLibU64Add (one, QUADLIB_U64_NEG (two));
|
|
} /* QuadLibU64Sub */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Add1 */
|
|
/* increment a 64-bit value */
|
|
/* method: add a constant 1 to a 64-bit value */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Add1 (
|
|
QUADLIB_U64 /*I*/ x)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = x.hi.u;
|
|
result.lo.u = x.lo.u + 1;
|
|
|
|
if (result.lo.u == 0)
|
|
{
|
|
/* x.lo.u must have had all 1 bits, so a carry occurred */
|
|
result.hi.u++;
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibU64Add1 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Sub1 */
|
|
/* decrement a 64-bit value */
|
|
/* method: add a constant -1 to a 64-bit value */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Sub1 (
|
|
QUADLIB_U64 /*I*/ x)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = x.hi.u;
|
|
result.lo.u = x.lo.u - 1;
|
|
|
|
if (x.lo.u == 0)
|
|
{
|
|
/* x.lo.u was 0, so a borrow occurred */
|
|
result.hi.u--;
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibU64Sub1 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64SHR */
|
|
/* shift an unsigned 64-bit value right by n bits */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64SHR (
|
|
QUADLIB_U64 /*I*/ value,
|
|
int32_t /*I*/ shift)
|
|
{
|
|
QUADLIB_U64 result = QUADLIB_ZERO;
|
|
|
|
if (shift == 0)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
if (shift < 0)
|
|
{
|
|
return QuadLibU64SHL (value, -shift);
|
|
}
|
|
|
|
if (shift > 63)
|
|
{
|
|
return result; /* all bits shifted out, return 0 */
|
|
}
|
|
|
|
for (result = value; shift > 0; shift--)
|
|
{
|
|
result.lo.u >>= 1;
|
|
|
|
if (result.hi.u & 1)
|
|
{
|
|
/* hi has low-order 1 about to be shifted out */
|
|
result.lo.u |= QUADLIB_U32_HIGHBIT;
|
|
}
|
|
|
|
result.hi.u >>= 1; /* unsigned shift right */
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibU64SHR */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64SHR */
|
|
/* shift a signed 64-bit value right by n bits */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64SHR (
|
|
QUADLIB_I64 /*I*/ value,
|
|
int32_t /*I*/ shift)
|
|
{
|
|
QUADLIB_I64 result = QUADLIB_ZERO;
|
|
|
|
if (shift == 0)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
if (shift < 0)
|
|
{
|
|
return QuadLibU64SHL (value, -shift);
|
|
}
|
|
|
|
if (shift > 63)
|
|
{
|
|
return result; /* all bits shifted out return 0 */
|
|
}
|
|
|
|
for (result = value; shift > 0; shift--)
|
|
{
|
|
result.lo.u >>= 1;
|
|
|
|
if (result.hi.u & 1)
|
|
{
|
|
/* hi has low-order 1 about to be shifted out */
|
|
result.lo.u |= QUADLIB_U32_HIGHBIT;
|
|
}
|
|
|
|
result.hi.i >>= 1; /* signed shift right */
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibI64SHR */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64SHL */
|
|
/* shift an unsigned 64-bit value left by n bits */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64SHL (
|
|
QUADLIB_U64 /*I*/ value,
|
|
int32_t /*I*/ shift)
|
|
{
|
|
QUADLIB_U64 result = QUADLIB_ZERO;
|
|
|
|
if (shift == 0)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
if (shift < 0)
|
|
{
|
|
return QuadLibU64SHR (value, -shift);
|
|
}
|
|
|
|
if (shift > 63)
|
|
{
|
|
return result; /* all bits shifted out return 0 */
|
|
}
|
|
|
|
for (result = value; shift > 0; shift--)
|
|
{
|
|
QUADLIB_U64_SHL1_EQ_INLINE (result);
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* QuadLibU64SHL */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64SHR1 */
|
|
/* shift a signed 64-bit value right by 1 bit */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64SHR1 (
|
|
QUADLIB_I64 /*I*/ value)
|
|
{
|
|
QUADLIB_I64_SHR1_EQ_INLINE (value);
|
|
|
|
return value;
|
|
|
|
} /* QuadLibI64SHR1 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64SHR1 */
|
|
/* shift an unsigned 64-bit value right by 1 bit */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64SHR1 (
|
|
QUADLIB_U64 /*I*/ value)
|
|
{
|
|
QUADLIB_U64_SHR1_EQ_INLINE (value);
|
|
|
|
return value;
|
|
|
|
} /* QuadLibU64SHR1 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64SHL1 */
|
|
/* shift an unsigned 64-bit value left by 1 bit */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64SHL1 (
|
|
QUADLIB_U64 /*I*/ value)
|
|
{
|
|
QUADLIB_U64_SHL1_EQ_INLINE (value);
|
|
|
|
return value;
|
|
|
|
} /* QuadLibU64SHL1 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64SHR4 */
|
|
/* shift a signed 64-bit value right by 1 bit */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64SHR4 (
|
|
QUADLIB_I64 /*I*/ value)
|
|
{
|
|
QUADLIB_I64_SHR4_EQ_INLINE (value);
|
|
|
|
return value;
|
|
|
|
} /* QuadLibI64SHR4 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64SHR4 */
|
|
/* shift an unsigned 64-bit value right by 1 bit */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64SHR4 (
|
|
QUADLIB_U64 /*I*/ value)
|
|
{
|
|
QUADLIB_U64_SHR4_EQ_INLINE (value);
|
|
|
|
return value;
|
|
|
|
} /* QuadLibU64SHR4 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64SHL4 */
|
|
/* shift an unsigned 64-bit value left by 1 bit */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64SHL4 (
|
|
QUADLIB_U64 /*I*/ value)
|
|
{
|
|
QUADLIB_U64_SHL4_EQ_INLINE (value);
|
|
|
|
return value;
|
|
|
|
} /* QuadLibU64SHL4 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Mul10 */
|
|
/* multiple an unsigned 64-bit value by 10 */
|
|
/* method: get value*2 and value*8 by shifting, and then add them */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Mul10 (
|
|
QUADLIB_U64 /*I*/ value)
|
|
{
|
|
QUADLIB_U64 value2;
|
|
QUADLIB_U64 value8;
|
|
QUADLIB_U64 result;
|
|
|
|
value2 = value;
|
|
QUADLIB_U64_SHL1_EQ_INLINE (value2);
|
|
|
|
value8 = value2;
|
|
QUADLIB_U64_SHL1_EQ_INLINE (value8);
|
|
QUADLIB_U64_SHL1_EQ_INLINE (value8);
|
|
|
|
result = QuadLibU64Add (value8, value2);
|
|
return result;
|
|
|
|
} /* QuadLibU64Mul10 */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* StrAToQuadLibU64 */
|
|
/* define a portable 64-bit unsigned atoi convervion */
|
|
/*****************************************************************************/
|
|
|
|
/* StrAToQuadLibU64 always defined */
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 StrAToQuadLibU64 (
|
|
char * /*I*/ str)
|
|
{
|
|
/* extract a decimal string and return unsigned int64 value */
|
|
|
|
QUADLIB_U64 result = QUADLIB_ZERO;
|
|
QUADLIB_U64 digit = QUADLIB_ZERO;
|
|
int32_t n;
|
|
|
|
if (str == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
while (isspace (*str))
|
|
{
|
|
str++; /* skip over whitespace */
|
|
}
|
|
|
|
/* handle hex value if present */
|
|
|
|
if ( (str[0] == '0') && ((str[1] == 'x') || (str[1] == 'X')) )
|
|
{
|
|
for (str+=2; *str; str++)
|
|
{
|
|
n = *str;
|
|
|
|
if ((n >= '0') && (n <= '9'))
|
|
{
|
|
n -= '0';
|
|
}
|
|
|
|
else if ((n >= 'A') && (n <= 'F'))
|
|
{
|
|
n = n - 'A' + 10;
|
|
}
|
|
|
|
else if ((n >= 'a') && (n <= 'f'))
|
|
{
|
|
n = n - 'a' + 10;
|
|
}
|
|
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
QUADLIB_I64_LO(digit) = n;
|
|
QUADLIB_U64_SHL1_EQ_INLINE (result);
|
|
QUADLIB_U64_ADD_EQ (result, digit);
|
|
} /* for */
|
|
|
|
return result;
|
|
}
|
|
|
|
for (; *str; str++)
|
|
{
|
|
n = (*str) - '0';
|
|
|
|
if ((n < 0) || (n > 9))
|
|
{
|
|
break;
|
|
}
|
|
|
|
QUADLIB_I64_LO(digit) = n;
|
|
QUADLIB_U64_MUL10_EQ (result);
|
|
QUADLIB_U64_ADD_EQ (result, digit);
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* StrAToQuadLibU64 */
|
|
|
|
/* StrAToQuadLibU64 always defined */
|
|
|
|
/*****************************************************************************/
|
|
/* StrAToQuadLibI64 */
|
|
/* define a portable 64-bit signed atoi convervion */
|
|
/*****************************************************************************/
|
|
|
|
/* StrAToQuadLibI64 always defined */
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 StrAToQuadLibI64 (
|
|
char * /*I*/ str)
|
|
{
|
|
/* extract a decimal string and return unsigned int64 value */
|
|
|
|
QUADLIB_I64 result = QUADLIB_ZERO;
|
|
QUADLIB_I64 digit = QUADLIB_ZERO;
|
|
char sign = ' ';
|
|
int32_t n;
|
|
|
|
if (str == NULL)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
while (isspace (*str))
|
|
{
|
|
str++; /* skip over whitespace */
|
|
}
|
|
|
|
if ((*str == '+') || (*str == '-'))
|
|
{
|
|
sign = *str;
|
|
str++; /* skip over sign */
|
|
}
|
|
|
|
/* handle hex value if present */
|
|
|
|
if ( (str[0] == '0') && ((str[1] == 'x') || (str[1] == 'X')) )
|
|
{
|
|
for (str+=2; *str; str++)
|
|
{
|
|
n = *str;
|
|
|
|
if ((n >= '0') && (n <= '9'))
|
|
{
|
|
n -= '0';
|
|
}
|
|
|
|
else if ((n >= 'A') && (n <= 'F'))
|
|
{
|
|
n = n - 'A' + 10;
|
|
}
|
|
|
|
else if ((n >= 'a') && (n <= 'f'))
|
|
{
|
|
n = n - 'a' + 10;
|
|
}
|
|
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
QUADLIB_I64_LO(digit) = n;
|
|
QUADLIB_U64_SHL1_EQ_INLINE (result);
|
|
QUADLIB_U64_ADD_EQ (result, digit);
|
|
} /* for */
|
|
|
|
if (sign == '-')
|
|
{
|
|
result = QUADLIB_I64_NEG (result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
for (; *str; str++)
|
|
{
|
|
n = (*str) - '0';
|
|
|
|
if ((n < 0) || (n > 9))
|
|
{
|
|
break;
|
|
}
|
|
|
|
QUADLIB_I64_LO(digit) = n;
|
|
QUADLIB_I64_MUL10_EQ (result);
|
|
QUADLIB_I64_ADD_EQ (result, digit);
|
|
}
|
|
|
|
if (sign == '-')
|
|
{
|
|
result = QUADLIB_I64_NEG (result);
|
|
}
|
|
|
|
return result;
|
|
|
|
} /* StrAToQuadLibI64 */
|
|
|
|
/* StrAToQuadLibI64 always defined */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64ToFixedStrA */
|
|
/* define a portable 64-bit unsigned itoa convervion */
|
|
/*****************************************************************************/
|
|
|
|
/* QuadLibU64ToFixedStrA always defined */
|
|
|
|
QUADLIB_STATIC void QuadLibU64ToFixedStrA (
|
|
QUADLIB_U64 /*I*/ qValue,
|
|
QUADLIB_STRINGA * /*O*/ pString)
|
|
{
|
|
QUADLIB_U64 value = qValue;
|
|
int32_t i;
|
|
int32_t n;
|
|
|
|
int32_t xdigit;
|
|
uint8_t sum [QUADLIB_STRING_LEN] = {0};
|
|
uint8_t carry;
|
|
|
|
char * factor;
|
|
static char * factor_table[16] =
|
|
{
|
|
"00000000000000000001",
|
|
"00000000000000000016",
|
|
"00000000000000000256",
|
|
"00000000000000004096",
|
|
"00000000000000065536",
|
|
"00000000000001048576",
|
|
"00000000000016777216",
|
|
"00000000000268435456",
|
|
"00000000004294967296",
|
|
"00000000068719476736",
|
|
"00000001099511627776",
|
|
"00000017592186044416",
|
|
"00000281474976710656",
|
|
"00004503599627370496",
|
|
"00072057594037927936",
|
|
"01152921504606846976",
|
|
};
|
|
|
|
/* grab 16 hex digits one at a time */
|
|
/* obtain the decimal factor for a '1' in that position */
|
|
/* multiply each decimal digit of the factor by the hex digit */
|
|
/* and add to sum */
|
|
|
|
for (i=0; i < 16; i++)
|
|
{
|
|
if (QUADLIB_U64_EQ_0 (value))
|
|
{
|
|
break;
|
|
}
|
|
|
|
xdigit = QUADLIB_U64_LO (value) & 0x0F;
|
|
QUADLIB_U64_SHR4_EQ (value);
|
|
|
|
if (xdigit == 0)
|
|
{
|
|
continue; /* nothing to do */
|
|
}
|
|
|
|
factor = factor_table [i];
|
|
|
|
/* highest value in any position is (15*9)+9 = 135+9 = 144 */
|
|
/* with a carry in of 9, the highest value is 153 */
|
|
/* recall that factor is ASCII when calculating the sum */
|
|
|
|
carry = 0;
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4244)
|
|
/* silence the VC compiler warning message: */
|
|
/* "conversion from 'int ' to 'unsigned __int8', possible loss of data" */
|
|
#endif
|
|
|
|
for (n = QUADLIB_STRING_LEN-1; n >= 0; n--)
|
|
{
|
|
sum[n] += (uint8_t) (((factor[n] & 0x0F) * xdigit) + carry);
|
|
carry = sum[n] / 10;
|
|
sum[n] %= 10;
|
|
}
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
/* copy sum to output, converting to ASCII */
|
|
|
|
for (n = 0; n < QUADLIB_STRING_LEN; n++)
|
|
{
|
|
pString->str[n] = (char) ((sum[n] & 0x0F) + '0');
|
|
}
|
|
|
|
pString->str[QUADLIB_STRING_LEN] = 0;
|
|
|
|
} /* QuadLibU64ToFixedStrA */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64ToFixedStrA */
|
|
/* define a portable 64-bit signed itoa convervion */
|
|
/*****************************************************************************/
|
|
|
|
/* QuadLibI64ToFixedStrA always defined */
|
|
|
|
QUADLIB_STATIC void QuadLibI64ToFixedStrA (
|
|
QUADLIB_I64 /*I*/ qValue,
|
|
QUADLIB_STRINGA * /*O*/ pString)
|
|
{
|
|
char sign = '0';
|
|
|
|
if (QUADLIB_I64_LT_0 (qValue))
|
|
{
|
|
qValue = QUADLIB_I64_NEG (qValue);
|
|
sign = '-';
|
|
}
|
|
|
|
QuadLibU64ToFixedStrA (* (QUADLIB_U64 *) &qValue, pString);
|
|
pString->str[0] = sign;
|
|
|
|
} /* QuadLibI64ToFixedStrA */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64ToStrA */
|
|
/* define a portable 64-bit signed itoa convervion, with zero suppression */
|
|
/*****************************************************************************/
|
|
|
|
/* QuadLibU64ToStrA always defined */
|
|
|
|
QUADLIB_STATIC void QuadLibU64ToStrA (
|
|
QUADLIB_U64 /*I*/ qValue,
|
|
QUADLIB_STRINGA * /*O*/ pString)
|
|
{
|
|
QUADLIB_STRINGA s;
|
|
int32_t source = 0;
|
|
int32_t target = 0;
|
|
|
|
QuadLibU64ToFixedStrA (qValue, &s);
|
|
|
|
/* copy back value, suppressing leading zeros */
|
|
|
|
while (s.str [source] == '0')
|
|
{
|
|
source++;
|
|
}
|
|
|
|
if (s.str [source] == 0)
|
|
{
|
|
pString->str [target++] = '0'; /* source is all zero */
|
|
}
|
|
|
|
while (s.str [source])
|
|
{
|
|
pString->str [target++] = s.str [source++];
|
|
}
|
|
|
|
pString->str [target] = 0;
|
|
|
|
} /* QuadLibU64ToStrA */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64ToStrA */
|
|
/* define a portable 64-bit signed itoa convervion, with zero suppression */
|
|
/*****************************************************************************/
|
|
|
|
/* QuadLibI64ToStrA always defined */
|
|
|
|
QUADLIB_STATIC void QuadLibI64ToStrA (
|
|
QUADLIB_I64 /*I*/ qValue,
|
|
QUADLIB_STRINGA * /*O*/ pString)
|
|
{
|
|
QUADLIB_STRINGA s;
|
|
int32_t source = 0;
|
|
int32_t target = 0;
|
|
|
|
QuadLibI64ToFixedStrA (qValue, &s);
|
|
|
|
/* copy back value, suppressing leading zeros */
|
|
|
|
if (s.str [source] == '-')
|
|
{
|
|
pString->str [target++] = s.str [source++];
|
|
}
|
|
|
|
while (s.str [source] == '0')
|
|
{
|
|
source++;
|
|
}
|
|
|
|
if (s.str [source] == 0)
|
|
{
|
|
pString->str [target++] = '0'; /* source is all zero */
|
|
}
|
|
|
|
while (s.str [source])
|
|
{
|
|
pString->str [target++] = s.str [source++];
|
|
}
|
|
|
|
pString->str [target] = 0;
|
|
|
|
} /* QuadLibI64ToStrA */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64DivMod */
|
|
/* divide two unsigned 64-bit values to produce a quotient and remainder */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64DivMod (
|
|
QUADLIB_U64 u64Dividend,
|
|
QUADLIB_U64 u64Divisor,
|
|
QUADLIB_U64 *pu64Remainder )
|
|
{
|
|
int32_t Count;
|
|
QUADLIB_U64 A_restore;
|
|
|
|
QUADLIB_U64 A = QUADLIB_ZERO;
|
|
QUADLIB_U64 M = u64Divisor;
|
|
QUADLIB_U64 Q = u64Dividend;
|
|
|
|
|
|
if ((u64Divisor.hi.u == 0)
|
|
&& (u64Divisor.lo.u == 0))
|
|
{
|
|
*pu64Remainder = A; /* 0 */
|
|
return A; /* 0 */
|
|
}
|
|
|
|
|
|
for (Count=64; Count; Count--)
|
|
{
|
|
/* shift A:Q left */
|
|
|
|
QUADLIB_U64_SHL1_EQ_INLINE (A);
|
|
|
|
if (Q.hi.i < 0) /* Q has high-order 1 bit */
|
|
{
|
|
A = QuadLibU64Add1(A); /* A gets low-order 1 bit */
|
|
}
|
|
|
|
QUADLIB_U64_SHL1_EQ_INLINE (Q); /* Q gets low-order 0 bit */
|
|
|
|
A_restore = A;
|
|
|
|
A = QuadLibU64Sub(A, M);
|
|
|
|
if (A.hi.i < 0) /* A has high-order 1 bit */
|
|
{
|
|
A = A_restore; /* Q has low-order 0 bit */
|
|
}
|
|
|
|
else
|
|
{
|
|
Q = QuadLibU64Add1(Q); /* Q gets low-order 1 bit */
|
|
}
|
|
|
|
} /* for */
|
|
|
|
*pu64Remainder = A;
|
|
return Q;
|
|
|
|
} /* QuadLibU64DivMod */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Div */
|
|
/* divide two signed 64-bit values to produce an unsigned quotient */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Div (
|
|
QUADLIB_U64 u64Dividend,
|
|
QUADLIB_U64 u64Divisor)
|
|
{
|
|
QUADLIB_U64 u64Remainder; /* dummy argument */
|
|
|
|
return QuadLibU64DivMod (u64Dividend, u64Divisor, &u64Remainder);
|
|
|
|
} /*QuadLibU64Div */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64Mod */
|
|
/* divide two signed 64-bit values to produce unsigned remainder (modulus) */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Mod (
|
|
QUADLIB_U64 u64Dividend,
|
|
QUADLIB_U64 u64Divisor)
|
|
{
|
|
QUADLIB_U64 u64Remainder;
|
|
|
|
QuadLibU64DivMod (u64Dividend, u64Divisor, &u64Remainder);
|
|
|
|
return u64Remainder;
|
|
|
|
} /*QuadLibU64Mod */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64DivMod */
|
|
/* divide two signed 64-bit values to produce a quotient and remainder */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64DivMod (
|
|
QUADLIB_I64 s64Dividend,
|
|
QUADLIB_I64 s64Divisor,
|
|
QUADLIB_I64 *ps64Remainder )
|
|
{
|
|
QUADLIB_I64 s64Quotient;
|
|
QUADLIB_U64 u64Dividend;
|
|
QUADLIB_U64 u64Divisor;
|
|
int32_t sign = 0;
|
|
|
|
if (s64Dividend.hi.i < 0)
|
|
{
|
|
u64Dividend = QUADLIB_I64_NEG (s64Dividend);
|
|
sign = 1;
|
|
}
|
|
|
|
else
|
|
{
|
|
u64Dividend = s64Dividend;
|
|
}
|
|
|
|
if (s64Divisor.hi.i < 0)
|
|
{
|
|
u64Divisor = QUADLIB_I64_NEG (s64Divisor);
|
|
sign ^= 1;
|
|
}
|
|
|
|
else
|
|
{
|
|
u64Divisor = s64Divisor;
|
|
}
|
|
|
|
s64Quotient = QuadLibU64DivMod (u64Dividend, u64Divisor, ps64Remainder);
|
|
|
|
if (sign)
|
|
{
|
|
/* signs of dividend and divisor are different, result is neg */
|
|
s64Quotient = QUADLIB_I64_NEG (s64Quotient);
|
|
}
|
|
|
|
/* remainder takes sign of dividend */
|
|
|
|
if (s64Dividend.hi.i < 0)
|
|
{
|
|
*ps64Remainder = QUADLIB_I64_NEG (*ps64Remainder);
|
|
}
|
|
|
|
return s64Quotient;
|
|
|
|
} /* QuadLibI64DivMod */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64Div */
|
|
/* divide two signed 64-bit values to produce a signed quotient */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64Div (
|
|
QUADLIB_I64 s64Dividend,
|
|
QUADLIB_I64 s64Divisor)
|
|
{
|
|
QUADLIB_U64 s64Remainder; /* dummy argument */
|
|
|
|
return QuadLibI64DivMod (s64Dividend, s64Divisor, &s64Remainder);
|
|
|
|
} /*QuadLibI64Div */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibI64Mod */
|
|
/* divide two signed 64-bit values to produce a signed remainder (modulus) */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64Mod (
|
|
QUADLIB_I64 s64Dividend,
|
|
QUADLIB_I64 s64Divisor)
|
|
{
|
|
QUADLIB_I64 s64Remainder;
|
|
|
|
QuadLibI64DivMod (s64Dividend, s64Divisor, &s64Remainder);
|
|
|
|
return s64Remainder;
|
|
|
|
} /*QuadLibI64Mod */
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* QuadLibU64DivMod - COMPATIBILITY MODE */
|
|
/* QuadLibI64DivMod - COMPATIBILITY MODE */
|
|
/* native I64 divide/modulus functions with I64 simulation not in effect */
|
|
/*****************************************************************************/
|
|
|
|
#ifndef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64DivMod (
|
|
QUADLIB_U64 u64Dividend,
|
|
QUADLIB_U64 u64Divisor,
|
|
QUADLIB_U64 *pu64Remainder)
|
|
{
|
|
if (pu64Remainder != NULL)
|
|
{
|
|
*pu64Remainder = u64Dividend % u64Divisor;
|
|
}
|
|
|
|
return u64Dividend / u64Divisor;
|
|
|
|
} /* QuadLibU64DivMod */
|
|
|
|
QUADLIB_STATIC QUADLIB_I64 QuadLibI64DivMod (
|
|
QUADLIB_I64 s64Dividend,
|
|
QUADLIB_I64 s64Divisor,
|
|
QUADLIB_I64 *ps64Remainder)
|
|
{
|
|
if (ps64Remainder != NULL)
|
|
{
|
|
*ps64Remainder = s64Dividend % s64Divisor;
|
|
}
|
|
|
|
return s64Dividend / s64Divisor;
|
|
|
|
} /* QuadLibI64DivMod */
|
|
|
|
#endif /* not QUADLIB_ENABLED */
|
|
|
|
|
|
/*****************************************************************************/
|
|
/* AND */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64And (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = one.hi.u & two.hi.u;
|
|
result.lo.u = one.lo.u & two.lo.u;
|
|
|
|
return result;
|
|
}
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64AndNot (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = one.hi.u & (~two.hi.u);
|
|
result.lo.u = one.lo.u & (~two.lo.u);
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* OR */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Or (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = one.hi.u | two.hi.u;
|
|
result.lo.u = one.lo.u | two.lo.u;
|
|
|
|
return result;
|
|
}
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64OrNot (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = one.hi.u | (~two.hi.u);
|
|
result.lo.u = one.lo.u | (~two.lo.u);
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|
|
/*****************************************************************************/
|
|
/* XOR */
|
|
/*****************************************************************************/
|
|
|
|
#ifdef QUADLIB_ENABLED
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64Xor (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = one.hi.u ^ two.hi.u;
|
|
result.lo.u = one.lo.u ^ two.lo.u;
|
|
|
|
return result;
|
|
}
|
|
|
|
QUADLIB_STATIC QUADLIB_U64 QuadLibU64XorNot (
|
|
QUADLIB_U64 /*I*/ one,
|
|
QUADLIB_U64 /*I*/ two)
|
|
{
|
|
QUADLIB_U64 result;
|
|
|
|
result.hi.u = one.hi.u ^ (~two.hi.u);
|
|
result.lo.u = one.lo.u ^ (~two.lo.u);
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif /* QUADLIB_ENABLED */
|
|
|