/* * 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>
/* * 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;
}
/* * If any of the low bits (which will be shifted out of the * number) are non-zero, the result is inexact.
*/ if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
exceptions |= FPSCR_IXC;
/* * Propagate the NaN, setting exceptions if it is signalling. * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
*/ static u32
vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
{ struct vfp_single *nan; int tn, tm = 0;
tn = vfp_single_type(vsn);
if (vsm)
tm = vfp_single_type(vsm);
if (fpscr & FPSCR_DEFAULT_NAN) /* * Default NaN mode - always returns a quiet NaN
*/
nan = &vfp_single_default_qnan; else { /* * Contemporary mode - select the first signalling * NAN, or if neither are signalling, the first * quiet NAN.
*/ if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
nan = vsn; else
nan = vsm; /* * Make the NaN quiet.
*/
nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
}
*vsd = *nan;
/* * If one was a signalling NAN, raise invalid operation.
*/ return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
}
a = significand << 1;
index = (a >> 27) & 15; if (exponent & 1) {
z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
z = ((a / z) << 14) + (z << 15);
a >>= 1;
} else {
z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
z = a / z + z;
z = (z >= 0x20000) ? 0xffff8000 : (z << 15); if (z <= a) return (s32)a >> 1;
}
{
u64 v = (u64)a << 31;
do_div(v, z); return v + (z >> 1);
}
}
static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
{ struct vfp_single vsm, vsd; int ret, tm;
/* * Equal := ZC * Less than := N * Greater than := C * Unordered := CV
*/ static u32 vfp_compare(int sd, int signal_on_qnan, s32 m, u32 fpscr)
{
s32 d;
u32 ret = 0;
d = vfp_get_float(sd); if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
ret |= FPSCR_C | FPSCR_V; if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) /* * Signalling NaN, or signalling on quiet NaN
*/
ret |= FPSCR_IOC;
}
if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
ret |= FPSCR_C | FPSCR_V; if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) /* * Signalling NaN, or signalling on quiet NaN
*/
ret |= FPSCR_IOC;
}
if (ret == 0) { if (d == m || vfp_single_packed_abs(d | m) == 0) { /* * equal
*/
ret |= FPSCR_Z | FPSCR_C;
} elseif (vfp_single_packed_sign(d ^ m)) { /* * different signs
*/ if (vfp_single_packed_sign(d)) /* * d is negative, so d < m
*/
ret |= FPSCR_N; else /* * d is positive, so d > m
*/
ret |= FPSCR_C;
} elseif ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { /* * d < m
*/
ret |= FPSCR_N;
} elseif ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { /* * d > m
*/
ret |= FPSCR_C;
}
} return ret;
}
static u32 vfp_single_fcmp(int sd, int unused, s32 m, u32 fpscr)
{ return vfp_compare(sd, 0, m, fpscr);
}
static u32 vfp_single_fcmpe(int sd, int unused, s32 m, u32 fpscr)
{ return vfp_compare(sd, 1, m, fpscr);
}
static u32 vfp_single_fcmpz(int sd, int unused, s32 m, u32 fpscr)
{ return vfp_compare(sd, 0, 0, fpscr);
}
static u32 vfp_single_fcmpez(int sd, int unused, s32 m, u32 fpscr)
{ return vfp_compare(sd, 1, 0, fpscr);
}
static u32 vfp_single_fcvtd(int dd, int unused, s32 m, u32 fpscr)
{ struct vfp_single vsm; struct vfp_double vdd; int tm;
u32 exceptions = 0;
vfp_single_unpack(&vsm, m);
tm = vfp_single_type(&vsm);
/* * If we have a signalling NaN, signal invalid operation.
*/ if (tm == VFP_SNAN)
exceptions = FPSCR_IOC;
if (tm & VFP_DENORMAL)
vfp_single_normalise_denormal(&vsm);
/* * If we have an infinity or NaN, the exponent must be 2047.
*/ if (tm & (VFP_INFINITY|VFP_NAN)) {
vdd.exponent = 2047; if (tm == VFP_QNAN)
vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; goto pack_nan;
} elseif (tm & VFP_ZERO)
vdd.exponent = 0; else
vdd.exponent = vsm.exponent + (1023 - 127);
if (vsn->significand & 0x80000000 ||
vsm->significand & 0x80000000) {
pr_info("VFP: bad FP values in %s\n", __func__);
vfp_single_dump("VSN", vsn);
vfp_single_dump("VSM", vsm);
}
/* * Ensure that 'n' is the largest magnitude number. Note that * if 'n' and 'm' have equal exponents, we do not swap them. * This ensures that NaN propagation works correctly.
*/ if (vsn->exponent < vsm->exponent) { struct vfp_single *t = vsn;
vsn = vsm;
vsm = t;
}
/* * Is 'n' an infinity or a NaN? Note that 'm' may be a number, * infinity or a NaN here.
*/ if (vsn->exponent == 255) return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
/* * We have two proper numbers, where 'vsn' is the larger magnitude. * * Copy 'n' to 'd' before doing the arithmetic.
*/
*vsd = *vsn;
/* * Ensure that 'n' is the largest magnitude number. Note that * if 'n' and 'm' have equal exponents, we do not swap them. * This ensures that NaN propagation works correctly.
*/ if (vsn->exponent < vsm->exponent) { struct vfp_single *t = vsn;
vsn = vsm;
vsm = t;
pr_debug("VFP: swapping M <-> N\n");
}
vsd->sign = vsn->sign ^ vsm->sign;
/* * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
*/ if (vsn->exponent == 255) { if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) return vfp_propagate_nan(vsd, vsn, vsm, fpscr); if ((vsm->exponent | vsm->significand) == 0) {
*vsd = vfp_single_default_qnan; return FPSCR_IOC;
}
vsd->exponent = vsn->exponent;
vsd->significand = 0; return 0;
}
/* * If 'm' is zero, the result is always zero. In this case, * 'n' may be zero or a number, but it doesn't matter which.
*/ if ((vsm->exponent | vsm->significand) == 0) {
vsd->exponent = 0;
vsd->significand = 0; return 0;
}
/* * We add 2 to the destination exponent for the same reason as * the addition case - though this time we have +1 from each * input operand.
*/
vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
/* * sd = sn - sm
*/ static u32 vfp_single_fsub(int sd, int sn, s32 m, u32 fpscr)
{ /* * Subtraction is addition with one sign inverted.
*/ return vfp_single_fadd(sd, sn, vfp_single_packed_negate(m), fpscr);
}
/* * sd = sn / sm
*/ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
{ struct vfp_single vsd, vsn, vsm;
u32 exceptions = 0;
s32 n = vfp_get_float(sn); int tm, tn;
/* * Is n a NAN?
*/ if (tn & VFP_NAN) goto vsn_nan;
/* * Is m a NAN?
*/ if (tm & VFP_NAN) goto vsm_nan;
/* * If n and m are infinity, the result is invalid * If n and m are zero, the result is invalid
*/ if (tm & tn & (VFP_INFINITY|VFP_ZERO)) goto invalid;
/* * If n is infinity, the result is infinity
*/ if (tn & VFP_INFINITY) goto infinity;
/* * If m is zero, raise div0 exception
*/ if (tm & VFP_ZERO) goto divzero;
/* * If m is infinity, or n is zero, the result is zero
*/ if (tm & VFP_INFINITY || tn & VFP_ZERO) goto zero;
if (tn & VFP_DENORMAL)
vfp_single_normalise_denormal(&vsn); if (tm & VFP_DENORMAL)
vfp_single_normalise_denormal(&vsm);
/* * Ok, we have two numbers, we can perform division.
*/
vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
vsm.significand <<= 1; if (vsm.significand <= (2 * vsn.significand)) {
vsn.significand >>= 1;
vsd.exponent++;
}
{
u64 significand = (u64)vsn.significand << 32;
do_div(significand, vsm.significand);
vsd.significand = significand;
} if ((vsd.significand & 0x3f) == 0)
vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
/* * fcvtsd takes a dN register number as destination, not sN. * Technically, if bit 0 of dd is set, this is an invalid * instruction. However, we ignore this for efficiency. * It also only operates on scalars.
*/ if (fop->flags & OP_DD)
dest = vfp_get_dd(inst); else
dest = vfp_get_sd(inst);
/* * If destination bank is zero, vector length is always '1'. * ARM DDI0100F C5.1.3, C5.3.2.
*/ if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
veclen = 0; else
veclen = fpscr & FPSCR_LENGTH_MASK;
/* * CHECK: It appears to be undefined whether we stop when * we encounter an exception. We continue.
*/
dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); if (FREG_BANK(sm) != 0)
sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
} return exceptions;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.