scfx_ieee.h revision 12027
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 SCFX_IEEE_H
55#define SCFX_IEEE_H
56
57
58#include "sysc/datatypes/fx/sc_fxdefs.h"
59
60
61namespace sc_dt
62{
63
64// classes defined in this module
65union ieee_double;
66class scfx_ieee_double;
67union ieee_float;
68class scfx_ieee_float;
69
70#define SCFX_MASK_(Size) \
71   ((1u << (Size))-1u)
72
73// ----------------------------------------------------------------------------
74//  UNION : ieee_double
75//
76//  IEEE 754 double-precision format.
77// ----------------------------------------------------------------------------
78
79union ieee_double
80{
81
82    double d;
83
84    struct
85    {
86#if defined( SC_BIG_ENDIAN )
87        unsigned negative:1;
88        unsigned exponent:11;
89        unsigned mantissa0:20;
90        unsigned mantissa1:32;
91#elif defined( SC_LITTLE_ENDIAN )
92        unsigned mantissa1:32;
93        unsigned mantissa0:20;
94        unsigned exponent:11;
95        unsigned negative:1;
96#endif
97    } s;
98
99};
100
101
102const unsigned int SCFX_IEEE_DOUBLE_BIAS   =  1023U;
103
104const int          SCFX_IEEE_DOUBLE_E_MAX  =  1023;
105const int          SCFX_IEEE_DOUBLE_E_MIN  = -1022;
106
107const unsigned int SCFX_IEEE_DOUBLE_M_SIZE  =    52;
108const unsigned int SCFX_IEEE_DOUBLE_M0_SIZE =    20;
109const unsigned int SCFX_IEEE_DOUBLE_M1_SIZE =    32;
110const unsigned int SCFX_IEEE_DOUBLE_E_SIZE  =    11;
111
112
113
114// ----------------------------------------------------------------------------
115//  CLASS : scfx_ieee_double
116//
117//  Convenient interface to union ieee_double.
118// ----------------------------------------------------------------------------
119
120class scfx_ieee_double
121{
122
123    ieee_double m_id;
124
125public:
126
127    scfx_ieee_double();
128    scfx_ieee_double( double );
129    scfx_ieee_double( const scfx_ieee_double& );
130
131    scfx_ieee_double& operator = ( double );
132    scfx_ieee_double& operator = ( const scfx_ieee_double& );
133
134    operator double() const;
135
136    unsigned int negative() const;
137    void negative( unsigned int );
138    int exponent() const;
139    void exponent( int );
140    unsigned int mantissa0() const;
141    void mantissa0( unsigned int );
142    unsigned int mantissa1() const;
143    void mantissa1( unsigned int );
144
145    bool is_zero() const;
146    bool is_subnormal() const;
147    bool is_normal() const;
148    bool is_inf() const;
149    bool is_nan() const;
150
151    void set_inf();
152    void set_nan();
153
154    int msb() const;            // most significant non-zero bit
155    int lsb() const;            // least significant non-zero bit
156
157    static const scfx_ieee_double nan();
158    static const scfx_ieee_double inf( int );
159
160};
161
162
163// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
164
165inline
166scfx_ieee_double::scfx_ieee_double() : m_id()
167{
168    m_id.d = 0.0;
169}
170
171inline
172scfx_ieee_double::scfx_ieee_double( double d ) : m_id()
173{
174    m_id.d = d;
175}
176
177inline
178scfx_ieee_double::scfx_ieee_double( const scfx_ieee_double& a ) : m_id(a.m_id)
179{
180    // m_id.d = a.m_id.d;
181}
182
183
184inline
185scfx_ieee_double&
186scfx_ieee_double::operator = ( double d )
187{
188    m_id.d = d;
189    return *this;
190}
191
192inline
193scfx_ieee_double&
194scfx_ieee_double::operator = ( const scfx_ieee_double& a )
195{
196    m_id.d = a.m_id.d;
197    return *this;
198}
199
200
201inline
202scfx_ieee_double::operator double() const
203{
204    return m_id.d;
205}
206
207
208inline
209unsigned int
210scfx_ieee_double::negative() const
211{
212    return m_id.s.negative;
213}
214
215inline
216void
217scfx_ieee_double::negative( unsigned int a )
218{
219    m_id.s.negative = a & SCFX_MASK_(1);
220}
221
222inline
223int
224scfx_ieee_double::exponent() const
225{
226    return m_id.s.exponent - SCFX_IEEE_DOUBLE_BIAS;
227}
228
229inline
230void
231scfx_ieee_double::exponent( int a )
232{
233    m_id.s.exponent = (SCFX_IEEE_DOUBLE_BIAS + a)
234                      & SCFX_MASK_(SCFX_IEEE_DOUBLE_E_SIZE);
235}
236
237inline
238unsigned int
239scfx_ieee_double::mantissa0() const
240{
241    return m_id.s.mantissa0;
242}
243
244inline
245void
246scfx_ieee_double::mantissa0( unsigned int a )
247{
248    m_id.s.mantissa0 = a & SCFX_MASK_(SCFX_IEEE_DOUBLE_M0_SIZE);
249}
250
251inline
252unsigned int
253scfx_ieee_double::mantissa1() const
254{
255    return m_id.s.mantissa1;
256}
257
258inline
259void
260scfx_ieee_double::mantissa1( unsigned int a )
261{
262    m_id.s.mantissa1 = a; // & SCFX_MASK_(SCFX_IEEE_DOUBLE_M1_SIZE);
263}
264
265
266inline
267bool
268scfx_ieee_double::is_zero() const
269{
270    return ( exponent() == SCFX_IEEE_DOUBLE_E_MIN - 1 &&
271             mantissa0() == 0U && mantissa1() == 0U );
272}
273
274inline
275bool
276scfx_ieee_double::is_subnormal() const
277{
278    return ( exponent() == SCFX_IEEE_DOUBLE_E_MIN - 1 &&
279             ( mantissa0() != 0U || mantissa1() != 0U ) );
280}
281
282inline
283bool
284scfx_ieee_double::is_normal() const
285{
286    return ( exponent() >= SCFX_IEEE_DOUBLE_E_MIN &&
287             exponent() <= SCFX_IEEE_DOUBLE_E_MAX );
288}
289
290inline
291bool
292scfx_ieee_double::is_inf() const
293{
294    return ( exponent() == SCFX_IEEE_DOUBLE_E_MAX + 1 &&
295             mantissa0() == 0U && mantissa1() == 0U );
296}
297
298inline
299bool
300scfx_ieee_double::is_nan() const
301{
302    return ( exponent() == SCFX_IEEE_DOUBLE_E_MAX + 1 &&
303             ( mantissa0() != 0U || mantissa1() != 0U ) );
304}
305
306
307inline
308void
309scfx_ieee_double::set_inf()
310{
311    exponent( SCFX_IEEE_DOUBLE_E_MAX + 1 );
312    mantissa0( 0U );
313    mantissa1( 0U );
314}
315
316inline
317void
318scfx_ieee_double::set_nan()
319{
320    exponent( SCFX_IEEE_DOUBLE_E_MAX + 1 );
321    mantissa0( (unsigned int) -1 );
322    mantissa1( (unsigned int) -1 );
323}
324
325
326#define MSB_STATEMENT(x,n) if( x >> n ) { x >>= n; i += n; }
327
328inline
329int
330scfx_ieee_double::msb() const
331{
332    unsigned int m0 = mantissa0();
333    unsigned int m1 = mantissa1();
334    if( m0 != 0 )
335    {
336        int i = 0;
337        MSB_STATEMENT(m0,16);
338        MSB_STATEMENT(m0,8);
339        MSB_STATEMENT(m0,4);
340        MSB_STATEMENT(m0,2);
341        MSB_STATEMENT(m0,1);
342        return ( i - 20 );
343    }
344    else if( m1 != 0 )
345    {
346        int i = 0;
347        MSB_STATEMENT(m1,16);
348        MSB_STATEMENT(m1,8);
349        MSB_STATEMENT(m1,4);
350        MSB_STATEMENT(m1,2);
351        MSB_STATEMENT(m1,1);
352        return ( i - 52 );
353    }
354    else
355    {
356        return 0;
357    }
358}
359
360#undef MSB_STATEMENT
361
362#define LSB_STATEMENT(x,n) if( x << n ) { x <<= n; i -= n; }
363
364inline
365int
366scfx_ieee_double::lsb() const
367{
368    unsigned int m0 = mantissa0();
369    unsigned int m1 = mantissa1();
370    if( m1 != 0 )
371    {
372        int i = 31;
373        LSB_STATEMENT(m1,16);
374        LSB_STATEMENT(m1,8);
375        LSB_STATEMENT(m1,4);
376        LSB_STATEMENT(m1,2);
377        LSB_STATEMENT(m1,1);
378        return ( i - 52 );
379    }
380    else if( m0 != 0 )
381    {
382        int i = 31;
383        LSB_STATEMENT(m0,16);
384        LSB_STATEMENT(m0,8);
385        LSB_STATEMENT(m0,4);
386        LSB_STATEMENT(m0,2);
387        LSB_STATEMENT(m0,1);
388        return ( i - 20 );
389    }
390    else
391    {
392        return 0;
393    }
394}
395
396#undef LSB_STATEMENT
397
398
399inline
400const scfx_ieee_double
401scfx_ieee_double::nan()
402{
403    scfx_ieee_double id;
404    id.set_nan();
405    return id;
406}
407
408inline
409const scfx_ieee_double
410scfx_ieee_double::inf( int sign )
411{
412    scfx_ieee_double id( sign );
413    id.set_inf();
414    return id;
415}
416
417
418// ----------------------------------------------------------------------------
419//  UNION : ieee_float
420//
421//  IEEE 754 single-precision format.
422// ----------------------------------------------------------------------------
423
424union ieee_float
425{
426
427    float f;
428
429    struct
430    {
431#if defined( SC_BIG_ENDIAN )
432        unsigned negative:1;
433        unsigned exponent:8;
434        unsigned mantissa:23;
435#elif defined( SC_LITTLE_ENDIAN )
436        unsigned mantissa:23;
437        unsigned exponent:8;
438        unsigned negative:1;
439#endif
440    } s;
441
442};
443
444
445const unsigned int SCFX_IEEE_FLOAT_BIAS   =  127U;
446
447const int          SCFX_IEEE_FLOAT_E_MAX  =  127;
448const int          SCFX_IEEE_FLOAT_E_MIN  = -126;
449
450const unsigned int SCFX_IEEE_FLOAT_M_SIZE =   23;
451const unsigned int SCFX_IEEE_FLOAT_E_SIZE =    8;
452
453
454// ----------------------------------------------------------------------------
455//  CLASS : scfx_ieee_float
456//
457// Convenient wrapper to union ieee_float.
458// ----------------------------------------------------------------------------
459
460class scfx_ieee_float
461{
462
463    ieee_float m_if;
464
465public:
466
467    scfx_ieee_float();
468    scfx_ieee_float( float );
469    scfx_ieee_float( const scfx_ieee_float& );
470
471    scfx_ieee_float& operator = ( float );
472    scfx_ieee_float& operator = ( const scfx_ieee_float& );
473
474    operator float() const;
475
476    unsigned int negative() const;
477    void negative( unsigned int );
478    int exponent() const;
479    void exponent( int );
480    unsigned int mantissa() const;
481    void mantissa( unsigned int );
482
483    bool is_zero() const;
484    bool is_subnormal() const;
485    bool is_normal() const;
486    bool is_inf() const;
487    bool is_nan() const;
488
489    void set_inf();
490    void set_nan();
491
492};
493
494
495// IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
496
497inline
498scfx_ieee_float::scfx_ieee_float() : m_if()
499{
500    m_if.f = 0.0;
501}
502
503inline
504scfx_ieee_float::scfx_ieee_float( float f ) : m_if()
505{
506    m_if.f = f;
507}
508
509inline
510scfx_ieee_float::scfx_ieee_float( const scfx_ieee_float& a ) : m_if(a.m_if)
511{
512    // m_if.f = a.m_if.f;
513}
514
515
516inline
517scfx_ieee_float&
518scfx_ieee_float::operator = ( float f )
519{
520    m_if.f = f;
521    return *this;
522}
523
524inline
525scfx_ieee_float&
526scfx_ieee_float::operator = ( const scfx_ieee_float& a )
527{
528    m_if.f = a.m_if.f;
529    return *this;
530}
531
532
533inline
534scfx_ieee_float::operator float() const
535{
536    return m_if.f;
537}
538
539
540inline
541unsigned int
542scfx_ieee_float::negative() const
543{
544    return m_if.s.negative;
545}
546
547inline
548void
549scfx_ieee_float::negative( unsigned int a )
550{
551    m_if.s.negative = a & SCFX_MASK_(1);
552}
553
554inline
555int
556scfx_ieee_float::exponent() const
557{
558    return m_if.s.exponent - SCFX_IEEE_FLOAT_BIAS;
559}
560
561inline
562void
563scfx_ieee_float::exponent( int a )
564{
565    m_if.s.exponent = (SCFX_IEEE_FLOAT_BIAS + a)
566                      & SCFX_MASK_(SCFX_IEEE_FLOAT_E_SIZE);
567}
568
569inline
570unsigned int
571scfx_ieee_float::mantissa() const
572{
573    return m_if.s.mantissa;
574}
575
576inline
577void
578scfx_ieee_float::mantissa( unsigned int a )
579{
580    m_if.s.mantissa = a & SCFX_MASK_(SCFX_IEEE_FLOAT_M_SIZE);
581}
582
583
584inline
585bool
586scfx_ieee_float::is_zero() const
587{
588    return ( exponent() == SCFX_IEEE_FLOAT_E_MIN - 1 && mantissa() == 0U );
589}
590
591inline
592bool
593scfx_ieee_float::is_subnormal() const
594{
595    return ( exponent() == SCFX_IEEE_FLOAT_E_MIN - 1 && mantissa() != 0U );
596}
597
598inline
599bool
600scfx_ieee_float::is_normal() const
601{
602    return ( exponent() >= SCFX_IEEE_FLOAT_E_MIN &&
603             exponent() <= SCFX_IEEE_FLOAT_E_MAX );
604}
605
606inline
607bool
608scfx_ieee_float::is_inf() const
609{
610    return ( exponent() == SCFX_IEEE_FLOAT_E_MAX + 1 && mantissa() == 0U );
611}
612
613inline
614bool
615scfx_ieee_float::is_nan() const
616{
617    return ( exponent() == SCFX_IEEE_FLOAT_E_MAX + 1 && mantissa() != 0U );
618}
619
620
621inline
622void
623scfx_ieee_float::set_inf()
624{
625    exponent( SCFX_IEEE_FLOAT_E_MAX + 1 );
626    mantissa( 0U );
627}
628
629inline
630void
631scfx_ieee_float::set_nan()
632{
633    exponent( SCFX_IEEE_FLOAT_E_MAX + 1 );
634    mantissa( (unsigned int) -1 );
635}
636
637
638// ----------------------------------------------------------------------------
639//  FUNCTION : scfx_pow2
640//
641//  Computes 2.0**exp in double-precision.
642// ----------------------------------------------------------------------------
643
644inline
645double scfx_pow2( int exp )
646{
647    scfx_ieee_double r;
648    if( exp < SCFX_IEEE_DOUBLE_E_MIN )
649    {
650        r = 0.0;
651        // handle subnormal case
652        exp -= SCFX_IEEE_DOUBLE_E_MIN;
653        if( ( exp += 20 ) >= 0 )
654	{
655            r.mantissa0( 1U << exp );
656        }
657	else if( ( exp += 32 ) >= 0 )
658	{
659            r.mantissa1( 1U << exp );
660        }
661    }
662    else if( exp > SCFX_IEEE_DOUBLE_E_MAX )
663    {
664        r.set_inf();
665    }
666    else
667    {
668        r = 1.0;
669        r.exponent( exp );
670    }
671    return r;
672}
673
674
675// ----------------------------------------------------------------------------
676//  FUNCTION : uint64_to_double
677//
678//  Platform independent conversion from double uint64 to double.
679//  Needed because VC++6 doesn't support this conversion.
680// ----------------------------------------------------------------------------
681
682inline
683double
684uint64_to_double( uint64 a )
685{
686#if defined( _MSC_VER ) || defined( __clang__ )
687    // conversion from uint64 to double not implemented; use int64
688    double tmp = static_cast<double>( static_cast<int64>( a ) );
689    return ( tmp >= 0 ) ? tmp : tmp + sc_dt::scfx_pow2( 64 );
690#else
691    return static_cast<double>( a );
692#endif
693}
694
695} // namespace sc_dt
696
697#undef SCFX_MASK_
698
699#endif
700
701// Taf!
702