vfp.hh revision 7430:db3e376f35d1
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
195typedef int VfpSavedState;
196
197VfpSavedState prepFpState(uint32_t rMode);
198void finishVfp(FPSCR &fpscr, VfpSavedState state);
199
200template <class fpType>
201fpType fixDest(FPSCR fpscr, fpType val, fpType op1);
202
203template <class fpType>
204fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
205
206template <class fpType>
207fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
208
209float fixFpDFpSDest(FPSCR fpscr, double val);
210double fixFpSFpDDest(FPSCR fpscr, float val);
211
212float vcvtFpSFpH(FPSCR &fpscr, float op, float dest, bool top);
213float vcvtFpHFpS(FPSCR &fpscr, float op, bool top);
214
215static inline double
216makeDouble(uint32_t low, uint32_t high)
217{
218    double junk = 0.0;
219    return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
220}
221
222static inline uint32_t
223lowFromDouble(double val)
224{
225    return fpToBits(val);
226}
227
228static inline uint32_t
229highFromDouble(double val)
230{
231    return fpToBits(val) >> 32;
232}
233
234uint64_t vfpFpSToFixed(float val, bool isSigned, bool half,
235                       uint8_t imm, bool rzero = true);
236float vfpUFixedToFpS(FPSCR fpscr, uint32_t val, bool half, uint8_t imm);
237float vfpSFixedToFpS(FPSCR fpscr, int32_t val, bool half, uint8_t imm);
238
239uint64_t vfpFpDToFixed(double val, bool isSigned, bool half,
240                       uint8_t imm, bool rzero = true);
241double vfpUFixedToFpD(FPSCR fpscr, uint32_t val, bool half, uint8_t imm);
242double vfpSFixedToFpD(FPSCR fpscr, int32_t val, bool half, uint8_t imm);
243
244class VfpMacroOp : public PredMacroOp
245{
246  public:
247    static bool
248    inScalarBank(IntRegIndex idx)
249    {
250        return (idx % 32) < 8;
251    }
252
253  protected:
254    bool wide;
255
256    VfpMacroOp(const char *mnem, ExtMachInst _machInst,
257            OpClass __opClass, bool _wide) :
258        PredMacroOp(mnem, _machInst, __opClass), wide(_wide)
259    {}
260
261    IntRegIndex addStride(IntRegIndex idx, unsigned stride);
262    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1, IntRegIndex &op2);
263    void nextIdxs(IntRegIndex &dest, IntRegIndex &op1);
264    void nextIdxs(IntRegIndex &dest);
265};
266
267static inline float
268fpAddS(float a, float b)
269{
270    return a + b;
271}
272
273static inline double
274fpAddD(double a, double b)
275{
276    return a + b;
277}
278
279static inline float
280fpSubS(float a, float b)
281{
282    return a - b;
283}
284
285static inline double
286fpSubD(double a, double b)
287{
288    return a - b;
289}
290
291static inline float
292fpDivS(float a, float b)
293{
294    return a / b;
295}
296
297static inline double
298fpDivD(double a, double b)
299{
300    return a / b;
301}
302
303static inline float
304fpMulS(float a, float b)
305{
306    return a * b;
307}
308
309static inline double
310fpMulD(double a, double b)
311{
312    return a * b;
313}
314
315class FpOp : public PredOp
316{
317  protected:
318    FpOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
319        PredOp(mnem, _machInst, __opClass)
320    {}
321
322    virtual float
323    doOp(float op1, float op2) const
324    {
325        panic("Unimplemented version of doOp called.\n");
326    }
327
328    virtual float
329    doOp(float op1) const
330    {
331        panic("Unimplemented version of doOp called.\n");
332    }
333
334    virtual double
335    doOp(double op1, double op2) const
336    {
337        panic("Unimplemented version of doOp called.\n");
338    }
339
340    virtual double
341    doOp(double op1) const
342    {
343        panic("Unimplemented version of doOp called.\n");
344    }
345
346    double
347    dbl(uint32_t low, uint32_t high) const
348    {
349        double junk = 0.0;
350        return bitsToFp((uint64_t)low | ((uint64_t)high << 32), junk);
351    }
352
353    uint32_t
354    dblLow(double val) const
355    {
356        return fpToBits(val);
357    }
358
359    uint32_t
360    dblHi(double val) const
361    {
362        return fpToBits(val) >> 32;
363    }
364
365    template <class fpType>
366    fpType
367    binaryOp(FPSCR &fpscr, fpType op1, fpType op2,
368            fpType (*func)(fpType, fpType),
369            bool flush, uint32_t rMode) const;
370
371    template <class fpType>
372    fpType
373    unaryOp(FPSCR &fpscr, fpType op1,
374            fpType (*func)(fpType),
375            bool flush, uint32_t rMode) const;
376};
377
378class FpRegRegOp : public FpOp
379{
380  protected:
381    IntRegIndex dest;
382    IntRegIndex op1;
383
384    FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
385               IntRegIndex _dest, IntRegIndex _op1,
386               VfpMicroMode mode = VfpNotAMicroop) :
387        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
388    {
389        setVfpMicroFlags(mode, flags);
390    }
391
392    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
393};
394
395class FpRegImmOp : public FpOp
396{
397  protected:
398    IntRegIndex dest;
399    uint64_t imm;
400
401    FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
402               IntRegIndex _dest, uint64_t _imm,
403               VfpMicroMode mode = VfpNotAMicroop) :
404        FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
405    {
406        setVfpMicroFlags(mode, flags);
407    }
408
409    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
410};
411
412class FpRegRegImmOp : public FpOp
413{
414  protected:
415    IntRegIndex dest;
416    IntRegIndex op1;
417    uint64_t imm;
418
419    FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
420                  IntRegIndex _dest, IntRegIndex _op1,
421                  uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
422        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
423    {
424        setVfpMicroFlags(mode, flags);
425    }
426
427    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
428};
429
430class FpRegRegRegOp : public FpOp
431{
432  protected:
433    IntRegIndex dest;
434    IntRegIndex op1;
435    IntRegIndex op2;
436
437    FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
438                  IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
439                  VfpMicroMode mode = VfpNotAMicroop) :
440        FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
441    {
442        setVfpMicroFlags(mode, flags);
443    }
444
445    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
446};
447
448}
449
450#endif //__ARCH_ARM_INSTS_VFP_HH__
451