/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include <blc_float.h>
#include <misc/multiply.h>

/*
*	Table of various negative powers of 10, for DblToAscii()
*/

const MULT	_blc_float_neg[] = {

	{ { 0xd267caa8, 0x62a12d66, 0xd072df63 }, -209, -695 },
	{ { 0xaae103b5, 0xfcd2a881, 0xd652bdc2 },  -95, -316 },
	{ { 0xb9447093, 0x8fa89bce, 0xf808e40e },  -76, -253 },
	{ { 0xc8de0475, 0x64d20a8b, 0xf245825a },  -57, -190 },
	{ { 0xd9c7dced, 0x53c72255, 0x96e7bd35 },  -38, -127 },
	{ { 0xec1e4a7d, 0xb69561a5, 0x2b31e9e3 },  -19,  -64 }
};

/*
*	Table of various positive powers of 10, for DblToAscii()
*/

const MULT	_blc_float_pos[] = {

	{ { 0x9bbcc7a1, 0x42b17ccb, 0x88a66076 }, 209, 694 },
	{ { 0xbfc2ef45, 0x6ae276e8, 0x9e3fedd8 },  95, 315 },
	{ { 0xb0de6538, 0x8cc8ada8, 0x3b25a55f },  76, 252 },
	{ { 0xa321f2d7, 0x226895c7, 0xaff72d52 },  57, 189 },
	{ { 0x96769950, 0xb50d88f4, 0x13144480 },  38, 126 },
	{ { 0x8ac72304, 0x89e80000, 0x00000000 },  19,  63 }
};

/*
*	Multiplies a 96 bit number with an other
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*	The upper 96 bits of the 192 bit result are kept and returned
*	in the first operand. The operands consist of three 32-bit words, in
*	big-endian word order (the format of the words themselves is irrelevant).
*	The result is rounded. If the result's top bit would be 0, then it
*	will be shifted up by 1 bit. Returns +1 if it shifted the result up
*	and 0 if not. It will never have to shift the result to the right.
*/

int		_blc_float_umul96x96( unsigned int *acc, const unsigned int *tag )
{
unsigned long long	x, y;
unsigned int		a, b, s;

	// Do the 96x96 multiply. We throw away the last 64 bits of the result
	// but keep them OR-ed together in 's', for rounding purposes.
	// The final result's upper 64 bits will be in 'x', the lower 32 bits
	// in 'a' and the next 32 bits (that we will discard later) in 'b'.

	x = umul32x32_64( acc[ 2 ], tag[ 2 ] );
	a = x >> 32;
	s = x;

	x = umul32x32_64( acc[ 2 ], tag[ 1 ] ) + a;
	a = x;
	y = x >> 32;

	x = umul32x32_64( acc[ 1 ], tag[ 2 ] ) + a;
	s = s | x;
	y = y  + ( x >> 32 );
	a = y;
	y = y >> 32;

	x = umul32x32_64( acc[ 2 ], tag[ 0 ] ) + a;
	a = x;
	y = y + ( x >> 32 );

	x = umul32x32_64( acc[ 1 ], tag[ 1 ] ) + a;
	a = x;
	y = y + ( x >> 32 );

	x = umul32x32_64( acc[ 0 ], tag[ 2 ] ) + a;
	b = x;
	y = y + ( x >> 32 );
	a = y;
	y = y >> 32;

	x = umul32x32_64( acc[ 1 ], tag[ 0 ] ) + a;
	a = x;
	y = y + ( x >> 32 );

	x = umul32x32_64( acc[ 0 ], tag[ 1 ] ) + a;
	a = x;
	y = y + ( x >> 32 );

	x = umul32x32_64( acc[ 0 ], tag[ 0 ] ) + y;

	// Normalise the result

	if ( ( x >> 63 ) ) {

		acc[ 0 ] = x >> 32;
		acc[ 1 ] = x;
		acc[ 2 ] = a;
		a = 0;
	}
	else {

		acc[ 0 ] = x >> 31;
		acc[ 1 ] = ((unsigned int) x << 1 ) | ( a >> 31 );
		acc[ 2 ] = ( a << 1 ) | ( b >> 31 );
		b <<= 1;
		a = 1;
	}

	// Round the result, using IEEE round-to-nearest rules. Here's a short
	// description: L is the last bit of the result that you keep, G is
	// the first bit you discard, R is the next bit and S is all bits
	// after that OR-ed together (i.e. if there are any 1-s in all the bits
	// below R. Then the rules are the following:
	//
	//	L G R S
	//	x 0 x x         do not round (throw away everything below L)
	//	0 1 0 0         do not round (throw away everything below L)
	//	1 1 x x         round up (add 1 to the result at L)
	//	x 1 1 x         round up (add 1 to the result at L)
	//	x 1 x 1         round up (add 1 to the result at L)

	if ( ( b & 0x80000000 ) &&					// G
		 ( ( acc[ 2 ] & 1 ) ||					// L
		   ( b & 0x40000000 ) ||				// R
		   ( b & 0x3fffffff || s > 0 ) ) ) {	// S

		if ( ! ++acc[ 2 ] && ! ++acc[ 1 ] && ! ++acc[ 0 ] ) {

			// In theory this could not happen, since when you multiply
			// ff...ff * ff...ff the result is ff...fe 00...01. However,
			// if the result was 7fff...ff f0...00 then we normalised the
			// the result, making it ffff...ff e0...00 which we will then
			// round up and *then* we get here.

			acc[ 0 ] = 0x80000000;
			acc[ 1 ] = 0;
			acc[ 2 ] = 0;
			a--;
		}
	}

	return( a );
}

