Deleted Added
sdiff udiff text old ( 7430:db3e376f35d1 ) new ( 7639:8c09b7ff5b57 )
full compact
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
464class FpRegRegOp : public FpOp
465{
466 protected:
467 IntRegIndex dest;
468 IntRegIndex op1;
469
470 FpRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
471 IntRegIndex _dest, IntRegIndex _op1,
472 VfpMicroMode mode = VfpNotAMicroop) :
473 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1)
474 {
475 setVfpMicroFlags(mode, flags);
476 }
477
478 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
479};
480
481class FpRegImmOp : public FpOp
482{
483 protected:
484 IntRegIndex dest;
485 uint64_t imm;
486
487 FpRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
488 IntRegIndex _dest, uint64_t _imm,
489 VfpMicroMode mode = VfpNotAMicroop) :
490 FpOp(mnem, _machInst, __opClass), dest(_dest), imm(_imm)
491 {
492 setVfpMicroFlags(mode, flags);
493 }
494
495 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
496};
497
498class FpRegRegImmOp : public FpOp
499{
500 protected:
501 IntRegIndex dest;
502 IntRegIndex op1;
503 uint64_t imm;
504
505 FpRegRegImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
506 IntRegIndex _dest, IntRegIndex _op1,
507 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
508 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), imm(_imm)
509 {
510 setVfpMicroFlags(mode, flags);
511 }
512
513 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
514};
515
516class FpRegRegRegOp : public FpOp
517{
518 protected:
519 IntRegIndex dest;
520 IntRegIndex op1;
521 IntRegIndex op2;
522
523 FpRegRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
524 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
525 VfpMicroMode mode = VfpNotAMicroop) :
526 FpOp(mnem, _machInst, __opClass), dest(_dest), op1(_op1), op2(_op2)
527 {
528 setVfpMicroFlags(mode, flags);
529 }
530
531 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
532};
533
534class FpRegRegRegImmOp : public FpOp
535{
536 protected:
537 IntRegIndex dest;
538 IntRegIndex op1;
539 IntRegIndex op2;
540 uint64_t imm;
541
542 FpRegRegRegImmOp(const char *mnem, ExtMachInst _machInst,
543 OpClass __opClass, IntRegIndex _dest,
544 IntRegIndex _op1, IntRegIndex _op2,
545 uint64_t _imm, VfpMicroMode mode = VfpNotAMicroop) :
546 FpOp(mnem, _machInst, __opClass),
547 dest(_dest), op1(_op1), op2(_op2), imm(_imm)
548 {
549 setVfpMicroFlags(mode, flags);
550 }
551
552 std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
553};
554
555}
556
557#endif //__ARCH_ARM_INSTS_VFP_HH__