1/*
2 * Copyright (c) 2010-2013, 2019 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    VfpRoundAway = 4
109};
110
111static inline float bitsToFp(uint64_t, float);
112static inline double bitsToFp(uint64_t, double);
113static inline uint32_t fpToBits(float);
114static inline uint64_t fpToBits(double);
115
116template <class fpType>
117static inline bool
118flushToZero(fpType &op)
119{
120    fpType junk = 0.0;
121    if (std::fpclassify(op) == FP_SUBNORMAL) {
122        uint64_t bitMask = ULL(0x1) << (sizeof(fpType) * 8 - 1);
123        op = bitsToFp(fpToBits(op) & bitMask, junk);
124        return true;
125    }
126    return false;
127}
128
129template <class fpType>
130static inline bool
131flushToZero(fpType &op1, fpType &op2)
132{
133    bool flush1 = flushToZero(op1);
134    bool flush2 = flushToZero(op2);
135    return flush1 || flush2;
136}
137
138template <class fpType>
139static inline void
140vfpFlushToZero(FPSCR &fpscr, fpType &op)
141{
142    if (fpscr.fz == 1 && flushToZero(op)) {
143        fpscr.idc = 1;
144    }
145}
146
147template <class fpType>
148static inline void
149vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
150{
151    vfpFlushToZero(fpscr, op1);
152    vfpFlushToZero(fpscr, op2);
153}
154
155static inline uint32_t
156fpToBits(float fp)
157{
158    union
159    {
160        float fp;
161        uint32_t bits;
162    } val;
163    val.fp = fp;
164    return val.bits;
165}
166
167static inline uint64_t
168fpToBits(double fp)
169{
170    union
171    {
172        double fp;
173        uint64_t bits;
174    } val;
175    val.fp = fp;
176    return val.bits;
177}
178
179static inline float
180bitsToFp(uint64_t bits, float junk)
181{
182    union
183    {
184        float fp;
185        uint32_t bits;
186    } val;
187    val.bits = bits;
188    return val.fp;
189}
190
191static inline double
192bitsToFp(uint64_t bits, double junk)
193{
194    union
195    {
196        double fp;
197        uint64_t bits;
198    } val;
199    val.bits = bits;
200    return val.fp;
201}
202
203template <class fpType>
204static inline bool
205isSnan(fpType val)
206{
207    const bool single = (sizeof(fpType) == sizeof(float));
208    const uint64_t qnan =
209        single ? 0x7fc00000 : ULL(0x7ff8000000000000);
210    return std::isnan(val) && ((fpToBits(val) & qnan) != qnan);
211}
212
213typedef int VfpSavedState;
214
215VfpSavedState prepFpState(uint32_t rMode);
216void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush, FPSCR mask = FpscrExcMask);
217
218template <class fpType>
219fpType fixDest(FPSCR fpscr, fpType val, fpType op1);
220
221template <class fpType>
222fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
223
224template <class fpType>
225fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
226
227float fixFpDFpSDest(FPSCR fpscr, double val);
228double fixFpSFpDDest(FPSCR fpscr, float val);
229
230uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan,
231                    uint32_t rMode, bool ahp, float op);
232uint16_t vcvtFpDFpH(FPSCR &fpscr, bool flush, bool defaultNan,
233                    uint32_t rMode, bool ahp, double op);
234
235float  vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op);
236double vcvtFpHFpD(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op);
237
238static inline double
239makeDouble(uint32_t low, uint32_t high)
240{
241    double junk = 0.0;
242    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
243}
244
245static inline uint32_t
246lowFromDouble(double val)
247{
248    return fpToBits(val);
249}
250
251static inline uint32_t
252highFromDouble(double val)
253{
254    return fpToBits(val) >> 32;
255}
256
257static inline void
258setFPExceptions(int exceptions) {
259    feclearexcept(FeAllExceptions);
260    feraiseexcept(exceptions);
261}
262
263template <typename T>
264uint64_t
265vfpFpToFixed(T val, bool isSigned, uint8_t width, uint8_t imm, bool
266             useRmode = true, VfpRoundingMode roundMode = VfpRoundZero,
267             bool aarch64 = false)
268{
269    int  rmode;
270    bool roundAwayFix = false;
271
272    if (!useRmode) {
273        rmode = fegetround();
274    } else {
275        switch (roundMode)
276        {
277          case VfpRoundNearest:
278            rmode = FeRoundNearest;
279            break;
280          case VfpRoundUpward:
281            rmode = FeRoundUpward;
282            break;
283          case VfpRoundDown:
284            rmode = FeRoundDown;
285            break;
286          case VfpRoundZero:
287            rmode = FeRoundZero;
288            break;
289          case VfpRoundAway:
290            // There is no equivalent rounding mode, use round down and we'll
291            // fix it later
292            rmode        = FeRoundDown;
293            roundAwayFix = true;
294            break;
295          default:
296            panic("Unsupported roundMode %d\n", roundMode);
297        }
298    }
299    __asm__ __volatile__("" : "=m" (rmode) : "m" (rmode));
300    fesetround(FeRoundNearest);
301    val = val * pow(2.0, imm);
302    __asm__ __volatile__("" : "=m" (val) : "m" (val));
303    fesetround(rmode);
304    feclearexcept(FeAllExceptions);
305    __asm__ __volatile__("" : "=m" (val) : "m" (val));
306    T origVal = val;
307    val = rint(val);
308    __asm__ __volatile__("" : "=m" (val) : "m" (val));
309
310    int exceptions = fetestexcept(FeAllExceptions);
311
312    int fpType = std::fpclassify(val);
313    if (fpType == FP_SUBNORMAL || fpType == FP_NAN) {
314        if (fpType == FP_NAN) {
315            exceptions |= FeInvalid;
316        }
317        val = 0.0;
318    } else if (origVal != val) {
319        switch (rmode) {
320          case FeRoundNearest:
321            if (origVal - val > 0.5)
322                val += 1.0;
323            else if (val - origVal > 0.5)
324                val -= 1.0;
325            break;
326          case FeRoundDown:
327            if (roundAwayFix) {
328                // The ordering on the subtraction looks a bit odd in that we
329                // don't do the obvious origVal - val, instead we do
330                // -(val - origVal). This is required to get the corruct bit
331                // exact behaviour when very close to the 0.5 threshold.
332                volatile T error = val;
333                error -= origVal;
334                error = -error;
335                if ( (error >  0.5) ||
336                    ((error == 0.5) && (val >= 0)) )
337                    val += 1.0;
338            } else {
339                if (origVal < val)
340                    val -= 1.0;
341            }
342            break;
343          case FeRoundUpward:
344            if (origVal > val)
345                val += 1.0;
346            break;
347        }
348        exceptions |= FeInexact;
349    }
350
351    __asm__ __volatile__("" : "=m" (val) : "m" (val));
352
353    if (isSigned) {
354        bool     outOfRange = false;
355        int64_t  result     = (int64_t) val;
356        uint64_t finalVal;
357
358        if (!aarch64) {
359            if (width == 16) {
360                finalVal = (int16_t)val;
361            } else if (width == 32) {
362                finalVal =(int32_t)val;
363            } else if (width == 64) {
364                finalVal = result;
365            } else {
366                panic("Unsupported width %d\n", width);
367            }
368
369            // check if value is in range
370            int64_t minVal = ~mask(width-1);
371            if ((double)val < minVal) {
372                outOfRange = true;
373                finalVal = minVal;
374            }
375            int64_t maxVal = mask(width-1);
376            if ((double)val > maxVal) {
377                outOfRange = true;
378                finalVal = maxVal;
379            }
380        } else {
381            bool isNeg = val < 0;
382            finalVal = result & mask(width);
383            // If the result is supposed to be less than 64 bits check that the
384            // upper bits that got thrown away are just sign extension bits
385            if (width != 64) {
386                outOfRange = ((uint64_t) result >> (width - 1)) !=
387                             (isNeg ? mask(64-width+1) : 0);
388            }
389            // Check if the original floating point value doesn't matches the
390            // integer version we are also out of range. So create a saturated
391            // result.
392            if (isNeg) {
393                outOfRange |= val < result;
394                if (outOfRange) {
395                    finalVal = 1LL << (width-1);
396                }
397            } else {
398                outOfRange |= val > result;
399                if (outOfRange) {
400                    finalVal = mask(width-1);
401                }
402            }
403        }
404
405        // Raise an exception if the value was out of range
406        if (outOfRange) {
407            exceptions |= FeInvalid;
408            exceptions &= ~FeInexact;
409        }
410        setFPExceptions(exceptions);
411        return finalVal;
412    } else {
413        if ((double)val < 0) {
414            exceptions |= FeInvalid;
415            exceptions &= ~FeInexact;
416            setFPExceptions(exceptions);
417            return 0;
418        }
419
420        uint64_t result = ((uint64_t) val) & mask(width);
421        if (val > result) {
422            exceptions |= FeInvalid;
423            exceptions &= ~FeInexact;
424            setFPExceptions(exceptions);
425            return mask(width);
426        }
427
428        setFPExceptions(exceptions);
429        return result;
430    }
431};
432
433
434float vfpUFixedToFpS(bool flush, bool defaultNan,
435        uint64_t val, uint8_t width, uint8_t imm);
436float vfpSFixedToFpS(bool flush, bool defaultNan,
437        int64_t val, uint8_t width, uint8_t imm);
438
439double vfpUFixedToFpD(bool flush, bool defaultNan,
440        uint64_t val, uint8_t width, uint8_t imm);
441double vfpSFixedToFpD(bool flush, bool defaultNan,
442        int64_t val, uint8_t width, uint8_t imm);
443
444float fprSqrtEstimate(FPSCR &fpscr, float op);
445uint32_t unsignedRSqrtEstimate(uint32_t op);
446
447float fpRecipEstimate(FPSCR &fpscr, float op);
448uint32_t unsignedRecipEstimate(uint32_t op);
449
450FPSCR
451fpStandardFPSCRValue(const FPSCR &fpscr);
452
453class VfpMacroOp : public PredMacroOp
454{
455  public:
456    static bool
457    inScalarBank(IntRegIndex idx)
458    {
459        return (idx % 32) < 8;
460    }
461
462  protected:
463    bool wide;
464
465    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
466            OpClass __opClass, bool _wide) :
467        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
468    {}
469
470    IntRegIndex addStride(IntRegIndex idx, unsigned stride);
471    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2);
472    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1);
473    void nextIdxs(IntRegIndex &dest);
474};
475
476template <typename T>
477static inline T
478fpAdd(T a, T b)
479{
480    return a + b;
481};
482
483template <typename T>
484static inline T
485fpSub(T a, T b)
486{
487    return a - b;
488};
489
490static inline float
491fpAddS(float a, float b)
492{
493    return a + b;
494}
495
496static inline double
497fpAddD(double a, double b)
498{
499    return a + b;
500}
501
502static inline float
503fpSubS(float a, float b)
504{
505    return a - b;
506}
507
508static inline double
509fpSubD(double a, double b)
510{
511    return a - b;
512}
513
514static inline float
515fpDivS(float a, float b)
516{
517    return a / b;
518}
519
520static inline double
521fpDivD(double a, double b)
522{
523    return a / b;
524}
525
526template <typename T>
527static inline T
528fpDiv(T a, T b)
529{
530    return a / b;
531};
532
533template <typename T>
534static inline T
535fpMulX(T a, T b)
536{
537    uint64_t opData;
538    uint32_t sign1;
539    uint32_t sign2;
540    const bool single = (sizeof(T) == sizeof(float));
541    if (single) {
542        opData = (fpToBits(a));
543        sign1 = opData>>31;
544        opData = (fpToBits(b));
545        sign2 = opData>>31;
546    } else {
547        opData = (fpToBits(a));
548        sign1 = opData>>63;
549        opData = (fpToBits(b));
550        sign2 = opData>>63;
551    }
552    bool inf1 = (std::fpclassify(a) == FP_INFINITE);
553    bool inf2 = (std::fpclassify(b) == FP_INFINITE);
554    bool zero1 = (std::fpclassify(a) == FP_ZERO);
555    bool zero2 = (std::fpclassify(b) == FP_ZERO);
556    if ((inf1 && zero2) || (zero1 && inf2)) {
557        if (sign1 ^ sign2)
558            return (T)(-2.0);
559        else
560            return (T)(2.0);
561    } else {
562        return (a * b);
563    }
564};
565
566
567template <typename T>
568static inline T
569fpMul(T a, T b)
570{
571    return a * b;
572};
573
574static inline float
575fpMulS(float a, float b)
576{
577    return a * b;
578}
579
580static inline double
581fpMulD(double a, double b)
582{
583    return a * b;
584}
585
586template <typename T>
587static inline T
588// @todo remove this when all calls to it have been replaced with the new fplib implementation
589fpMulAdd(T op1, T op2, T addend)
590{
591    T result;
592
593    if (sizeof(T) == sizeof(float))
594        result = fmaf(op1, op2, addend);
595    else
596        result = fma(op1, op2, addend);
597
598    // ARM doesn't generate signed nan's from this opperation, so fix up the result
599    if (std::isnan(result) && !std::isnan(op1) &&
600        !std::isnan(op2) && !std::isnan(addend))
601    {
602        uint64_t bitMask = ULL(0x1) << ((sizeof(T) * 8) - 1);
603        result = bitsToFp(fpToBits(result) & ~bitMask, op1);
604    }
605    return result;
606}
607
608template <typename T>
609static inline T
610fpRIntX(T a, FPSCR &fpscr)
611{
612    T rVal;
613
614    rVal = rint(a);
615    if (rVal != a && !std::isnan(a))
616        fpscr.ixc = 1;
617    return (rVal);
618};
619
620template <typename T>
621static inline T
622fpMaxNum(T a, T b)
623{
624    const bool     single = (sizeof(T) == sizeof(float));
625    const uint64_t qnan   = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
626
627    if (std::isnan(a))
628        return ((fpToBits(a) & qnan) == qnan) ? b : a;
629    if (std::isnan(b))
630        return ((fpToBits(b) & qnan) == qnan) ? a : b;
631    // Handle comparisons of +0 and -0.
632    if (!std::signbit(a) && std::signbit(b))
633        return a;
634    return fmax(a, b);
635};
636
637template <typename T>
638static inline T
639fpMax(T a, T b)
640{
641    if (std::isnan(a))
642        return a;
643    if (std::isnan(b))
644        return b;
645    return fpMaxNum<T>(a, b);
646};
647
648template <typename T>
649static inline T
650fpMinNum(T a, T b)
651{
652    const bool     single = (sizeof(T) == sizeof(float));
653    const uint64_t qnan   = single ? 0x7fc00000 : ULL(0x7ff8000000000000);
654
655    if (std::isnan(a))
656        return ((fpToBits(a) & qnan) == qnan) ? b : a;
657    if (std::isnan(b))
658        return ((fpToBits(b) & qnan) == qnan) ? a : b;
659    // Handle comparisons of +0 and -0.
660    if (std::signbit(a) && !std::signbit(b))
661        return a;
662    return fmin(a, b);
663};
664
665template <typename T>
666static inline T
667fpMin(T a, T b)
668{
669    if (std::isnan(a))
670        return a;
671    if (std::isnan(b))
672        return b;
673    return fpMinNum<T>(a, b);
674};
675
676template <typename T>
677static inline T
678fpRSqrts(T a, T b)
679{
680    int fpClassA = std::fpclassify(a);
681    int fpClassB = std::fpclassify(b);
682    T aXb;
683    int fpClassAxB;
684
685    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
686        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
687        return 1.5;
688    }
689    aXb = a*b;
690    fpClassAxB = std::fpclassify(aXb);
691    if (fpClassAxB == FP_SUBNORMAL) {
692       feraiseexcept(FeUnderflow);
693       return 1.5;
694    }
695    return (3.0 - (a * b)) / 2.0;
696};
697
698template <typename T>
699static inline T
700fpRecps(T a, T b)
701{
702    int fpClassA = std::fpclassify(a);
703    int fpClassB = std::fpclassify(b);
704    T aXb;
705    int fpClassAxB;
706
707    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
708        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
709        return 2.0;
710    }
711    aXb = a*b;
712    fpClassAxB = std::fpclassify(aXb);
713    if (fpClassAxB == FP_SUBNORMAL) {
714       feraiseexcept(FeUnderflow);
715       return 2.0;
716    }
717    return 2.0 - (a * b);
718};
719
720
721static inline float
722fpRSqrtsS(float a, float b)
723{
724    int fpClassA = std::fpclassify(a);
725    int fpClassB = std::fpclassify(b);
726    float aXb;
727    int fpClassAxB;
728
729    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
730        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
731        return 1.5;
732    }
733    aXb = a*b;
734    fpClassAxB = std::fpclassify(aXb);
735    if (fpClassAxB == FP_SUBNORMAL) {
736       feraiseexcept(FeUnderflow);
737       return 1.5;
738    }
739    return (3.0 - (a * b)) / 2.0;
740}
741
742static inline float
743fpRecpsS(float a, float b)
744{
745    int fpClassA = std::fpclassify(a);
746    int fpClassB = std::fpclassify(b);
747    float aXb;
748    int fpClassAxB;
749
750    if ((fpClassA == FP_ZERO && fpClassB == FP_INFINITE) ||
751        (fpClassA == FP_INFINITE && fpClassB == FP_ZERO)) {
752        return 2.0;
753    }
754    aXb = a*b;
755    fpClassAxB = std::fpclassify(aXb);
756    if (fpClassAxB == FP_SUBNORMAL) {
757       feraiseexcept(FeUnderflow);
758       return 2.0;
759    }
760    return 2.0 - (a * b);
761}
762
763template <typename T>
764static inline T
765roundNEven(T a) {
766    T val;
767
768    val = round(a);
769    if (a - val == 0.5) {
770        if ( (((int) a) & 1) == 0 ) val += 1.0;
771    }
772    else if (a - val == -0.5) {
773        if ( (((int) a) & 1) == 0 ) val -= 1.0;
774    }
775    return val;
776}
777
778
779
780class FpOp : public PredOp
781{
782  protected:
783    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
784        PredOp(mnem, _machInst, __opClass)
785    {}
786
787    virtual float
788    doOp(float op1, float op2) const
789    {
790        panic("Unimplemented version of doOp called.\n");
791    }
792
793    virtual float
794    doOp(float op1) const
795    {
796        panic("Unimplemented version of doOp called.\n");
797    }
798
799    virtual double
800    doOp(double op1, double op2) const
801    {
802        panic("Unimplemented version of doOp called.\n");
803    }
804
805    virtual double
806    doOp(double op1) const
807    {
808        panic("Unimplemented version of doOp called.\n");
809    }
810
811    double
812    dbl(uint32_t low, uint32_t high) const
813    {
814        double junk = 0.0;
815        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
816    }
817
818    uint32_t
819    dblLow(double val) const
820    {
821        return fpToBits(val);
822    }
823
824    uint32_t
825    dblHi(double val) const
826    {
827        return fpToBits(val) >> 32;
828    }
829
830    template <class fpType>
831    fpType
832    processNans(FPSCR &fpscr, bool &done, bool defaultNan,
833                fpType op1, fpType op2) const;
834
835    template <class fpType>
836    fpType
837    ternaryOp(FPSCR &fpscr, fpType op1, fpType op2, fpType op3,
838              fpType (*func)(fpType, fpType, fpType),
839              bool flush, bool defaultNan, uint32_t rMode) const;
840
841    template <class fpType>
842    fpType
843    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
844            fpType (*func)(fpType, fpType),
845            bool flush, bool defaultNan, uint32_t rMode) const;
846
847    template <class fpType>
848    fpType
849    unaryOp(FPSCR &fpscr, fpType op1,
850            fpType (*func)(fpType),
851            bool flush, uint32_t rMode) const;
852
853    void
854    advancePC(PCState &pcState) const
855    {
856        if (flags[IsLastMicroop]) {
857            pcState.uEnd();
858        } else if (flags[IsMicroop]) {
859            pcState.uAdvance();
860        } else {
861            pcState.advance();
862        }
863    }
864
865    float
866    fpSqrt (FPSCR fpscr,float x) const
867    {
868
869        return unaryOp(fpscr,x,sqrtf,fpscr.fz,fpscr.rMode);
870
871    }
872
873    double
874    fpSqrt (FPSCR fpscr,double x) const
875    {
876
877        return unaryOp(fpscr,x,sqrt,fpscr.fz,fpscr.rMode);
878
879    }
880};
881
882class FpCondCompRegOp : public FpOp
883{
884  protected:
885    IntRegIndex op1, op2;
886    ConditionCode condCode;
887    uint8_t defCc;
888
889    FpCondCompRegOp(const char *mnem, ExtMachInst _machInst,
890                       OpClass __opClass, IntRegIndex _op1, IntRegIndex _op2,
891                       ConditionCode _condCode, uint8_t _defCc) :
892        FpOp(mnem, _machInst, __opClass),
893        op1(_op1), op2(_op2), condCode(_condCode), defCc(_defCc)
894    {}
895
896    std::string generateDisassembly(
897            Addr pc, const SymbolTable *symtab) const override;
898};
899
900class FpCondSelOp : public FpOp
901{
902  protected:
903    IntRegIndex dest, op1, op2;
904    ConditionCode condCode;
905
906    FpCondSelOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
907                IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
908                ConditionCode _condCode) :
909        FpOp(mnem, _machInst, __opClass),
910        dest(_dest), op1(_op1), op2(_op2), condCode(_condCode)
911    {}
912
913    std::string generateDisassembly(
914            Addr pc, const SymbolTable *symtab) const override;
915};
916
917class FpRegRegOp : public FpOp
918{
919  protected:
920    IntRegIndex dest;
921    IntRegIndex op1;
922
923    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
924               IntRegIndex _dest, IntRegIndex _op1,
925               VfpMicroMode mode = VfpNotAMicroop) :
926        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
927    {
928        setVfpMicroFlags(mode, flags);
929    }
930
931    std::string generateDisassembly(
932            Addr pc, const SymbolTable *symtab) const override;
933};
934
935class FpRegImmOp : public FpOp
936{
937  protected:
938    IntRegIndex dest;
939    uint64_t imm;
940
941    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
942               IntRegIndex _dest, uint64_t _imm,
943               VfpMicroMode mode = VfpNotAMicroop) :
944        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
945    {
946        setVfpMicroFlags(mode, flags);
947    }
948
949    std::string generateDisassembly(
950            Addr pc, const SymbolTable *symtab) const override;
951};
952
953class FpRegRegImmOp : public FpOp
954{
955  protected:
956    IntRegIndex dest;
957    IntRegIndex op1;
958    uint64_t imm;
959
960    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
961                  IntRegIndex _dest, IntRegIndex _op1,
962                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
963        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
964    {
965        setVfpMicroFlags(mode, flags);
966    }
967
968    std::string generateDisassembly(
969            Addr pc, const SymbolTable *symtab) const override;
970};
971
972class FpRegRegRegOp : public FpOp
973{
974  protected:
975    IntRegIndex dest;
976    IntRegIndex op1;
977    IntRegIndex op2;
978
979    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
980                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
981                  VfpMicroMode mode = VfpNotAMicroop) :
982        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
983    {
984        setVfpMicroFlags(mode, flags);
985    }
986
987    std::string generateDisassembly(
988            Addr pc, const SymbolTable *symtab) const override;
989};
990
991class FpRegRegRegCondOp : public FpOp
992{
993  protected:
994    IntRegIndex dest;
995    IntRegIndex op1;
996    IntRegIndex op2;
997    ConditionCode cond;
998
999    FpRegRegRegCondOp(const char *mnem, ExtMachInst _machInst,
1000                      OpClass __opClass, IntRegIndex _dest, IntRegIndex _op1,
1001                      IntRegIndex _op2, ConditionCode _cond,
1002                      VfpMicroMode mode = VfpNotAMicroop) :
1003        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2),
1004        cond(_cond)
1005    {
1006        setVfpMicroFlags(mode, flags);
1007    }
1008
1009    std::string generateDisassembly(
1010            Addr pc, const SymbolTable *symtab) const override;
1011};
1012
1013class FpRegRegRegRegOp : public FpOp
1014{
1015  protected:
1016    IntRegIndex dest;
1017    IntRegIndex op1;
1018    IntRegIndex op2;
1019    IntRegIndex op3;
1020
1021    FpRegRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
1022                     IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
1023                     IntRegIndex _op3, VfpMicroMode mode = VfpNotAMicroop) :
1024        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2),
1025        op3(_op3)
1026    {
1027        setVfpMicroFlags(mode, flags);
1028    }
1029
1030    std::string generateDisassembly(
1031            Addr pc, const SymbolTable *symtab) const override;
1032};
1033
1034class FpRegRegRegImmOp : public FpOp
1035{
1036  protected:
1037    IntRegIndex dest;
1038    IntRegIndex op1;
1039    IntRegIndex op2;
1040    uint64_t imm;
1041
1042    FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst,
1043                     OpClass __opClass, IntRegIndex _dest,
1044                     IntRegIndex _op1, IntRegIndex _op2,
1045                     uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
1046        FpOp(mnem, _machInst, __opClass),
1047        dest(_dest), op1(_op1), op2(_op2), imm(_imm)
1048    {
1049        setVfpMicroFlags(mode, flags);
1050    }
1051
1052    std::string generateDisassembly(
1053            Addr pc, const SymbolTable *symtab) const override;
1054};
1055
1056}
1057
1058#endif //__ARCH_ARM_INSTS_VFP_HH__
1059