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