9babaae04fb7cffc34731442ae44cef1e86089a8
[gem5.git] / src / arch / arm / insts / vfp.hh
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
50 namespace ArmISA
51 {
52
53 enum VfpMicroMode {
54 VfpNotAMicroop,
55 VfpMicroop,
56 VfpFirstMicroop,
57 VfpLastMicroop
58 };
59
60 template<class T>
61 static inline void
62 setVfpMicroFlags(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
84 enum 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
94 enum FeRoundingMode
95 {
96 FeRoundDown = FE_DOWNWARD,
97 FeRoundNearest = FE_TONEAREST,
98 FeRoundZero = FE_TOWARDZERO,
99 FeRoundUpward = FE_UPWARD
100 };
101
102 enum VfpRoundingMode
103 {
104 VfpRoundNearest = 0,
105 VfpRoundUpward = 1,
106 VfpRoundDown = 2,
107 VfpRoundZero = 3
108 };
109
110 static inline float bitsToFp(uint64_t, float);
111 static inline double bitsToFp(uint64_t, double);
112 static inline uint32_t fpToBits(float);
113 static inline uint64_t fpToBits(double);
114
115 template <class fpType>
116 static inline bool
117 flushToZero(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
128 template <class fpType>
129 static inline bool
130 flushToZero(fpType &op1, fpType &op2)
131 {
132 bool flush1 = flushToZero(op1);
133 bool flush2 = flushToZero(op2);
134 return flush1 || flush2;
135 }
136
137 template <class fpType>
138 static inline void
139 vfpFlushToZero(FPSCR &fpscr, fpType &op)
140 {
141 if (fpscr.fz == 1 && flushToZero(op)) {
142 fpscr.idc = 1;
143 }
144 }
145
146 template <class fpType>
147 static inline void
148 vfpFlushToZero(FPSCR &fpscr, fpType &op1, fpType &op2)
149 {
150 vfpFlushToZero(fpscr, op1);
151 vfpFlushToZero(fpscr, op2);
152 }
153
154 static inline uint32_t
155 fpToBits(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
166 static inline uint64_t
167 fpToBits(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
178 static inline float
179 bitsToFp(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
190 static inline double
191 bitsToFp(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
202 template <class fpType>
203 static bool
204 isSnan(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
212 typedef int VfpSavedState;
213
214 VfpSavedState prepFpState(uint32_t rMode);
215 void finishVfp(FPSCR &fpscr, VfpSavedState state, bool flush);
216
217 template <class fpType>
218 fpType fixDest(FPSCR fpscr, fpType val, fpType op1);
219
220 template <class fpType>
221 fpType fixDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
222
223 template <class fpType>
224 fpType fixDivDest(FPSCR fpscr, fpType val, fpType op1, fpType op2);
225
226 float fixFpDFpSDest(FPSCR fpscr, double val);
227 double fixFpSFpDDest(FPSCR fpscr, float val);
228
229 uint16_t vcvtFpSFpH(FPSCR &fpscr, bool flush, bool defaultNan,
230 uint32_t rMode, bool ahp, float op);
231 float vcvtFpHFpS(FPSCR &fpscr, bool defaultNan, bool ahp, uint16_t op);
232
233 static inline double
234 makeDouble(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
240 static inline uint32_t
241 lowFromDouble(double val)
242 {
243 return fpToBits(val);
244 }
245
246 static inline uint32_t
247 highFromDouble(double val)
248 {
249 return fpToBits(val) >> 32;
250 }
251
252 uint64_t vfpFpSToFixed(float val, bool isSigned, bool half,
253 uint8_t imm, bool rzero = true);
254 float vfpUFixedToFpS(bool flush, bool defaultNan,
255 uint32_t val, bool half, uint8_t imm);
256 float vfpSFixedToFpS(bool flush, bool defaultNan,
257 int32_t val, bool half, uint8_t imm);
258
259 uint64_t vfpFpDToFixed(double val, bool isSigned, bool half,
260 uint8_t imm, bool rzero = true);
261 double vfpUFixedToFpD(bool flush, bool defaultNan,
262 uint32_t val, bool half, uint8_t imm);
263 double vfpSFixedToFpD(bool flush, bool defaultNan,
264 int32_t val, bool half, uint8_t imm);
265
266 float fprSqrtEstimate(FPSCR &fpscr, float op);
267 uint32_t unsignedRSqrtEstimate(uint32_t op);
268
269 float fpRecipEstimate(FPSCR &fpscr, float op);
270 uint32_t unsignedRecipEstimate(uint32_t op);
271
272 class 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
295 static inline float
296 fpAddS(float a, float b)
297 {
298 return a + b;
299 }
300
301 static inline double
302 fpAddD(double a, double b)
303 {
304 return a + b;
305 }
306
307 static inline float
308 fpSubS(float a, float b)
309 {
310 return a - b;
311 }
312
313 static inline double
314 fpSubD(double a, double b)
315 {
316 return a - b;
317 }
318
319 static inline float
320 fpDivS(float a, float b)
321 {
322 return a / b;
323 }
324
325 static inline double
326 fpDivD(double a, double b)
327 {
328 return a / b;
329 }
330
331 static inline float
332 fpMulS(float a, float b)
333 {
334 return a * b;
335 }
336
337 static inline double
338 fpMulD(double a, double b)
339 {
340 return a * b;
341 }
342
343 static inline float
344 fpMaxS(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
352 static inline float
353 fpMinS(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
361 static inline float
362 fpRSqrtsS(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
382 static inline float
383 fpRecpsS(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
403 class 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
483 class 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
500 class 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
517 class 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
535 class 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
553 class 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__