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