/*
* linux/arch/arm/vfp/vfpdouble.c
*
* This code is derived in part from John R. Housers softfloat library, which
* carries the following notice:
*
* ===========================================================================
* This C source file is part of the SoftFloat IEC/IEEE Floating-point
* Arithmetic Package, Release 2.
*
* Written by John R. Hauser. This work was made possible in part by the
* International Computer Science Institute, located at Suite 600, 1947 Center
* Street, Berkeley, California 94704. Funding was partially provided by the
* National Science Foundation under grant MIP-9311980. The original version
* of this code was written as part of a project to build a fixed-point vector
* processor in collaboration with the University of California at Berkeley,
* overseen by Profs. Nelson Morgan and John Wawrzynek. More information
* is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
* arithmetic/softfloat.html'.
*
* THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
* has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
* TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
* PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
* AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
*
* Derivative works are acceptable, even for commercial purposes, so long as
* (1) they include prominent notice that the work is derivative, and (2) they
* include prominent notice akin to these three paragraphs for those parts of
* this code that are retained.
* ===========================================================================
*/
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <asm/div64.h>
#include <asm/vfp.h>
#include "vfpinstr.h"
#include "vfp.h"
static struct vfp_double vfp_double_default_qnan = {
.exponent = 2047,
.sign = 0,
.significand = VFP_DOUBLE_SIGNIFICAND_QNAN,
};
static void vfp_double_dump(const char *str, struct vfp_double *d)
{
pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
str, d->sign != 0, d->exponent, d->significand);
}
static void vfp_double_normalise_denormal(struct vfp_double *vd)
{
int bits = 31 - fls(vd->significand >> 32);
if (bits == 31)
bits = 63 - fls(vd->significand);
vfp_double_dump("normalise_denormal: in", vd);
if (bits) {
vd->exponent -= bits - 1;
vd->significand <<= bits;
}
vfp_double_dump("normalise_denormal: out", vd);
}
u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
{
u64 significand, incr;
int exponent, shift, underflow;
u32 rmode;
vfp_double_dump("pack: in", vd);
/*
* Infinities and NaNs are a special case.
*/
if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
goto pack;
/*
* Special-case zero.
*/
if (vd->significand == 0) {
vd->exponent = 0;
goto pack;
}
exponent = vd->exponent;
significand = vd->significand;
shift = 32 - fls(significand >> 32);
if (shift == 32)
shift = 64 - fls(significand);
if (shift) {
exponent -= shift;
significand <<= shift;
}
#ifdef DEBUG
vd->exponent = exponent;
vd->significand = significand;
vfp_double_dump("pack: normalised", vd);
#endif
/*
* Tiny number?
*/
underflow = exponent < 0;
if (underflow) {
significand