/*
* linux/arch/arm/vfp/vfpsingle.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_single vfp_single_default_qnan = {
.exponent = 255,
.sign = 0,
.significand = VFP_SINGLE_SIGNIFICAND_QNAN,
};
static void vfp_single_dump(const char *str, struct vfp_single *s)
{
pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
str, s->sign != 0, s->exponent, s->significand);
}
static void vfp_single_normalise_denormal(struct vfp_single *vs)
{
int bits = 31 - fls(vs->significand);
vfp_single_dump("normalise_denormal: in", vs);
if (bits) {
vs->exponent -= bits - 1;
vs->significand <<= bits;
}
vfp_single_dump("normalise_denormal: out", vs);
}
#ifndef DEBUG
#define vfp_single_normaliseround(sd,vsd,fpscr,except,func) __vfp_single_normaliseround(sd,vsd,fpscr,except)
u32 __vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions)
#else
u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
#endif
{
u32 significand, incr, rmode;
int exponent, shift, underflow;
vfp_single_dump("pack: in", vs);
/*
* Infinities and NaNs are a special case.
*/
if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
goto pack;
/*
* Special-case zero.
*/
if (vs->significand == 0) {
vs->exponent = 0;
goto pack;
}
exponent = vs->exponent;
significand = vs->significand;
/*
* Normalise first. Note that we shift the significand up to
* bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
* significant bit.
*/
shift = 32 - fls(significand);
if (shift < 32 && shift) {
exponent -= shift;
significand <<= shift;
}