vfp.hh revision 8737:770ccf3af571
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
110static inline float bitsToFp(uint64_t, float);
111static inline uint32_t fpToBits(float);
112
113template <class fpType>
114static inline bool
115flushToZero(fpType &op)
116{
117    fpType junk = 0.0;
118    if (std::fpclassify(op) == FP_SUBNORMAL) {
119        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
120        op = bitsToFp(fpToBits(op) & bitMask, junk);
121        return true;
122    }
123    return false;
124}
125
126template <class fpType>
127static inline bool
128flushToZero(fpType &op1, fpType &op2)
129{
130    bool flush1 = flushToZero(op1);
131    bool flush2 = flushToZero(op2);
132    return flush1 || flush2;
133}
134
135template <class fpType>
136static inline void
137vfpFlushToZero(FPSCR &fpscr, fpType &op)
138{
139    if (fpscr.fz == 1 && flushToZero(op)) {
140        fpscr.idc = 1;
141    }
142}
143
144template <class fpType>
145static inline void
146vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
147{
148    vfpFlushToZero(fpscr, op1);
149    vfpFlushToZero(fpscr, op2);
150}
151
152static inline uint32_t
153fpToBits(float fp)
154{
155    union
156    {
157        float fp;
158        uint32_t bits;
159    } val;
160    val.fp = fp;
161    return val.bits;
162}
163
164static inline uint64_t
165fpToBits(double fp)
166{
167    union
168    {
169        double fp;
170        uint64_t bits;
171    } val;
172    val.fp = fp;
173    return val.bits;
174}
175
176static inline float
177bitsToFp(uint64_t bits, float junk)
178{
179    union
180    {
181        float fp;
182        uint32_t bits;
183    } val;
184    val.bits = bits;
185    return val.fp;
186}
187
188static inline double
189bitsToFp(uint64_t bits, double junk)
190{
191    union
192    {
193        double fp;
194        uint64_t bits;
195    } val;
196    val.bits = bits;
197    return val.fp;
198}
199
200template <class fpType>
201static bool
202isSnan(fpType val)
203{
204    const bool single = (sizeof(fpType) == sizeof(float));
205    const uint64_t qnan =
206        single ? 0x7fc00000 : ULL(0x7ff8000000000000);
207    return std::isnan(val) && ((fpToBits(val) & qnan) != qnan);
208}
209
210typedef int VfpSavedState;
211
212VfpSavedState prepFpState(uint32_t rMode);
213void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush);
214
215template <class fpType>
216fpType fixDest(FPSCR fpscr, fpType val, fpType op1);
217
218template <class fpType>
219fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
220
221template <class fpType>
222fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
223
224float fixFpDFpSDest(FPSCR fpscr, double val);
225double fixFpSFpDDest(FPSCR fpscr, float val);
226
227uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan,
228                    uint32_t rMode, bool ahp, float op);
229float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op);
230
231static inline double
232makeDouble(uint32_t low, uint32_t high)
233{
234    double junk = 0.0;
235    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
236}
237
238static inline uint32_t
239lowFromDouble(double val)
240{
241    return fpToBits(val);
242}
243
244static inline uint32_t
245highFromDouble(double val)
246{
247    return fpToBits(val) >> 32;
248}
249
250uint64_t vfpFpSToFixed(float val, bool isSigned, bool half,
251                       uint8_t imm, bool rzero = true);
252float vfpUFixedToFpS(bool flush, bool defaultNan,
253        uint32_t val, bool half, uint8_t imm);
254float vfpSFixedToFpS(bool flush, bool defaultNan,
255        int32_t val, bool half, uint8_t imm);
256
257uint64_t vfpFpDToFixed(double val, bool isSigned, bool half,
258                       uint8_t imm, bool rzero = true);
259double vfpUFixedToFpD(bool flush, bool defaultNan,
260        uint32_t val, bool half, uint8_t imm);
261double vfpSFixedToFpD(bool flush, bool defaultNan,
262        int32_t val, bool half, uint8_t imm);
263
264float fprSqrtEstimate(FPSCR &fpscr, float op);
265uint32_t unsignedRSqrtEstimate(uint32_t op);
266
267float fpRecipEstimate(FPSCR &fpscr, float op);
268uint32_t unsignedRecipEstimate(uint32_t op);
269
270class VfpMacroOp : public PredMacroOp
271{
272  public:
273    static bool
274    inScalarBank(IntRegIndex idx)
275    {
276        return (idx % 32) < 8;
277    }
278
279  protected:
280    bool wide;
281
282    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
283            OpClass __opClass, bool _wide) :
284        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
285    {}
286
287    IntRegIndex addStride(IntRegIndex idx, unsigned stride);
288    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2);
289    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1);
290    void nextIdxs(IntRegIndex &dest);
291};
292
293static inline float
294fpAddS(float a, float b)
295{
296    return a + b;
297}
298
299static inline double
300fpAddD(double a, double b)
301{
302    return a + b;
303}
304
305static inline float
306fpSubS(float a, float b)
307{
308    return a - b;
309}
310
311static inline double
312fpSubD(double a, double b)
313{
314    return a - b;
315}
316
317static inline float
318fpDivS(float a, float b)
319{
320    return a / b;
321}
322
323static inline double
324fpDivD(double a, double b)
325{
326    return a / b;
327}
328
329static inline float
330fpMulS(float a, float b)
331{
332    return a * b;
333}
334
335static inline double
336fpMulD(double a, double b)
337{
338    return a * b;
339}
340
341static inline float
342fpMaxS(float a, float b)
343{
344    // Handle comparisons of +0 and -0.
345    if (!std::signbit(a) && std::signbit(b))
346        return a;
347    return fmaxf(a, b);
348}
349
350static inline float
351fpMinS(float a, float b)
352{
353    // Handle comparisons of +0 and -0.
354    if (std::signbit(a) && !std::signbit(b))
355        return a;
356    return fminf(a, b);
357}
358
359static inline float
360fpRSqrtsS(float a, float b)
361{
362    int fpClassA = std::fpclassify(a);
363    int fpClassB = std::fpclassify(b);
364    float aXb;
365    int fpClassAxB;
366
367    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
368        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
369        return 1.5;
370    }
371    aXb = a*b;
372    fpClassAxB = std::fpclassify(aXb);
373    if(fpClassAxB == FP_SUBNORMAL) {
374       feraiseexcept(FeUnderflow);
375       return 1.5;
376    }
377    return (3.0 - (a * b)) / 2.0;
378}
379
380static inline float
381fpRecpsS(float a, float b)
382{
383    int fpClassA = std::fpclassify(a);
384    int fpClassB = std::fpclassify(b);
385    float aXb;
386    int fpClassAxB;
387
388    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
389        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
390        return 2.0;
391    }
392    aXb = a*b;
393    fpClassAxB = std::fpclassify(aXb);
394    if(fpClassAxB == FP_SUBNORMAL) {
395       feraiseexcept(FeUnderflow);
396       return 2.0;
397    }
398    return 2.0 - (a * b);
399}
400
401class FpOp : public PredOp
402{
403  protected:
404    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
405        PredOp(mnem, _machInst, __opClass)
406    {}
407
408    virtual float
409    doOp(float op1, float op2) const
410    {
411        panic("Unimplemented version of doOp called.\n");
412    }
413
414    virtual float
415    doOp(float op1) const
416    {
417        panic("Unimplemented version of doOp called.\n");
418    }
419
420    virtual double
421    doOp(double op1, double op2) const
422    {
423        panic("Unimplemented version of doOp called.\n");
424    }
425
426    virtual double
427    doOp(double op1) const
428    {
429        panic("Unimplemented version of doOp called.\n");
430    }
431
432    double
433    dbl(uint32_t low, uint32_t high) const
434    {
435        double junk = 0.0;
436        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
437    }
438
439    uint32_t
440    dblLow(double val) const
441    {
442        return fpToBits(val);
443    }
444
445    uint32_t
446    dblHi(double val) const
447    {
448        return fpToBits(val) >> 32;
449    }
450
451    template <class fpType>
452    fpType
453    processNans(FPSCR &fpscr, bool &done, bool defaultNan,
454                fpType op1, fpType op2) const;
455
456    template <class fpType>
457    fpType
458    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
459            fpType (*func)(fpType, fpType),
460            bool flush, bool defaultNan, uint32_t rMode) const;
461
462    template <class fpType>
463    fpType
464    unaryOp(FPSCR &fpscr, fpType op1,
465            fpType (*func)(fpType),
466            bool flush, uint32_t rMode) const;
467
468    void
469    advancePC(PCState &pcState) const
470    {
471        if (flags[IsLastMicroop]) {
472            pcState.uEnd();
473        } else if (flags[IsMicroop]) {
474            pcState.uAdvance();
475        } else {
476            pcState.advance();
477        }
478    }
479};
480
481class FpRegRegOp : public FpOp
482{
483  protected:
484    IntRegIndex dest;
485    IntRegIndex op1;
486
487    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
488               IntRegIndex _dest, IntRegIndex _op1,
489               VfpMicroMode mode = VfpNotAMicroop) :
490        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
491    {
492        setVfpMicroFlags(mode, flags);
493    }
494
495    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
496};
497
498class FpRegImmOp : public FpOp
499{
500  protected:
501    IntRegIndex dest;
502    uint64_t imm;
503
504    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
505               IntRegIndex _dest, uint64_t _imm,
506               VfpMicroMode mode = VfpNotAMicroop) :
507        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
508    {
509        setVfpMicroFlags(mode, flags);
510    }
511
512    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
513};
514
515class FpRegRegImmOp : public FpOp
516{
517  protected:
518    IntRegIndex dest;
519    IntRegIndex op1;
520    uint64_t imm;
521
522    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
523                  IntRegIndex _dest, IntRegIndex _op1,
524                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
525        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
526    {
527        setVfpMicroFlags(mode, flags);
528    }
529
530    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
531};
532
533class FpRegRegRegOp : public FpOp
534{
535  protected:
536    IntRegIndex dest;
537    IntRegIndex op1;
538    IntRegIndex op2;
539
540    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
541                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
542                  VfpMicroMode mode = VfpNotAMicroop) :
543        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
544    {
545        setVfpMicroFlags(mode, flags);
546    }
547
548    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
549};
550
551class FpRegRegRegImmOp : public FpOp
552{
553  protected:
554    IntRegIndex dest;
555    IntRegIndex op1;
556    IntRegIndex op2;
557    uint64_t imm;
558
559    FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst,
560                     OpClass __opClass, IntRegIndex _dest,
561                     IntRegIndex _op1, IntRegIndex _op2,
562                     uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
563        FpOp(mnem, _machInst, __opClass),
564        dest(_dest), op1(_op1), op2(_op2), imm(_imm)
565    {
566        setVfpMicroFlags(mode, flags);
567    }
568
569    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
570};
571
572}
573
574#endif //__ARCH_ARM_INSTS_VFP_HH__
575