vfp.hh revision 8229
1/*
2 * Copyright (c) 2010 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Gabe Black
38 */
39
40#ifndef __ARCH_ARM_INSTS_VFP_HH__
41#define __ARCH_ARM_INSTS_VFP_HH__
42
43#include <fenv.h>
44
45#include <cmath>
46
47#include "arch/arm/insts/misc.hh"
48#include "arch/arm/miscregs.hh"
49
50namespace ArmISA
51{
52
53enum VfpMicroMode {
54    VfpNotAMicroop,
55    VfpMicroop,
56    VfpFirstMicroop,
57    VfpLastMicroop
58};
59
60template<class T>
61static inline void
62setVfpMicroFlags(VfpMicroMode mode, T &flags)
63{
64    switch (mode) {
65      case VfpMicroop:
66        flags[StaticInst::IsMicroop] = true;
67        break;
68      case VfpFirstMicroop:
69        flags[StaticInst::IsMicroop] =
70            flags[StaticInst::IsFirstMicroop] = true;
71        break;
72      case VfpLastMicroop:
73        flags[StaticInst::IsMicroop] =
74            flags[StaticInst::IsLastMicroop] = true;
75        break;
76      case VfpNotAMicroop:
77        break;
78    }
79    if (mode == VfpMicroop || mode == VfpFirstMicroop) {
80        flags[StaticInst::IsDelayedCommit] = true;
81    }
82}
83
84enum FeExceptionBit
85{
86    FeDivByZero = FE_DIVBYZERO,
87    FeInexact = FE_INEXACT,
88    FeInvalid = FE_INVALID,
89    FeOverflow = FE_OVERFLOW,
90    FeUnderflow = FE_UNDERFLOW,
91    FeAllExceptions = FE_ALL_EXCEPT
92};
93
94enum FeRoundingMode
95{
96    FeRoundDown = FE_DOWNWARD,
97    FeRoundNearest = FE_TONEAREST,
98    FeRoundZero = FE_TOWARDZERO,
99    FeRoundUpward = FE_UPWARD
100};
101
102enum VfpRoundingMode
103{
104    VfpRoundNearest = 0,
105    VfpRoundUpward = 1,
106    VfpRoundDown = 2,
107    VfpRoundZero = 3
108};
109
110template <class fpType>
111static inline bool
112flushToZero(fpType &op)
113{
114    fpType junk = 0.0;
115    if (std::fpclassify(op) == FP_SUBNORMAL) {
116        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
117        op = bitsToFp(fpToBits(op) & bitMask, junk);
118        return true;
119    }
120    return false;
121}
122
123template <class fpType>
124static inline bool
125flushToZero(fpType &op1, fpType &op2)
126{
127    bool flush1 = flushToZero(op1);
128    bool flush2 = flushToZero(op2);
129    return flush1 || flush2;
130}
131
132template <class fpType>
133static inline void
134vfpFlushToZero(FPSCR &fpscr, fpType &op)
135{
136    if (fpscr.fz == 1 && flushToZero(op)) {
137        fpscr.idc = 1;
138    }
139}
140
141template <class fpType>
142static inline void
143vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
144{
145    vfpFlushToZero(fpscr, op1);
146    vfpFlushToZero(fpscr, op2);
147}
148
149static inline uint32_t
150fpToBits(float fp)
151{
152    union
153    {
154        float fp;
155        uint32_t bits;
156    } val;
157    val.fp = fp;
158    return val.bits;
159}
160
161static inline uint64_t
162fpToBits(double fp)
163{
164    union
165    {
166        double fp;
167        uint64_t bits;
168    } val;
169    val.fp = fp;
170    return val.bits;
171}
172
173static inline float
174bitsToFp(uint64_t bits, float junk)
175{
176    union
177    {
178        float fp;
179        uint32_t bits;
180    } val;
181    val.bits = bits;
182    return val.fp;
183}
184
185static inline double
186bitsToFp(uint64_t bits, double junk)
187{
188    union
189    {
190        double fp;
191        uint64_t bits;
192    } val;
193    val.bits = bits;
194    return val.fp;
195}
196
197template <class fpType>
198static bool
199isSnan(fpType val)
200{
201    const bool single = (sizeof(fpType) == sizeof(float));
202    const uint64_t qnan =
203        single ? 0x7fc00000 : ULL(0x7ff8000000000000);
204    return std::isnan(val) && ((fpToBits(val) & qnan) != qnan);
205}
206
207typedef int VfpSavedState;
208
209VfpSavedState prepFpState(uint32_t rMode);
210void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush);
211
212template <class fpType>
213fpType fixDest(FPSCR fpscr, fpType val, fpType op1);
214
215template <class fpType>
216fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
217
218template <class fpType>
219fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
220
221float fixFpDFpSDest(FPSCR fpscr, double val);
222double fixFpSFpDDest(FPSCR fpscr, float val);
223
224uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan,
225                    uint32_t rMode, bool ahp, float op);
226float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op);
227
228static inline double
229makeDouble(uint32_t low, uint32_t high)
230{
231    double junk = 0.0;
232    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
233}
234
235static inline uint32_t
236lowFromDouble(double val)
237{
238    return fpToBits(val);
239}
240
241static inline uint32_t
242highFromDouble(double val)
243{
244    return fpToBits(val) >> 32;
245}
246
247uint64_t vfpFpSToFixed(float val, bool isSigned, bool half,
248                       uint8_t imm, bool rzero = true);
249float vfpUFixedToFpS(bool flush, bool defaultNan,
250        uint32_t val, bool half, uint8_t imm);
251float vfpSFixedToFpS(bool flush, bool defaultNan,
252        int32_t val, bool half, uint8_t imm);
253
254uint64_t vfpFpDToFixed(double val, bool isSigned, bool half,
255                       uint8_t imm, bool rzero = true);
256double vfpUFixedToFpD(bool flush, bool defaultNan,
257        uint32_t val, bool half, uint8_t imm);
258double vfpSFixedToFpD(bool flush, bool defaultNan,
259        int32_t val, bool half, uint8_t imm);
260
261float fprSqrtEstimate(FPSCR &fpscr, float op);
262uint32_t unsignedRSqrtEstimate(uint32_t op);
263
264float fpRecipEstimate(FPSCR &fpscr, float op);
265uint32_t unsignedRecipEstimate(uint32_t op);
266
267class VfpMacroOp : public PredMacroOp
268{
269  public:
270    static bool
271    inScalarBank(IntRegIndex idx)
272    {
273        return (idx % 32) < 8;
274    }
275
276  protected:
277    bool wide;
278
279    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
280            OpClass __opClass, bool _wide) :
281        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
282    {}
283
284    IntRegIndex addStride(IntRegIndex idx, unsigned stride);
285    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2);
286    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1);
287    void nextIdxs(IntRegIndex &dest);
288};
289
290static inline float
291fpAddS(float a, float b)
292{
293    return a + b;
294}
295
296static inline double
297fpAddD(double a, double b)
298{
299    return a + b;
300}
301
302static inline float
303fpSubS(float a, float b)
304{
305    return a - b;
306}
307
308static inline double
309fpSubD(double a, double b)
310{
311    return a - b;
312}
313
314static inline float
315fpDivS(float a, float b)
316{
317    return a / b;
318}
319
320static inline double
321fpDivD(double a, double b)
322{
323    return a / b;
324}
325
326static inline float
327fpMulS(float a, float b)
328{
329    return a * b;
330}
331
332static inline double
333fpMulD(double a, double b)
334{
335    return a * b;
336}
337
338static inline float
339fpMaxS(float a, float b)
340{
341    // Handle comparisons of +0 and -0.
342    if (!std::signbit(a) && std::signbit(b))
343        return a;
344    return fmaxf(a, b);
345}
346
347static inline float
348fpMinS(float a, float b)
349{
350    // Handle comparisons of +0 and -0.
351    if (std::signbit(a) && !std::signbit(b))
352        return a;
353    return fminf(a, b);
354}
355
356static inline float
357fpRSqrtsS(float a, float b)
358{
359    int fpClassA = std::fpclassify(a);
360    int fpClassB = std::fpclassify(b);
361    float aXb;
362    int fpClassAxB;
363
364    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
365        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
366        return 1.5;
367    }
368    aXb = a*b;
369    fpClassAxB = std::fpclassify(aXb);
370    if(fpClassAxB == FP_SUBNORMAL) {
371       feraiseexcept(FeUnderflow);
372       return 1.5;
373    }
374    return (3.0 - (a * b)) / 2.0;
375}
376
377static inline float
378fpRecpsS(float a, float b)
379{
380    int fpClassA = std::fpclassify(a);
381    int fpClassB = std::fpclassify(b);
382    float aXb;
383    int fpClassAxB;
384
385    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
386        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
387        return 2.0;
388    }
389    aXb = a*b;
390    fpClassAxB = std::fpclassify(aXb);
391    if(fpClassAxB == FP_SUBNORMAL) {
392       feraiseexcept(FeUnderflow);
393       return 2.0;
394    }
395    return 2.0 - (a * b);
396}
397
398class FpOp : public PredOp
399{
400  protected:
401    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
402        PredOp(mnem, _machInst, __opClass)
403    {}
404
405    virtual float
406    doOp(float op1, float op2) const
407    {
408        panic("Unimplemented version of doOp called.\n");
409    }
410
411    virtual float
412    doOp(float op1) const
413    {
414        panic("Unimplemented version of doOp called.\n");
415    }
416
417    virtual double
418    doOp(double op1, double op2) const
419    {
420        panic("Unimplemented version of doOp called.\n");
421    }
422
423    virtual double
424    doOp(double op1) const
425    {
426        panic("Unimplemented version of doOp called.\n");
427    }
428
429    double
430    dbl(uint32_t low, uint32_t high) const
431    {
432        double junk = 0.0;
433        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
434    }
435
436    uint32_t
437    dblLow(double val) const
438    {
439        return fpToBits(val);
440    }
441
442    uint32_t
443    dblHi(double val) const
444    {
445        return fpToBits(val) >> 32;
446    }
447
448    template <class fpType>
449    fpType
450    processNans(FPSCR &fpscr, bool &done, bool defaultNan,
451                fpType op1, fpType op2) const;
452
453    template <class fpType>
454    fpType
455    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
456            fpType (*func)(fpType, fpType),
457            bool flush, bool defaultNan, uint32_t rMode) const;
458
459    template <class fpType>
460    fpType
461    unaryOp(FPSCR &fpscr, fpType op1,
462            fpType (*func)(fpType),
463            bool flush, uint32_t rMode) const;
464
465    void
466    advancePC(PCState &pcState) const
467    {
468        if (flags[IsLastMicroop]) {
469            pcState.uEnd();
470        } else if (flags[IsMicroop]) {
471            pcState.uAdvance();
472        } else {
473            pcState.advance();
474        }
475    }
476};
477
478class FpRegRegOp : public FpOp
479{
480  protected:
481    IntRegIndex dest;
482    IntRegIndex op1;
483
484    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
485               IntRegIndex _dest, IntRegIndex _op1,
486               VfpMicroMode mode = VfpNotAMicroop) :
487        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
488    {
489        setVfpMicroFlags(mode, flags);
490    }
491
492    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
493};
494
495class FpRegImmOp : public FpOp
496{
497  protected:
498    IntRegIndex dest;
499    uint64_t imm;
500
501    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
502               IntRegIndex _dest, uint64_t _imm,
503               VfpMicroMode mode = VfpNotAMicroop) :
504        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
505    {
506        setVfpMicroFlags(mode, flags);
507    }
508
509    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
510};
511
512class FpRegRegImmOp : public FpOp
513{
514  protected:
515    IntRegIndex dest;
516    IntRegIndex op1;
517    uint64_t imm;
518
519    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
520                  IntRegIndex _dest, IntRegIndex _op1,
521                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
522        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
523    {
524        setVfpMicroFlags(mode, flags);
525    }
526
527    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
528};
529
530class FpRegRegRegOp : public FpOp
531{
532  protected:
533    IntRegIndex dest;
534    IntRegIndex op1;
535    IntRegIndex op2;
536
537    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
538                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
539                  VfpMicroMode mode = VfpNotAMicroop) :
540        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
541    {
542        setVfpMicroFlags(mode, flags);
543    }
544
545    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
546};
547
548class FpRegRegRegImmOp : public FpOp
549{
550  protected:
551    IntRegIndex dest;
552    IntRegIndex op1;
553    IntRegIndex op2;
554    uint64_t imm;
555
556    FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst,
557                     OpClass __opClass, IntRegIndex _dest,
558                     IntRegIndex _op1, IntRegIndex _op2,
559                     uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
560        FpOp(mnem, _machInst, __opClass),
561        dest(_dest), op1(_op1), op2(_op2), imm(_imm)
562    {
563        setVfpMicroFlags(mode, flags);
564    }
565
566    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
567};
568
569}
570
571#endif //__ARCH_ARM_INSTS_VFP_HH__
572