
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//                             Low level maths                               //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "..\include.h"

///////////////////////////////////////////////////////////////////////////////
// multiply 2 entries, rH:rL = a * bH:bL

void MulWW(buint* rL, buint* rH, buint a, buintH bL, buintH bH)
{
	//       bHbL
	//     x aHaL
	//-------------
	//       r0r0
	//     r1r1
	//     r2r2
	//   r3r3
	//-------------
	//       r012r0
	// r3r123

	// multiply elements (max. FFFF * FFFF = FFFE0001)
	buint aL = a & BIGMASK12;
	buint r0 = aL*bL;
	buint r1 = aL*bH;
	buint aH = a >> BIGBITS12;
	buint r2 = aH*bL;
	buint r3 = aH*bH;

	// add elements
	r1 += r0 >> BIGBITS12; // max. FFFE0001 + FFFE = FFFEFFFF no carry
	r1 += r2; // max. FFFEFFFF + FFFE0001 = 1FFFD0000 can carry
	if (r1 < r2) r3 += (buint)1 << BIGBITS12; // add carry, FFFE0001 + 10000 = FFFF0001 no carry

	// result, max. FFFFFFFF * FFFFFFFF = FFFFFFFE:00000001
	*rL = (r1 << BIGBITS12) + (r0 & BIGMASK12); // result low, FFFF0000 + FFFF = FFFFFFFF no carry
	*rH = r3 + (r1 >> BIGBITS12); // result high, FFFF0001 + FFFD = FFFFFFFE no carry 
}

///////////////////////////////////////////////////////////////////////////////
// multiply 2 entries, rH:rL = a * bL (bH = 0)

void MulWL(buint* rL, buint* rH, buint a, buintH bL)
{
	//         bL
	//     x aHaL
	//-------------
	//       r0r0
	//     r2r2
	//-------------
	//       r02r0
	//     r2

	// multiply elements (max. FFFF * FFFF = FFFE0001)
	buint aL = a & BIGMASK12;
	buint r0 = aL*bL;
	buint aH = a >> BIGBITS12;
	buint r2 = aH*bL;

	// add elements
	r2 += r0 >> BIGBITS12; // max. FFFE0001 + FFFE = FFFEFFFF no carry

	// result, max. FFFFFFFF * 0000FFFF = 0000FFFE:FFFF0001
	*rL = (r2 << BIGBITS12) + (r0 & BIGMASK12); // result low, FFFF0000 + FFFF = FFFFFFFF no carry
	*rH = r2 >> BIGBITS12; // result high, max. 0000FFFE
}

///////////////////////////////////////////////////////////////////////////////
// square entry, rH:rL = a * a

void SqrWW(buint* rL, buint* rH, buint a)
{
	//       aHaL
	//     x aHaL
	//-------------
	//       r0r0
	//    2*r1r1
	//   r3r3
	//-------------
	//       r01r0
	//  r3r13

	// multiply elements (max. FFFF * FFFF = FFFE0001)
	buint aL = a & BIGMASK12;
	buint aH = a >> BIGBITS12;
	buint r0 = aL*aL;
	buint r1 = aL*aH;
	buint r2 = r1;
	buint r3 = aH*aH;

	// add elements
	r1 += r0 >> BIGBITS12; // max. FFFE0001 + FFFE = FFFEFFFF no carry
	r1 += r2; // max. FFFEFFFF + FFFE0001 = 1FFFD0000 can carry
	if (r1 < r2) r3 += (buint)1 << BIGBITS12; // add carry, FFFE0001 + 10000 = FFFF0001 no carry

	// result, max. FFFFFFFF * FFFFFFFF = FFFFFFFE:00000001
	*rL = (r1 << BIGBITS12) + (r0 & BIGMASK12); // result low, FFFF0000 + FFFF = FFFFFFFF no carry
	*rH = r3 + (r1 >> BIGBITS12); // result high, FFFF0001 + FFFD = FFFFFFFE no carry 
}

///////////////////////////////////////////////////////////////////////////////
// add 2 dbl-entries, r = a + b

void AddWW(buint* rL, buint* rH, buint aL, buint aH, buint bL, buint bH)
{
	buint r = aL + bL;
	*rH = aH + bH + ((r < aL) ? 1 : 0);
	*rL = r;
}

///////////////////////////////////////////////////////////////////////////////
// sub 2 dbl-entries, r = a - b

void SubWW(buint* rL, buint* rH, buint aL, buint aH, buint bL, buint bH)
{
	buint r = aL - bL;
	*rH = aH - bH - ((aL < bL) ? 1 : 0);
	*rL = r;
}

///////////////////////////////////////////////////////////////////////////////
// divide 3-entry by 2-entry, r = a / b

void DivWW(buint* rX, buint* rH, buint* rL, buint aX, buint aH, buint aL, buint bX, buint bH, buint bL)
{
	//buint t, tH, tL, m;
	//bignum::MulWW(rX, &t, aX, 

// !!!!!!!!!!!!!


}
