sc_fxnum.cc revision 12854
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  sc_fxnum.cpp -
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
39// $Log: sc_fxnum.cpp,v $
40// Revision 1.3  2011/01/19 18:57:40  acg
41//  Andy Goodrich: changes for IEEE_1666_2011.
42//
43// Revision 1.2  2010/12/07 20:09:08  acg
44// Andy Goodrich: Philipp Hartmann's constructor disambiguation fix
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:57  acg
50// Andy Goodrich: added $Log command so that CVS comments are reproduced in
51// the source.
52//
53
54#include <cmath>
55
56#include "systemc/ext/dt/fx/sc_fxnum.hh"
57
58namespace sc_dt
59{
60
61// ----------------------------------------------------------------------------
62//  CLASS : sc_fxnum_bitref
63//
64//  Proxy class for bit-selection in class sc_fxnum, behaves like sc_bit.
65// ----------------------------------------------------------------------------
66
67bool sc_fxnum_bitref::get() const { return m_num.get_bit(m_idx); }
68void sc_fxnum_bitref::set(bool high) { m_num.set_bit(m_idx, high); }
69
70// print or dump content
71void sc_fxnum_bitref::print(::std::ostream &os) const { os << get(); }
72
73void
74sc_fxnum_bitref::scan(::std::istream &is)
75{
76    bool b;
77    is >> b;
78    *this = b;
79}
80
81void
82sc_fxnum_bitref::dump(::std::ostream &os) const
83{
84    os << "sc_fxnum_bitref" << ::std::endl;
85    os << "(" << ::std::endl;
86    os << "num = ";
87    m_num.dump(os);
88    os << "idx = " << m_idx << ::std::endl;
89    os << ")" << ::std::endl;
90}
91
92
93// ----------------------------------------------------------------------------
94//  CLASS : sc_fxnum_fast_bitref
95//
96//  Proxy class for bit-selection in class sc_fxnum_fast, behaves like sc_bit.
97// ----------------------------------------------------------------------------
98
99bool sc_fxnum_fast_bitref::get() const { return m_num.get_bit(m_idx); }
100void sc_fxnum_fast_bitref::set(bool high) { m_num.set_bit(m_idx, high); }
101
102// print or dump content
103void sc_fxnum_fast_bitref::print(::std::ostream &os) const { os << get(); }
104
105void
106sc_fxnum_fast_bitref::scan(::std::istream &is)
107{
108    bool b;
109    is >> b;
110    *this = b;
111}
112
113void
114sc_fxnum_fast_bitref::dump(::std::ostream &os) const
115{
116    os << "sc_fxnum_fast_bitref" << ::std::endl;
117    os << "(" << ::std::endl;
118    os << "num = ";
119    m_num.dump(os);
120    os << "idx = " << m_idx << ::std::endl;
121    os << ")" << ::std::endl;
122}
123
124// ----------------------------------------------------------------------------
125//  CLASS : sc_fxnum_subref
126//
127//  Proxy class for part-selection in class sc_fxnum,
128//  behaves like sc_bv_base.
129// ----------------------------------------------------------------------------
130
131bool
132sc_fxnum_subref::get() const
133{
134    return m_num.get_slice(m_from, m_to, m_bv);
135}
136
137bool
138sc_fxnum_subref::set()
139{
140    return m_num.set_slice(m_from, m_to, m_bv);
141}
142
143// print or dump content
144void
145sc_fxnum_subref::print(::std::ostream &os) const
146{
147    get();
148    m_bv.print(os);
149}
150
151void
152sc_fxnum_subref::scan(::std::istream &is)
153{
154    m_bv.scan(is);
155    set();
156}
157
158void
159sc_fxnum_subref::dump(::std::ostream &os) const
160{
161    os << "sc_fxnum_subref" << ::std::endl;
162    os << "(" << ::std::endl;
163    os << "num  = ";
164    m_num.dump(os);
165    os << "from = " << m_from << ::std::endl;
166    os << "to   = " << m_to << ::std::endl;
167    os << ")" << ::std::endl;
168}
169
170
171// ----------------------------------------------------------------------------
172//  CLASS : sc_fxnum_fast_subref
173//
174//  Proxy class for part-selection in class sc_fxnum_fast,
175//  behaves like sc_bv_base.
176// ----------------------------------------------------------------------------
177
178bool
179sc_fxnum_fast_subref::get() const
180{
181    return m_num.get_slice(m_from, m_to, m_bv);
182}
183
184bool
185sc_fxnum_fast_subref::set()
186{
187    return m_num.set_slice(m_from, m_to, m_bv);
188}
189
190// print or dump content
191void
192sc_fxnum_fast_subref::print(::std::ostream &os) const
193{
194    get();
195    m_bv.print(os);
196}
197
198void
199sc_fxnum_fast_subref::scan(::std::istream &is)
200{
201    m_bv.scan(is);
202    set();
203}
204
205void
206sc_fxnum_fast_subref::dump(::std::ostream &os) const
207{
208    os << "sc_fxnum_fast_subref" << ::std::endl;
209    os << "(" << ::std::endl;
210    os << "num  = ";
211    m_num.dump(os);
212    os << "from = " << m_from << ::std::endl;
213    os << "to   = " << m_to << ::std::endl;
214    os << ")" << ::std::endl;
215}
216
217
218// ----------------------------------------------------------------------------
219//  CLASS : sc_fxnum
220//
221//  Base class for the fixed-point types; arbitrary precision.
222// ----------------------------------------------------------------------------
223
224// explicit conversion to character string
225
226const std::string
227sc_fxnum::to_string() const
228{
229    return std::string(m_rep->to_string(SC_DEC, -1, SC_F, &m_params));
230}
231
232const std::string
233sc_fxnum::to_string(sc_numrep numrep) const
234{
235    return std::string(m_rep->to_string(numrep, -1, SC_F, &m_params));
236}
237
238const std::string
239sc_fxnum::to_string(sc_numrep numrep, bool w_prefix) const
240{
241    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0),
242                                        SC_F, &m_params));
243}
244
245const std::string
246sc_fxnum::to_string(sc_fmt fmt) const
247{
248    return std::string(m_rep->to_string(SC_DEC, -1, fmt, &m_params));
249}
250
251const std::string
252sc_fxnum::to_string(sc_numrep numrep, sc_fmt fmt) const
253{
254    return std::string(m_rep->to_string(numrep, -1, fmt, &m_params));
255}
256
257const std::string
258sc_fxnum::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
259{
260    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0),
261                                        fmt, &m_params));
262}
263
264
265const std::string
266sc_fxnum::to_dec() const
267{
268    return std::string(m_rep->to_string(SC_DEC, -1, SC_F, &m_params));
269}
270
271const std::string
272sc_fxnum::to_bin() const
273{
274    return std::string(m_rep->to_string(SC_BIN, -1, SC_F, &m_params));
275}
276
277const std::string
278sc_fxnum::to_oct() const
279{
280    return std::string(m_rep->to_string(SC_OCT, -1, SC_F, &m_params));
281}
282
283const std::string
284sc_fxnum::to_hex() const
285{
286    return std::string(m_rep->to_string(SC_HEX, -1, SC_F, &m_params));
287}
288
289
290// print or dump content
291void
292sc_fxnum::print(::std::ostream &os) const
293{
294    os << m_rep->to_string(SC_DEC, -1, SC_F, &m_params);
295}
296
297void
298sc_fxnum::scan(::std::istream &is)
299{
300    std::string s;
301    is >> s;
302    *this = s.c_str();
303}
304
305void
306sc_fxnum::dump(::std::ostream &os) const
307{
308    os << "sc_fxnum" << ::std::endl;
309    os << "(" << ::std::endl;
310    os << "rep      = ";
311    m_rep->dump(os);
312    os << "params   = ";
313    m_params.dump(os);
314    os << "q_flag   = " << m_q_flag << ::std::endl;
315    os << "o_flag   = " << m_o_flag << ::std::endl;
316    // TO BE COMPLETED
317    // os << "observer = ";
318    // if (m_observer != 0)
319    //     m_observer->dump(os);
320    // else
321    //     os << "0" << ::std::endl;
322    os << ")" << ::std::endl;
323}
324
325
326sc_fxnum_observer *
327sc_fxnum::lock_observer() const
328{
329    SC_ASSERT_(m_observer != 0, "lock observer failed");
330    sc_fxnum_observer * tmp = m_observer;
331    m_observer = 0;
332    return tmp;
333}
334
335void
336sc_fxnum::unlock_observer(sc_fxnum_observer *observer_) const
337{
338    SC_ASSERT_(observer_ != 0, "unlock observer failed");
339    m_observer = observer_;
340}
341
342
343// ----------------------------------------------------------------------------
344//  CLASS : sc_fxnum_fast
345//
346//  Base class for the fixed-point types; limited precision.
347// ----------------------------------------------------------------------------
348
349static void
350quantization(double &c, const scfx_params &params, bool &q_flag)
351{
352    int fwl = params.wl() - params.iwl();
353    double scale = scfx_pow2(fwl);
354    double val = scale * c;
355    double int_part;
356    double frac_part = modf(val, &int_part);
357
358    q_flag = (frac_part != 0.0);
359
360    if (q_flag) {
361        val = int_part;
362
363        switch (params.q_mode()) {
364          case SC_TRN: // truncation
365            {
366                if (c < 0.0)
367                    val -= 1.0;
368                break;
369            }
370          case SC_RND: // rounding to plus infinity
371            {
372                if (frac_part >= 0.5)
373                    val += 1.0;
374                else if (frac_part < -0.5)
375                    val -= 1.0;
376                break;
377            }
378          case SC_TRN_ZERO: // truncation to zero
379            {
380                break;
381            }
382          case SC_RND_INF: // rounding to infinity
383            {
384                if (frac_part >= 0.5)
385                    val += 1.0;
386                else if (frac_part <= -0.5)
387                    val -= 1.0;
388                break;
389            }
390          case SC_RND_CONV: // convergent rounding
391            {
392                if (frac_part > 0.5 ||
393                    (frac_part == 0.5 && fmod(int_part, 2.0) != 0.0)) {
394                    val += 1.0;
395                } else if (frac_part < -0.5 ||
396                           (frac_part == -0.5 && fmod(int_part, 2.0) != 0.0)) {
397                    val -= 1.0;
398                }
399                break;
400            }
401          case SC_RND_ZERO: // rounding to zero
402            {
403                if (frac_part > 0.5)
404                    val += 1.0;
405                else if (frac_part < -0.5)
406                    val -= 1.0;
407                break;
408            }
409          case SC_RND_MIN_INF: // rounding to minus infinity
410            {
411                if (frac_part > 0.5)
412                    val += 1.0;
413                else if (frac_part <= -0.5)
414                    val -= 1.0;
415                break;
416            }
417          default:
418            ;
419        }
420    }
421
422    val /= scale;
423    c = val;
424}
425
426static void
427overflow(double &c, const scfx_params &params, bool &o_flag)
428{
429    int iwl = params.iwl();
430    int fwl = params.wl() - iwl;
431    double full_circle = scfx_pow2(iwl);
432    double resolution = scfx_pow2(-fwl);
433    double low, high;
434    if (params.enc() == SC_TC_) {
435        high = full_circle / 2.0 - resolution;
436        if (params.o_mode() == SC_SAT_SYM)
437            low = - high;
438        else
439            low = - full_circle / 2.0;
440    } else {
441        low = 0.0;
442        high = full_circle - resolution;
443    }
444    double val = c;
445    sc_fxval_fast c2(c);
446
447    bool under = (val < low);
448    bool over = (val > high);
449
450    o_flag = (under || over);
451
452    if (o_flag) {
453        switch (params.o_mode()) {
454          case SC_WRAP: // wrap-around
455            {
456                int n_bits = params.n_bits();
457
458                if (n_bits == 0) {
459                    // wrap-around all 'wl' bits
460                    val -= floor(val / full_circle) * full_circle;
461                    if (val > high)
462                        val -= full_circle;
463                } else if (n_bits < params.wl()) {
464                    double X = scfx_pow2(iwl - n_bits);
465
466                    // wrap-around least significant 'wl - n_bits' bits
467                    val -= floor(val / X) * X;
468                    if (val > (X - resolution))
469                        val -= X;
470
471                    // saturate most significant 'n_bits' bits
472                    if (under) {
473                        val += low;
474                    } else {
475                        if (params.enc() == SC_TC_)
476                            val += full_circle / 2.0 - X;
477                        else
478                            val += full_circle - X;
479                    }
480                } else {
481                    // saturate all 'wl' bits
482                    if (under)
483                        val = low;
484                    else
485                        val = high;
486                }
487                break;
488            }
489          case SC_SAT: // saturation
490          case SC_SAT_SYM: // symmetrical saturation
491            {
492                if (under)
493                    val = low;
494                else
495                    val = high;
496                break;
497            }
498          case SC_SAT_ZERO: // saturation to zero
499            {
500                val = 0.0;
501                break;
502            }
503          case SC_WRAP_SM: // sign magnitude wrap-around
504            {
505                SC_ERROR_IF_(params.enc() == SC_US_,
506                             "SC_WRAP_SM not defined for unsigned numbers");
507
508                int n_bits = params.n_bits();
509
510                if (n_bits == 0) {
511                    // invert conditionally
512                    if (c2.get_bit(iwl) != c2.get_bit(iwl - 1))
513                        val = -val - resolution;
514
515                    // wrap-around all 'wl' bits
516                    val -= floor(val / full_circle) * full_circle;
517                    if (val > high)
518                        val -= full_circle;
519                } else if (n_bits == 1) {
520                    // invert conditionally
521                    if (c2.is_neg() != c2.get_bit(iwl - 1))
522                        val = -val - resolution;
523
524                    // wrap-around all 'wl' bits
525                    val -= floor(val / full_circle) * full_circle;
526                    if (val > high)
527                        val -= full_circle;
528                } else if (n_bits < params.wl()) {
529                    // invert conditionally
530                    if (c2.is_neg() == c2.get_bit(iwl - n_bits))
531                        val = -val - resolution;
532
533                    double X = scfx_pow2(iwl - n_bits);
534
535                    // wrap-around least significant 'wl - n_bits' bits
536                    val -= floor(val / X) * X;
537                    if (val > (X - resolution))
538                        val -= X;
539
540                    // saturate most significant 'n_bits' bits
541                    if (under)
542                        val += low;
543                    else
544                        val += full_circle / 2.0 - X;
545                } else {
546                    // saturate all 'wl' bits
547                    if (under)
548                        val = low;
549                    else
550                        val = high;
551                }
552                break;
553            }
554            default:
555                ;
556        }
557
558        c = val;
559    }
560}
561
562
563void
564sc_fxnum_fast::cast()
565{
566    scfx_ieee_double id(m_val);
567    SC_ERROR_IF_(id.is_nan() || id.is_inf(), "invalid fixed-point value");
568
569    if (m_params.cast_switch() == SC_ON) {
570        m_q_flag = false;
571        m_o_flag = false;
572
573        // check for special cases
574
575        if (id.is_zero()) {
576            if (id.negative() != 0)
577                m_val = -m_val;
578            return;
579        }
580
581        // perform casting
582        sc_dt::quantization(m_val, m_params, m_q_flag);
583        sc_dt::overflow(m_val, m_params, m_o_flag);
584
585        // check for special case: -0
586        id = m_val;
587        if (id.is_zero() && id.negative() != 0) {
588            m_val = -m_val;
589        }
590
591        // check for special case: NaN of Inf
592        if (id.is_nan() || id.is_inf()) {
593            m_val = 0.0;
594        }
595    }
596}
597
598
599// defined in sc_fxval.cpp;
600extern const char* to_string(const scfx_ieee_double &, sc_numrep, int, sc_fmt,
601                             const scfx_params * =0);
602
603
604// explicit conversion to character string
605
606const std::string
607sc_fxnum_fast::to_string() const
608{
609    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params));
610}
611
612const std::string
613sc_fxnum_fast::to_string(sc_numrep numrep) const
614{
615    return std::string(sc_dt::to_string(m_val, numrep, -1, SC_F, &m_params));
616}
617
618const std::string
619sc_fxnum_fast::to_string(sc_numrep numrep, bool w_prefix) const
620{
621    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
622                                        SC_F, &m_params));
623}
624
625const std::string
626sc_fxnum_fast::to_string(sc_fmt fmt) const
627{
628    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt, &m_params));
629}
630
631const std::string
632sc_fxnum_fast::to_string(sc_numrep numrep, sc_fmt fmt) const
633{
634    return std::string(sc_dt::to_string(m_val, numrep, -1, fmt, &m_params));
635}
636
637const std::string
638sc_fxnum_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
639{
640    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
641                                        fmt, &m_params));
642}
643
644
645const std::string
646sc_fxnum_fast::to_dec() const
647{
648    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params));
649}
650
651const std::string
652sc_fxnum_fast::to_bin() const
653{
654    return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_F, &m_params));
655}
656
657const std::string
658sc_fxnum_fast::to_oct() const
659{
660    return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_F, &m_params));
661}
662
663const std::string
664sc_fxnum_fast::to_hex() const
665{
666    return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_F, &m_params));
667}
668
669// print or dump content
670void
671sc_fxnum_fast::print(::std::ostream &os) const
672{
673    os << sc_dt::to_string(m_val, SC_DEC, -1, SC_F, &m_params);
674}
675
676void
677sc_fxnum_fast::scan(::std::istream &is)
678{
679    std::string s;
680    is >> s;
681    *this = s.c_str();
682}
683
684void
685sc_fxnum_fast::dump(::std::ostream &os) const
686{
687    os << "sc_fxnum_fast" << ::std::endl;
688    os << "(" << ::std::endl;
689    os << "val      = " << m_val << ::std::endl;
690    os << "params   = ";
691    m_params.dump(os);
692    os << "q_flag   = " << m_q_flag << ::std::endl;
693    os << "o_flag   = " << m_o_flag << ::std::endl;
694    // TO BE COMPLETED
695    // os << "observer = ";
696    // if (m_observer != 0)
697    //     m_observer->dump(os);
698    // else
699    //     os << "0" << ::std::endl;
700    os << ")" << ::std::endl;
701}
702
703// internal use only;
704bool
705sc_fxnum_fast::get_bit(int i) const
706{
707    scfx_ieee_double id(m_val);
708    if (id.is_zero() || id.is_nan() || id.is_inf())
709        return false;
710
711    // convert to two's complement
712    unsigned int m0 = id.mantissa0();
713    unsigned int m1 = id.mantissa1();
714
715    if (id.is_normal())
716        m0 += 1U << 20;
717
718    if (id.negative() != 0) {
719        m0 = ~ m0;
720        m1 = ~ m1;
721        unsigned int tmp = m1;
722        m1 += 1U;
723        if (m1 <= tmp)
724            m0 += 1U;
725    }
726
727    // get the right bit
728    int j = i - id.exponent();
729    if ((j += 20) >= 32)
730        return ((m0 & 1U << 31) != 0);
731    else if (j >= 0)
732        return ((m0 & 1U << j) != 0);
733    else if ((j += 32) >= 0)
734        return ((m1 & 1U << j) != 0);
735    else
736        return false;
737}
738
739
740bool
741sc_fxnum_fast::set_bit(int i, bool high)
742{
743    scfx_ieee_double id(m_val);
744    if (id.is_nan() || id.is_inf())
745        return false;
746
747    if (high) {
748        if (get_bit(i))
749            return true;
750
751        if (m_params.enc() == SC_TC_ && i == m_params.iwl() - 1)
752            m_val -= scfx_pow2(i);
753        else
754            m_val += scfx_pow2(i);
755    } else {
756        if (!get_bit(i))
757            return true;
758
759        if (m_params.enc() == SC_TC_ && i == m_params.iwl() - 1)
760            m_val += scfx_pow2(i);
761        else
762            m_val -= scfx_pow2(i);
763    }
764
765    return true;
766}
767
768
769bool
770sc_fxnum_fast::get_slice(int i, int j, sc_bv_base &bv) const
771{
772    scfx_ieee_double id(m_val);
773    if (id.is_nan() || id.is_inf())
774        return false;
775
776    // convert to two's complement
777    unsigned int m0 = id.mantissa0();
778    unsigned int m1 = id.mantissa1();
779
780    if (id.is_normal())
781        m0 += 1U << 20;
782
783    if (id.negative() != 0) {
784        m0 = ~ m0;
785        m1 = ~ m1;
786        unsigned int tmp = m1;
787        m1 += 1U;
788        if (m1 <= tmp)
789            m0 += 1U;
790    }
791
792    // get the bits
793    int l = j;
794    for (int k = 0; k < bv.length(); ++ k) {
795        bool b = false;
796
797        int n = l - id.exponent();
798        if ((n += 20) >= 32)
799            b = ((m0 & 1U << 31) != 0);
800        else if (n >= 0)
801            b = ((m0 & 1U << n) != 0);
802        else if ((n += 32) >= 0)
803            b = ((m1 & 1U << n) != 0);
804
805        bv[k] = b;
806
807        if (i >= j)
808            ++l;
809        else
810            --l;
811    }
812
813    return true;
814}
815
816bool
817sc_fxnum_fast::set_slice(int i, int j, const sc_bv_base &bv)
818{
819    scfx_ieee_double id(m_val);
820    if (id.is_nan() || id.is_inf())
821        return false;
822
823    // set the bits
824    int l = j;
825    for (int k = 0; k < bv.length(); ++k) {
826        if (bv[k].to_bool()) {
827            if (!get_bit(l)) {
828                if (m_params.enc() == SC_TC_ && l == m_params.iwl() - 1)
829                    m_val -= scfx_pow2(l);
830                else
831                    m_val += scfx_pow2(l);
832            }
833        } else {
834            if (get_bit(l)) {
835                if (m_params.enc() == SC_TC_ && l == m_params.iwl() - 1)
836                    m_val += scfx_pow2(l);
837                else
838                    m_val -= scfx_pow2(l);
839            }
840        }
841
842        if (i >= j)
843            ++l;
844        else
845            --l;
846    }
847
848    return true;
849}
850
851sc_fxnum_fast_observer *
852sc_fxnum_fast::lock_observer() const
853{
854    SC_ASSERT_(m_observer != 0, "lock observer failed");
855    sc_fxnum_fast_observer *tmp = m_observer;
856    m_observer = 0;
857    return tmp;
858}
859
860void
861sc_fxnum_fast::unlock_observer(sc_fxnum_fast_observer *observer_) const
862{
863    SC_ASSERT_(observer_ != 0, "unlock observer failed");
864    m_observer = observer_;
865}
866
867} // namespace sc_dt
868