1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  scfx_ieee.h -
23
24  Original Author: Martin Janssen, Synopsys, Inc.
25
26 *****************************************************************************/
27
28/*****************************************************************************
29
30  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
31  changes you are making here.
32
33      Name, Affiliation, Date:
34  Description of Modification:
35
36 *****************************************************************************/
37
38// $Log: scfx_ieee.h,v $
39// Revision 1.3  2011/08/24 22:05:43  acg
40//  Torsten Maehne: initialization changes to remove warnings.
41//
42// Revision 1.2  2011/08/07 18:55:24  acg
43//  Philipp A. Hartmann: added guard for __clang__ to get the clang platform
44//  working.
45//
46// Revision 1.1.1.1  2006/12/15 20:20:04  acg
47// SystemC 2.3
48//
49// Revision 1.3  2006/01/13 18:53:58  acg
50// Andy Goodrich: added $Log command so that CVS comments are reproduced in
51// the source.
52//
53
54#ifndef __SYSTEMC_EXT_DT_FX_SCFX_IEEE_HH__
55#define __SYSTEMC_EXT_DT_FX_SCFX_IEEE_HH__
56
57#include "../../utils/endian.hh"
58#include "sc_fxdefs.hh"
59
60namespace sc_dt
61{
62
63// classes defined in this module
64union ieee_double;
65class scfx_ieee_double;
66union ieee_float;
67class scfx_ieee_float;
68
69#define SCFX_MASK_(Size) ((1u << (Size))-1u)
70
71// ----------------------------------------------------------------------------
72//  UNION : ieee_double
73//
74//  IEEE 754 double-precision format.
75// ----------------------------------------------------------------------------
76
77union ieee_double
78{
79    double d;
80
81    struct
82    {
83#if defined(SC_BOOST_BIG_ENDIAN)
84        unsigned negative:1;
85        unsigned exponent:11;
86        unsigned mantissa0:20;
87        unsigned mantissa1:32;
88#elif defined(SC_BOOST_LITTLE_ENDIAN)
89        unsigned mantissa1:32;
90        unsigned mantissa0:20;
91        unsigned exponent:11;
92        unsigned negative:1;
93#endif
94    } s;
95};
96
97
98const unsigned int SCFX_IEEE_DOUBLE_BIAS = 1023U;
99
100const int SCFX_IEEE_DOUBLE_E_MAX = 1023;
101const int SCFX_IEEE_DOUBLE_E_MIN = -1022;
102
103const unsigned int SCFX_IEEE_DOUBLE_M_SIZE = 52;
104const unsigned int SCFX_IEEE_DOUBLE_M0_SIZE = 20;
105const unsigned int SCFX_IEEE_DOUBLE_M1_SIZE = 32;
106const unsigned int SCFX_IEEE_DOUBLE_E_SIZE = 11;
107
108
109// ----------------------------------------------------------------------------
110//  CLASS : scfx_ieee_double
111//
112//  Convenient interface to union ieee_double.
113// ----------------------------------------------------------------------------
114
115class scfx_ieee_double
116{
117    ieee_double m_id;
118  public:
119    scfx_ieee_double();
120    scfx_ieee_double(double);
121    scfx_ieee_double(const scfx_ieee_double &);
122
123    scfx_ieee_double &operator = (double);
124    scfx_ieee_double &operator = (const scfx_ieee_double &);
125
126    operator double() const;
127
128    unsigned int negative() const;
129    void negative(unsigned int);
130    int exponent() const;
131    void exponent(int);
132    unsigned int mantissa0() const;
133    void mantissa0(unsigned int);
134    unsigned int mantissa1() const;
135    void mantissa1(unsigned int);
136
137    bool is_zero() const;
138    bool is_subnormal() const;
139    bool is_normal() const;
140    bool is_inf() const;
141    bool is_nan() const;
142
143    void set_inf();
144    void set_nan();
145
146    int msb() const; // most significant non-zero bit
147    int lsb() const; // least significant non-zero bit
148
149    static const scfx_ieee_double nan();
150    static const scfx_ieee_double inf(int);
151};
152
153
154// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
155
156inline scfx_ieee_double::scfx_ieee_double() : m_id()
157{
158    m_id.d = 0.0;
159}
160
161inline scfx_ieee_double::scfx_ieee_double(double d) : m_id()
162{
163    m_id.d = d;
164}
165
166inline scfx_ieee_double::scfx_ieee_double(const scfx_ieee_double &a) :
167        m_id(a.m_id)
168{
169    // m_id.d = a.m_id.d;
170}
171
172inline scfx_ieee_double &
173scfx_ieee_double::operator = (double d)
174{
175    m_id.d = d;
176    return *this;
177}
178
179inline scfx_ieee_double &
180scfx_ieee_double::operator = (const scfx_ieee_double &a)
181{
182    m_id.d = a.m_id.d;
183    return *this;
184}
185
186inline scfx_ieee_double::operator double() const
187{
188    return m_id.d;
189}
190
191inline unsigned int
192scfx_ieee_double::negative() const
193{
194    return m_id.s.negative;
195}
196
197inline void
198scfx_ieee_double::negative(unsigned int a)
199{
200    m_id.s.negative = a & SCFX_MASK_(1);
201}
202
203inline int
204scfx_ieee_double::exponent() const
205{
206    return m_id.s.exponent - SCFX_IEEE_DOUBLE_BIAS;
207}
208
209inline void
210scfx_ieee_double::exponent(int a)
211{
212    m_id.s.exponent = (SCFX_IEEE_DOUBLE_BIAS + a)
213                      & SCFX_MASK_(SCFX_IEEE_DOUBLE_E_SIZE);
214}
215
216inline unsigned int
217scfx_ieee_double::mantissa0() const
218{
219    return m_id.s.mantissa0;
220}
221
222inline void
223scfx_ieee_double::mantissa0(unsigned int a)
224{
225    m_id.s.mantissa0 = a & SCFX_MASK_(SCFX_IEEE_DOUBLE_M0_SIZE);
226}
227
228inline unsigned int
229scfx_ieee_double::mantissa1() const
230{
231    return m_id.s.mantissa1;
232}
233
234inline void
235scfx_ieee_double::mantissa1(unsigned int a)
236{
237    m_id.s.mantissa1 = a; // & SCFX_MASK_(SCFX_IEEE_DOUBLE_M1_SIZE);
238}
239
240inline bool
241scfx_ieee_double::is_zero() const
242{
243    return (exponent() == SCFX_IEEE_DOUBLE_E_MIN - 1 &&
244            mantissa0() == 0U && mantissa1() == 0U);
245}
246
247inline bool
248scfx_ieee_double::is_subnormal() const
249{
250    return (exponent() == SCFX_IEEE_DOUBLE_E_MIN - 1 &&
251            (mantissa0() != 0U || mantissa1() != 0U));
252}
253
254inline bool
255scfx_ieee_double::is_normal() const
256{
257    return (exponent() >= SCFX_IEEE_DOUBLE_E_MIN &&
258            exponent() <= SCFX_IEEE_DOUBLE_E_MAX);
259}
260
261inline bool
262scfx_ieee_double::is_inf() const
263{
264    return (exponent() == SCFX_IEEE_DOUBLE_E_MAX + 1 &&
265            mantissa0() == 0U && mantissa1() == 0U);
266}
267
268inline bool
269scfx_ieee_double::is_nan() const
270{
271    return (exponent() == SCFX_IEEE_DOUBLE_E_MAX + 1 &&
272             (mantissa0() != 0U || mantissa1() != 0U));
273}
274
275inline void
276scfx_ieee_double::set_inf()
277{
278    exponent(SCFX_IEEE_DOUBLE_E_MAX + 1);
279    mantissa0(0U);
280    mantissa1(0U);
281}
282
283inline void
284scfx_ieee_double::set_nan()
285{
286    exponent(SCFX_IEEE_DOUBLE_E_MAX + 1);
287    mantissa0((unsigned int)-1);
288    mantissa1((unsigned int)-1);
289}
290
291#define MSB_STATEMENT(x,n) if ( x >> n ) { x >>= n; i += n; }
292
293inline int
294scfx_ieee_double::msb() const
295{
296    unsigned int m0 = mantissa0();
297    unsigned int m1 = mantissa1();
298    if (m0 != 0) {
299        int i = 0;
300        MSB_STATEMENT(m0, 16);
301        MSB_STATEMENT(m0, 8);
302        MSB_STATEMENT(m0, 4);
303        MSB_STATEMENT(m0, 2);
304        MSB_STATEMENT(m0, 1);
305        return (i - 20);
306    } else if (m1 != 0) {
307        int i = 0;
308        MSB_STATEMENT(m1, 16);
309        MSB_STATEMENT(m1, 8);
310        MSB_STATEMENT(m1, 4);
311        MSB_STATEMENT(m1, 2);
312        MSB_STATEMENT(m1, 1);
313        return (i - 52);
314    } else {
315        return 0;
316    }
317}
318
319#undef MSB_STATEMENT
320
321#define LSB_STATEMENT(x,n) if ( x << n ) { x <<= n; i -= n; }
322
323inline int
324scfx_ieee_double::lsb() const
325{
326    unsigned int m0 = mantissa0();
327    unsigned int m1 = mantissa1();
328    if (m1 != 0) {
329        int i = 31;
330        LSB_STATEMENT(m1, 16);
331        LSB_STATEMENT(m1, 8);
332        LSB_STATEMENT(m1, 4);
333        LSB_STATEMENT(m1, 2);
334        LSB_STATEMENT(m1, 1);
335        return (i - 52);
336    } else if (m0 != 0) {
337        int i = 31;
338        LSB_STATEMENT(m0, 16);
339        LSB_STATEMENT(m0, 8);
340        LSB_STATEMENT(m0, 4);
341        LSB_STATEMENT(m0, 2);
342        LSB_STATEMENT(m0, 1);
343        return (i - 20);
344    } else {
345        return 0;
346    }
347}
348
349#undef LSB_STATEMENT
350
351inline const scfx_ieee_double
352scfx_ieee_double::nan()
353{
354    scfx_ieee_double id;
355    id.set_nan();
356    return id;
357}
358
359inline const scfx_ieee_double
360scfx_ieee_double::inf(int sign)
361{
362    scfx_ieee_double id(sign);
363    id.set_inf();
364    return id;
365}
366
367
368// ----------------------------------------------------------------------------
369//  UNION : ieee_float
370//
371//  IEEE 754 single-precision format.
372// ----------------------------------------------------------------------------
373
374union ieee_float
375{
376    float f;
377    struct
378    {
379#if defined(SC_BOOST_BIG_ENDIAN)
380        unsigned negative:1;
381        unsigned exponent:8;
382        unsigned mantissa:23;
383#elif defined(SC_BOOST_LITTLE_ENDIAN)
384        unsigned mantissa:23;
385        unsigned exponent:8;
386        unsigned negative:1;
387#endif
388    } s;
389};
390
391
392const unsigned int SCFX_IEEE_FLOAT_BIAS = 127U;
393
394const int SCFX_IEEE_FLOAT_E_MAX = 127;
395const int SCFX_IEEE_FLOAT_E_MIN = -126;
396
397const unsigned int SCFX_IEEE_FLOAT_M_SIZE = 23;
398const unsigned int SCFX_IEEE_FLOAT_E_SIZE = 8;
399
400
401// ----------------------------------------------------------------------------
402//  CLASS : scfx_ieee_float
403//
404// Convenient wrapper to union ieee_float.
405// ----------------------------------------------------------------------------
406
407class scfx_ieee_float
408{
409    ieee_float m_if;
410
411  public:
412    scfx_ieee_float();
413    scfx_ieee_float(float);
414    scfx_ieee_float(const scfx_ieee_float &);
415
416    scfx_ieee_float &operator = (float);
417    scfx_ieee_float &operator = (const scfx_ieee_float &);
418
419    operator float() const;
420
421    unsigned int negative() const;
422    void negative(unsigned int);
423    int exponent() const;
424    void exponent(int);
425    unsigned int mantissa() const;
426    void mantissa(unsigned int);
427
428    bool is_zero() const;
429    bool is_subnormal() const;
430    bool is_normal() const;
431    bool is_inf() const;
432    bool is_nan() const;
433
434    void set_inf();
435    void set_nan();
436};
437
438
439// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
440
441inline scfx_ieee_float::scfx_ieee_float() : m_if()
442{
443    m_if.f = 0.0;
444}
445
446inline scfx_ieee_float::scfx_ieee_float(float f) : m_if()
447{
448    m_if.f = f;
449}
450
451inline scfx_ieee_float::scfx_ieee_float(const scfx_ieee_float &a) :
452        m_if(a.m_if)
453{
454    // m_if.f = a.m_if.f;
455}
456
457
458inline scfx_ieee_float &
459scfx_ieee_float::operator = (float f)
460{
461    m_if.f = f;
462    return *this;
463}
464
465inline scfx_ieee_float &
466scfx_ieee_float::operator = (const scfx_ieee_float &a)
467{
468    m_if.f = a.m_if.f;
469    return *this;
470}
471
472inline scfx_ieee_float::operator float() const
473{
474    return m_if.f;
475}
476
477inline unsigned int
478scfx_ieee_float::negative() const
479{
480    return m_if.s.negative;
481}
482
483inline void
484scfx_ieee_float::negative(unsigned int a)
485{
486    m_if.s.negative = a & SCFX_MASK_(1);
487}
488
489inline int
490scfx_ieee_float::exponent() const
491{
492    return m_if.s.exponent - SCFX_IEEE_FLOAT_BIAS;
493}
494
495inline void
496scfx_ieee_float::exponent(int a)
497{
498    m_if.s.exponent = (SCFX_IEEE_FLOAT_BIAS + a) &
499                      SCFX_MASK_(SCFX_IEEE_FLOAT_E_SIZE);
500}
501
502inline unsigned int
503scfx_ieee_float::mantissa() const
504{
505    return m_if.s.mantissa;
506}
507
508inline void
509scfx_ieee_float::mantissa(unsigned int a)
510{
511    m_if.s.mantissa = a & SCFX_MASK_(SCFX_IEEE_FLOAT_M_SIZE);
512}
513
514
515inline bool
516scfx_ieee_float::is_zero() const
517{
518    return (exponent() == SCFX_IEEE_FLOAT_E_MIN - 1 && mantissa() == 0U);
519}
520
521inline bool
522scfx_ieee_float::is_subnormal() const
523{
524    return (exponent() == SCFX_IEEE_FLOAT_E_MIN - 1 && mantissa() != 0U);
525}
526
527inline bool
528scfx_ieee_float::is_normal() const
529{
530    return (exponent() >= SCFX_IEEE_FLOAT_E_MIN &&
531            exponent() <= SCFX_IEEE_FLOAT_E_MAX);
532}
533
534inline bool
535scfx_ieee_float::is_inf() const
536{
537    return (exponent() == SCFX_IEEE_FLOAT_E_MAX + 1 && mantissa() == 0U);
538}
539
540inline bool
541scfx_ieee_float::is_nan() const
542{
543    return (exponent() == SCFX_IEEE_FLOAT_E_MAX + 1 && mantissa() != 0U);
544}
545
546inline void
547scfx_ieee_float::set_inf()
548{
549    exponent(SCFX_IEEE_FLOAT_E_MAX + 1);
550    mantissa(0U);
551}
552
553inline void
554scfx_ieee_float::set_nan()
555{
556    exponent(SCFX_IEEE_FLOAT_E_MAX + 1);
557    mantissa((unsigned int)-1);
558}
559
560
561// ----------------------------------------------------------------------------
562//  FUNCTION : scfx_pow2
563//
564//  Computes 2.0**exp in double-precision.
565// ----------------------------------------------------------------------------
566
567inline double
568scfx_pow2(int exp)
569{
570    scfx_ieee_double r;
571    if (exp < SCFX_IEEE_DOUBLE_E_MIN) {
572        r = 0.0;
573        // handle subnormal case
574        exp -= SCFX_IEEE_DOUBLE_E_MIN;
575        if ((exp += 20) >= 0) {
576            r.mantissa0(1U << exp);
577        } else if ((exp += 32) >= 0) {
578            r.mantissa1(1U << exp);
579        }
580    } else if (exp > SCFX_IEEE_DOUBLE_E_MAX) {
581        r.set_inf();
582    } else {
583        r = 1.0;
584        r.exponent(exp);
585    }
586    return r;
587}
588
589
590// ----------------------------------------------------------------------------
591//  FUNCTION : uint64_to_double
592//
593//  Platform independent conversion from double uint64 to double.
594//  Needed because VC++6 doesn't support this conversion.
595// ----------------------------------------------------------------------------
596
597inline double
598uint64_to_double(uint64 a)
599{
600#if defined(__clang__)
601    // conversion from uint64 to double not implemented; use int64
602    double tmp = static_cast<double>(static_cast<int64>(a));
603    return (tmp >= 0) ? tmp : tmp + sc_dt::scfx_pow2(64);
604#else
605    return static_cast<double>(a);
606#endif
607}
608
609} // namespace sc_dt
610
611#undef SCFX_MASK_
612
613#endif // __SYSTEMC_EXT_DT_FX_SCFX_IEEE_HH__
614