linux/arch/arm/vfp/vfp.h
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/vfp/vfp.h
   3 *
   4 *  Copyright (C) 2004 ARM Limited.
   5 *  Written by Deep Blue Solutions Limited.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11
  12static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift)
  13{
  14        if (shift) {
  15                if (shift < 32)
  16                        val = val >> shift | ((val << (32 - shift)) != 0);
  17                else
  18                        val = val != 0;
  19        }
  20        return val;
  21}
  22
  23static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift)
  24{
  25        if (shift) {
  26                if (shift < 64)
  27                        val = val >> shift | ((val << (64 - shift)) != 0);
  28                else
  29                        val = val != 0;
  30        }
  31        return val;
  32}
  33
  34static inline u32 vfp_hi64to32jamming(u64 val)
  35{
  36        u32 v;
  37
  38        asm(
  39        "cmp    %Q1, #1         @ vfp_hi64to32jamming\n\t"
  40        "movcc  %0, %R1\n\t"
  41        "orrcs  %0, %R1, #1"
  42        : "=r" (v) : "r" (val) : "cc");
  43
  44        return v;
  45}
  46
  47static inline void add128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml)
  48{
  49        asm(    "adds   %Q0, %Q2, %Q4\n\t"
  50                "adcs   %R0, %R2, %R4\n\t"
  51                "adcs   %Q1, %Q3, %Q5\n\t"
  52                "adc    %R1, %R3, %R5"
  53            : "=r" (nl), "=r" (nh)
  54            : "0" (nl), "1" (nh), "r" (ml), "r" (mh)
  55            : "cc");
  56        *resh = nh;
  57        *resl = nl;
  58}
  59
  60static inline void sub128(u64 *resh, u64 *resl, u64 nh, u64 nl, u64 mh, u64 ml)
  61{
  62        asm(    "subs   %Q0, %Q2, %Q4\n\t"
  63                "sbcs   %R0, %R2, %R4\n\t"
  64                "sbcs   %Q1, %Q3, %Q5\n\t"
  65                "sbc    %R1, %R3, %R5\n\t"
  66            : "=r" (nl), "=r" (nh)
  67            : "0" (nl), "1" (nh), "r" (ml), "r" (mh)
  68            : "cc");
  69        *resh = nh;
  70        *resl = nl;
  71}
  72
  73static inline void mul64to128(u64 *resh, u64 *resl, u64 n, u64 m)
  74{
  75        u32 nh, nl, mh, ml;
  76        u64 rh, rma, rmb, rl;
  77
  78        nl = n;
  79        ml = m;
  80        rl = (u64)nl * ml;
  81
  82        nh = n >> 32;
  83        rma = (u64)nh * ml;
  84
  85        mh = m >> 32;
  86        rmb = (u64)nl * mh;
  87        rma += rmb;
  88
  89        rh = (u64)nh * mh;
  90        rh += ((u64)(rma < rmb) << 32) + (rma >> 32);
  91
  92        rma <<= 32;
  93        rl += rma;
  94        rh += (rl < rma);
  95
  96        *resl = rl;
  97        *resh = rh;
  98}
  99
 100static inline void shift64left(u64 *resh, u64 *resl, u64 n)
 101{
 102        *resh = n >> 63;
 103        *resl = n << 1;
 104}
 105
 106static inline u64 vfp_hi64multiply64(u64 n, u64 m)
 107{
 108        u64 rh, rl;
 109        mul64to128(&rh, &rl, n, m);
 110        return rh | (rl != 0);
 111}
 112
 113static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
 114{
 115        u64 mh, ml, remh, reml, termh, terml, z;
 116
 117        if (nh >= m)
 118                return ~0ULL;
 119        mh = m >> 32;
 120        z = (mh << 32 <= nh) ? 0xffffffff00000000ULL : (nh / mh) << 32;
 121        mul64to128(&termh, &terml, m, z);
 122        sub128(&remh, &reml, nh, nl, termh, terml);
 123        ml = m << 32;
 124        while ((s64)remh < 0) {
 125                z -= 0x100000000ULL;
 126                add128(&remh, &reml, remh, reml, mh, ml);
 127        }
 128        remh = (remh << 32) | (reml >> 32);
 129        z |= (mh << 32 <= remh) ? 0xffffffff : remh / mh;
 130        return z;
 131}
 132
 133/*
 134 * Operations on unpacked elements
 135 */
 136#define vfp_sign_negate(sign)   (sign ^ 0x8000)
 137
 138/*
 139 * Single-precision
 140 */
 141struct vfp_single {
 142        s16     exponent;
 143        u16     sign;
 144        u32     significand;
 145};
 146
 147extern s32 vfp_get_float(unsigned int reg);
 148extern void vfp_put_float(unsigned int reg, s32 val);
 149
 150/*
 151 * VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa
 152 * VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent
 153 * VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand
 154 *  which are not propagated to the float upon packing.
 155 */
 156#define VFP_SINGLE_MANTISSA_BITS        (23)
 157#define VFP_SINGLE_EXPONENT_BITS        (8)
 158#define VFP_SINGLE_LOW_BITS             (32 - VFP_SINGLE_MANTISSA_BITS - 2)
 159#define VFP_SINGLE_LOW_BITS_MASK        ((1 << VFP_SINGLE_LOW_BITS) - 1)
 160
 161/*
 162 * The bit in an unpacked float which indicates that it is a quiet NaN
 163 */
 164#define VFP_SINGLE_SIGNIFICAND_QNAN     (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS))
 165
 166/*
 167 * Operations on packed single-precision numbers
 168 */
 169#define vfp_single_packed_sign(v)       ((v) & 0x80000000)
 170#define vfp_single_packed_negate(v)     ((v) ^ 0x80000000)
 171#define vfp_single_packed_abs(v)        ((v) & ~0x80000000)
 172#define vfp_single_packed_exponent(v)   (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
 173#define vfp_single_packed_mantissa(v)   ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1))
 174
 175/*
 176 * Unpack a single-precision float.  Note that this returns the magnitude
 177 * of the single-precision float mantissa with the 1. if necessary,
 178 * aligned to bit 30.
 179 */
 180static inline void vfp_single_unpack(struct vfp_single *s, s32 val)
 181{
 182        u32 significand;
 183
 184        s->sign = vfp_single_packed_sign(val) >> 16,
 185        s->exponent = vfp_single_packed_exponent(val);
 186
 187        significand = (u32) val;
 188        significand = (significand << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
 189        if (s->exponent && s->exponent != 255)
 190                significand |= 0x40000000;
 191        s->significand = significand;
 192}
 193
 194/*
 195 * Re-pack a single-precision float.  This assumes that the float is
 196 * already normalised such that the MSB is bit 30, _not_ bit 31.
 197 */
 198static inline s32 vfp_single_pack(struct vfp_single *s)
 199{
 200        u32 val;
 201        val = (s->sign << 16) +
 202              (s->exponent << VFP_SINGLE_MANTISSA_BITS) +
 203              (s->significand >> VFP_SINGLE_LOW_BITS);
 204        return (s32)val;
 205}
 206
 207#define VFP_NUMBER              (1<<0)
 208#define VFP_ZERO                (1<<1)
 209#define VFP_DENORMAL            (1<<2)
 210#define VFP_INFINITY            (1<<3)
 211#define VFP_NAN                 (1<<4)
 212#define VFP_NAN_SIGNAL          (1<<5)
 213
 214#define VFP_QNAN                (VFP_NAN)
 215#define VFP_SNAN                (VFP_NAN|VFP_NAN_SIGNAL)
 216
 217static inline int vfp_single_type(struct vfp_single *s)
 218{
 219        int type = VFP_NUMBER;
 220        if (s->exponent == 255) {
 221                if (s->significand == 0)
 222                        type = VFP_INFINITY;
 223                else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN)
 224                        type = VFP_QNAN;
 225                else
 226                        type = VFP_SNAN;
 227        } else if (s->exponent == 0) {
 228                if (s->significand == 0)
 229                        type |= VFP_ZERO;
 230                else
 231                        type |= VFP_DENORMAL;
 232        }
 233        return type;
 234}
 235
 236#ifndef DEBUG
 237#define vfp_single_normaliseround(sd,vsd,fpscr,except,func) __vfp_single_normaliseround(sd,vsd,fpscr,except)
 238u32 __vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions);
 239#else
 240u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func);
 241#endif
 242
 243/*
 244 * Double-precision
 245 */
 246struct vfp_double {
 247        s16     exponent;
 248        u16     sign;
 249        u64     significand;
 250};
 251
 252/*
 253 * VFP_REG_ZERO is a special register number for vfp_get_double
 254 * which returns (double)0.0.  This is useful for the compare with
 255 * zero instructions.
 256 */
 257#define VFP_REG_ZERO    16
 258extern u64 vfp_get_double(unsigned int reg);
 259extern void vfp_put_double(unsigned int reg, u64 val);
 260
 261#define VFP_DOUBLE_MANTISSA_BITS        (52)
 262#define VFP_DOUBLE_EXPONENT_BITS        (11)
 263#define VFP_DOUBLE_LOW_BITS             (64 - VFP_DOUBLE_MANTISSA_BITS - 2)
 264#define VFP_DOUBLE_LOW_BITS_MASK        ((1 << VFP_DOUBLE_LOW_BITS) - 1)
 265
 266/*
 267 * The bit in an unpacked double which indicates that it is a quiet NaN
 268 */
 269#define VFP_DOUBLE_SIGNIFICAND_QNAN     (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS))
 270
 271/*
 272 * Operations on packed single-precision numbers
 273 */
 274#define vfp_double_packed_sign(v)       ((v) & (1ULL << 63))
 275#define vfp_double_packed_negate(v)     ((v) ^ (1ULL << 63))
 276#define vfp_double_packed_abs(v)        ((v) & ~(1ULL << 63))
 277#define vfp_double_packed_exponent(v)   (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
 278#define vfp_double_packed_mantissa(v)   ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1))
 279
 280/*
 281 * Unpack a double-precision float.  Note that this returns the magnitude
 282 * of the double-precision float mantissa with the 1. if necessary,
 283 * aligned to bit 62.
 284 */
 285static inline void vfp_double_unpack(struct vfp_double *s, s64 val)
 286{
 287        u64 significand;
 288
 289        s->sign = vfp_double_packed_sign(val) >> 48;
 290        s->exponent = vfp_double_packed_exponent(val);
 291
 292        significand = (u64) val;
 293        significand = (significand << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
 294        if (s->exponent && s->exponent != 2047)
 295                significand |= (1ULL << 62);
 296        s->significand = significand;
 297}
 298
 299/*
 300 * Re-pack a double-precision float.  This assumes that the float is
 301 * already normalised such that the MSB is bit 30, _not_ bit 31.
 302 */
 303static inline s64 vfp_double_pack(struct vfp_double *s)
 304{
 305        u64 val;
 306        val = ((u64)s->sign << 48) +
 307              ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
 308              (s->significand >> VFP_DOUBLE_LOW_BITS);
 309        return (s64)val;
 310}
 311
 312static inline int vfp_double_type(struct vfp_double *s)
 313{
 314        int type = VFP_NUMBER;
 315        if (s->exponent == 2047) {
 316                if (s->significand == 0)
 317                        type = VFP_INFINITY;
 318                else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN)
 319                        type = VFP_QNAN;
 320                else
 321                        type = VFP_SNAN;
 322        } else if (s->exponent == 0) {
 323                if (s->significand == 0)
 324                        type |= VFP_ZERO;
 325                else
 326                        type |= VFP_DENORMAL;
 327        }
 328        return type;
 329}
 330
 331u32 vfp_double_normaliseround(int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
 332
 333/*
 334 * System registers
 335 */
 336extern u32 vfp_get_sys(unsigned int reg);
 337extern void vfp_put_sys(unsigned int reg, u32 val);
 338
 339u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
 340
 341/*
 342 * A special flag to tell the normalisation code not to normalise.
 343 */
 344#define VFP_NAN_FLAG    0x100
 345
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.