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