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_fxval.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_fxval.cpp,v $
40// Revision 1.1.1.1  2006/12/15 20:20:04  acg
41// SystemC 2.3
42//
43// Revision 1.3  2006/01/13 18:53:58  acg
44// Andy Goodrich: added $Log command so that CVS comments are reproduced in
45// the source.
46//
47
48#include <cctype>
49#include <cfloat>
50#include <cmath>
51#include <cstdlib>
52
53#include "systemc/ext/dt/fx/sc_fxval.hh"
54#include "systemc/ext/utils/messages.hh"
55
56namespace sc_dt
57{
58
59// ----------------------------------------------------------------------------
60//  CLASS : sc_fxval
61//
62//  Fixed-point value type; arbitrary precision.
63// ----------------------------------------------------------------------------
64
65// explicit conversion to character string
66
67const std::string
68sc_fxval::to_string() const
69{
70    return std::string(m_rep->to_string(SC_DEC, -1, SC_E));
71}
72
73const std::string
74sc_fxval::to_string(sc_numrep numrep) const
75{
76    return std::string(m_rep->to_string(numrep, -1, SC_E));
77}
78
79const std::string
80sc_fxval::to_string(sc_numrep numrep, bool w_prefix) const
81{
82    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), SC_E));
83}
84
85const std::string
86sc_fxval::to_string(sc_fmt fmt) const
87{
88    return std::string(m_rep->to_string(SC_DEC, -1, fmt));
89}
90
91const std::string
92sc_fxval::to_string(sc_numrep numrep, sc_fmt fmt) const
93{
94    return std::string(m_rep->to_string(numrep, -1, fmt));
95}
96
97const std::string
98sc_fxval::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
99{
100    return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), fmt));
101}
102
103
104const std::string
105sc_fxval::to_dec() const
106{
107    return std::string(m_rep->to_string(SC_DEC, -1, SC_E));
108}
109
110const std::string
111sc_fxval::to_bin() const
112{
113    return std::string(m_rep->to_string(SC_BIN, -1, SC_E));
114}
115
116const std::string
117sc_fxval::to_oct() const
118{
119    return std::string(m_rep->to_string(SC_OCT, -1, SC_E));
120}
121
122const std::string
123sc_fxval::to_hex() const
124{
125    return std::string(m_rep->to_string(SC_HEX, -1, SC_E));
126}
127
128
129// print or dump content
130
131void sc_fxval::print(::std::ostream &os) const { m_rep->print(os); }
132
133void
134sc_fxval::scan(::std::istream &is)
135{
136    std::string s;
137    is >> s;
138    *this = s.c_str();
139}
140
141void
142sc_fxval::dump(::std::ostream &os) const
143{
144    os << "sc_fxval" << ::std::endl;
145    os << "(" << ::std::endl;
146    os << "rep = ";
147    m_rep->dump(os);
148    // TO BE COMPLETED
149    // os << "r_flag   = " << m_r_flag << ::std::endl;
150    // os << "observer = ";
151    // if (m_observer != 0)
152    //     m_observer->dump(os);
153    // else
154    //     os << "0" << ::std::endl;
155    os << ")" << ::std::endl;
156}
157
158// protected methods and friend functions
159sc_fxval_observer *
160sc_fxval::lock_observer() const
161{
162    SC_ASSERT_(m_observer != 0, "lock observer failed");
163    sc_fxval_observer *tmp = m_observer;
164    m_observer = 0;
165    return tmp;
166}
167
168void
169sc_fxval::unlock_observer(sc_fxval_observer *observer_) const
170{
171    SC_ASSERT_(observer_ != 0, "unlock observer failed");
172    m_observer = observer_;
173}
174
175
176// ----------------------------------------------------------------------------
177//  CLASS : sc_fxval_fast
178//
179//  Fixed-point value types; limited precision.
180// ----------------------------------------------------------------------------
181
182static void
183print_dec(scfx_string &s, scfx_ieee_double id, int w_prefix, sc_fmt fmt)
184{
185    if (id.negative() != 0) {
186        id.negative(0);
187        s += '-';
188    }
189
190    if (w_prefix == 1) {
191        scfx_print_prefix(s, SC_DEC);
192    }
193
194    if (id.is_zero()) {
195        s += '0';
196        return;
197    }
198
199    // split 'id' into its integer and fractional part
200    double int_part;
201    double frac_part = std::modf(static_cast<double>(id), &int_part);
202
203    int i;
204
205    // print integer part
206    int int_digits = 0;
207    int int_zeros  = 0;
208
209    if (int_part != 0.0) {
210        int_digits = (int)std::ceil(std::log10(int_part + 1.0));
211
212        int len = s.length();
213        s.append(int_digits);
214
215        bool zero_digits = (frac_part == 0.0 && fmt != SC_F);
216
217        for (i = int_digits + len - 1; i >= len; i--) {
218            unsigned int remainder = (unsigned int)std::fmod(int_part, 10.0);
219            s[i] = static_cast<char>('0' + remainder);
220
221            if (zero_digits) {
222                if (remainder == 0)
223                    int_zeros++;
224                else
225                    zero_digits = false;
226            }
227
228            int_part /= 10.0;
229        }
230
231        // discard trailing zeros from int_part
232        s.discard(int_zeros);
233
234        if (s[len] == '0') {
235            // int_digits was overestimated by one
236            s.remove(len);
237            --int_digits;
238        }
239    }
240
241    // print fractional part
242    int frac_digits = 0;
243    int frac_zeros  = 0;
244
245    if (frac_part != 0.0) {
246        s += '.';
247
248        bool zero_digits = (int_digits == 0 && fmt != SC_F);
249
250        frac_zeros = (int)std::floor(-std::log10(frac_part + DBL_EPSILON));
251
252        frac_part *= std::pow(10.0, frac_zeros);
253
254        frac_digits = frac_zeros;
255        if (!zero_digits) {
256            for (i = 0; i < frac_zeros; i++)
257                s += '0';
258            frac_zeros = 0;
259        }
260
261        while (frac_part != 0.0) {
262            frac_part *= 10.0;
263            int n = static_cast<int>(frac_part);
264
265            if (zero_digits) {
266                if (n == 0)
267                    frac_zeros++;
268                else
269                    zero_digits = false;
270            }
271
272            if (!zero_digits)
273                s += static_cast<char>('0' + n);
274
275            frac_part -= n;
276            frac_digits++;
277        }
278    }
279
280    // print exponent
281    if (fmt != SC_F) {
282        if (frac_digits == 0)
283            scfx_print_exp(s, int_zeros);
284        else if (int_digits == 0)
285            scfx_print_exp(s, -frac_zeros);
286    }
287}
288
289static void
290print_other(scfx_string &s, const scfx_ieee_double &id, sc_numrep numrep,
291             int w_prefix, sc_fmt fmt, const scfx_params *params)
292{
293    scfx_ieee_double id2 = id;
294
295    sc_numrep numrep2 = numrep;
296
297    bool numrep_is_sm = (numrep == SC_BIN_SM ||
298                         numrep == SC_OCT_SM ||
299                         numrep == SC_HEX_SM);
300
301    if (numrep_is_sm) {
302        if (id2.negative() != 0) {
303            s += '-';
304            id2.negative(0);
305        }
306        switch (numrep) {
307          case SC_BIN_SM:
308            numrep2 = SC_BIN_US;
309            break;
310          case SC_OCT_SM:
311            numrep2 = SC_OCT_US;
312            break;
313          case SC_HEX_SM:
314            numrep2 = SC_HEX_US;
315            break;
316          default:
317            ;
318        }
319    }
320
321    if (w_prefix != 0) {
322        scfx_print_prefix(s, numrep);
323    }
324
325    numrep = numrep2;
326
327    sc_fxval_fast a(id2);
328
329    int msb, lsb;
330
331    if (params != 0) {
332        msb = params->iwl() - 1;
333        lsb = params->iwl() - params->wl();
334
335        if (params->enc() == SC_TC_ &&
336            (numrep == SC_BIN_US ||
337              numrep == SC_OCT_US ||
338              numrep == SC_HEX_US) &&
339            !numrep_is_sm &&
340            params->wl() > 1) {
341            --msb;
342        } else if (params->enc() == SC_US_ &&
343            (numrep == SC_BIN ||
344              numrep == SC_OCT ||
345              numrep == SC_HEX ||
346              numrep == SC_CSD)) {
347            ++msb;
348        }
349    } else {
350        if (a.is_zero()) {
351            msb = 0;
352            lsb = 0;
353        } else {
354            msb = id2.exponent() + 1;
355            while (a.get_bit(msb) == a.get_bit(msb - 1))
356                --msb;
357
358            if (numrep == SC_BIN_US ||
359                numrep == SC_OCT_US ||
360                numrep == SC_HEX_US) {
361                --msb;
362            }
363
364            lsb = id2.exponent() - 52;
365            while (!a.get_bit(lsb))
366                ++lsb;
367        }
368    }
369
370    int step;
371
372    switch (numrep) {
373      case SC_BIN:
374      case SC_BIN_US:
375      case SC_CSD:
376        step = 1;
377       break;
378      case SC_OCT:
379      case SC_OCT_US:
380        step = 3;
381        break;
382      case SC_HEX:
383      case SC_HEX_US:
384        step = 4;
385        break;
386      default:
387        SC_REPORT_FATAL(sc_core::SC_ID_ASSERTION_FAILED_,
388                "unexpected sc_numrep");
389        sc_core::sc_abort();
390    }
391
392    msb = (int)std::ceil(double(msb + 1) / step) * step - 1;
393
394    lsb = (int)std::floor(double(lsb) / step) * step;
395
396    if (msb < 0) {
397        s += '.';
398        if (fmt == SC_F) {
399            int sign = (id2.negative() != 0) ? (1 << step) - 1 : 0;
400            for (int i = (msb + 1) / step; i < 0; i++) {
401                if (sign < 10)
402                    s += static_cast<char>(sign + '0');
403                else
404                    s += static_cast<char>(sign + 'a' - 10);
405            }
406        }
407    }
408
409    int i = msb;
410    while (i >= lsb) {
411        int value = 0;
412        for (int j = step - 1; j >= 0; --j) {
413            value += static_cast<int>(a.get_bit(i)) << j;
414            --i;
415        }
416        if (value < 10)
417            s += static_cast<char>(value + '0');
418        else
419            s += static_cast<char>(value + 'a' - 10);
420        if (i == -1)
421            s += '.';
422    }
423
424    if (lsb > 0 && fmt == SC_F) {
425        for (int i = lsb / step; i > 0; i--)
426            s += '0';
427    }
428
429    if (s[s.length() - 1] == '.')
430        s.discard(1);
431
432    if (fmt != SC_F) {
433        if (msb < 0)
434            scfx_print_exp(s, (msb + 1) / step);
435        else if (lsb > 0)
436            scfx_print_exp(s, lsb / step);
437    }
438
439    if (numrep == SC_CSD)
440        scfx_tc2csd(s, w_prefix);
441}
442
443const char *
444to_string(const scfx_ieee_double &id, sc_numrep numrep, int w_prefix,
445          sc_fmt fmt, const scfx_params *params=0)
446{
447    static scfx_string s;
448
449    s.clear();
450
451    if (id.is_nan()) {
452        scfx_print_nan(s);
453    } else if (id.is_inf()) {
454        scfx_print_inf(s, static_cast<bool>(id.negative()));
455    } else if (id.negative() && !id.is_zero() &&
456             (numrep == SC_BIN_US ||
457               numrep == SC_OCT_US ||
458               numrep == SC_HEX_US)) {
459        s += "negative";
460    } else if (numrep == SC_DEC) {
461        sc_dt::print_dec(s, id, w_prefix, fmt);
462    } else {
463        sc_dt::print_other(s, id, numrep, w_prefix, fmt, params);
464    }
465
466    return s;
467}
468
469
470// explicit conversion to character string
471const std::string
472sc_fxval_fast::to_string() const
473{
474    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E));
475}
476
477const std::string
478sc_fxval_fast::to_string(sc_numrep numrep) const
479{
480    return std::string(sc_dt::to_string(m_val, numrep, -1, SC_E));
481}
482
483const std::string
484sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix) const
485{
486    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
487                       SC_E));
488}
489
490const std::string
491sc_fxval_fast::to_string(sc_fmt fmt) const
492{
493    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt));
494}
495
496const std::string
497sc_fxval_fast::to_string(sc_numrep numrep, sc_fmt fmt) const
498{
499    return std::string(sc_dt::to_string(m_val, numrep, -1, fmt));
500}
501
502const std::string
503sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const
504{
505    return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0),
506                                        fmt));
507}
508
509const std::string
510sc_fxval_fast::to_dec() const
511{
512    return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E));
513}
514
515const std::string
516sc_fxval_fast::to_bin() const
517{
518    return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_E));
519}
520
521const std::string
522sc_fxval_fast::to_oct() const
523{
524    return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_E));
525}
526
527const std::string
528sc_fxval_fast::to_hex() const
529{
530    return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_E));
531}
532
533
534// print or dump content
535
536void
537sc_fxval_fast::print(::std::ostream &os) const
538{
539    os << sc_dt::to_string(m_val, SC_DEC, -1, SC_E);
540}
541
542void
543sc_fxval_fast::scan(::std::istream &is)
544{
545    std::string s;
546    is >> s;
547    *this = s.c_str();
548}
549
550void
551sc_fxval_fast::dump(::std::ostream &os) const
552{
553    os << "sc_fxval_fast" << ::std::endl;
554    os << "(" << ::std::endl;
555    os << "val = " << m_val << ::std::endl;
556    // TO BE COMPLETED
557    // os << "r_flag   = " << m_r_flag << ::std::endl;
558    // os << "observer = ";
559    // if (m_observer != 0)
560    //     m_observer->dump(os);
561    // else
562    //     os << "0" << ::std::endl;
563    os << ")" << ::std::endl;
564}
565
566
567// internal use only;
568bool
569sc_fxval_fast::get_bit(int i) const
570{
571    scfx_ieee_double id(m_val);
572    if (id.is_zero() || id.is_nan() || id.is_inf())
573        return false;
574
575    // convert to two's complement
576    unsigned int m0 = id.mantissa0();
577    unsigned int m1 = id.mantissa1();
578
579    if (id.is_normal())
580        m0 += 1U << 20;
581
582    if (id.negative() != 0) {
583        m0 = ~ m0;
584        m1 = ~ m1;
585        unsigned int tmp = m1;
586        m1 += 1U;
587        if (m1 <= tmp)
588            m0 += 1U;
589    }
590
591    // get the right bit
592    int j = i - id.exponent();
593    if ((j += 20) >= 32)
594        return ((m0 & 1U << 31) != 0);
595    else if (j >= 0)
596        return ((m0 & 1U << j) != 0);
597    else if ((j += 32) >= 0)
598        return ((m1 & 1U << j) != 0);
599    else
600        return false;
601}
602
603
604// protected methods and friend functions
605sc_fxval_fast_observer *
606sc_fxval_fast::lock_observer() const
607{
608    SC_ASSERT_(m_observer != 0, "lock observer failed");
609    sc_fxval_fast_observer *tmp = m_observer;
610    m_observer = 0;
611    return tmp;
612}
613
614void
615sc_fxval_fast::unlock_observer(sc_fxval_fast_observer *observer_) const
616{
617    SC_ASSERT_(observer_ != 0, "unlock observer failed");
618    m_observer = observer_;
619}
620
621#define SCFX_FAIL_IF_(cnd)                                                    \
622{                                                                             \
623    if ((cnd))                                                             \
624        return static_cast<double>(scfx_ieee_double::nan());                \
625}
626
627double
628sc_fxval_fast::from_string(const char *s)
629{
630    SCFX_FAIL_IF_(s == 0 || *s == 0);
631
632    scfx_string s2;
633    s2 += s;
634    s2 += '\0';
635
636    bool sign_char;
637    int sign = scfx_parse_sign(s, sign_char);
638
639    sc_numrep numrep = scfx_parse_prefix(s);
640
641    int base = 0;
642
643    switch (numrep) {
644      case SC_DEC:
645        {
646            base = 10;
647            if (scfx_is_nan(s)) // special case: NaN
648                return static_cast<double>(scfx_ieee_double::nan());
649            if (scfx_is_inf(s)) // special case: Infinity
650                return static_cast<double>(scfx_ieee_double::inf(sign));
651            break;
652        }
653      case SC_BIN:
654      case SC_BIN_US:
655        {
656            SCFX_FAIL_IF_(sign_char);
657            base = 2;
658            break;
659        }
660
661      case SC_BIN_SM:
662        {
663            base = 2;
664            break;
665        }
666      case SC_OCT:
667      case SC_OCT_US:
668        {
669            SCFX_FAIL_IF_(sign_char);
670            base = 8;
671            break;
672        }
673      case SC_OCT_SM:
674        {
675            base = 8;
676            break;
677        }
678      case SC_HEX:
679      case SC_HEX_US:
680        {
681            SCFX_FAIL_IF_(sign_char);
682            base = 16;
683            break;
684        }
685      case SC_HEX_SM:
686        {
687            base = 16;
688            break;
689        }
690      case SC_CSD:
691        {
692            SCFX_FAIL_IF_(sign_char);
693            base = 2;
694            scfx_csd2tc(s2);
695            s = (const char*) s2 + 4;
696            numrep = SC_BIN;
697            break;
698        }
699      default:;// Martin, what is default???
700    }
701
702    //
703    // find end of mantissa and count the digits and points
704    //
705
706    const char *end = s;
707    bool based_point = false;
708    int int_digits = 0;
709    int frac_digits = 0;
710
711    while (*end) {
712        if (scfx_exp_start(end))
713            break;
714
715        if (*end == '.') {
716            SCFX_FAIL_IF_(based_point);
717            based_point = true;
718        } else {
719            SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep));
720            if (based_point)
721                frac_digits++;
722            else
723                int_digits++;
724        }
725
726        end++;
727    }
728
729    SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0);
730
731    // [ exponent ]
732    int exponent = 0;
733    if (*end) {
734        for (const char *e = end + 2; *e; e++)
735            SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC));
736        exponent = std::atoi(end + 1);
737    }
738
739    //
740    // convert the mantissa
741    //
742    double integer = 0.0;
743    if (int_digits != 0) {
744        bool first_digit = true;
745
746        for (; s < end; s++) {
747            if (*s == '.')
748                break;
749
750            if (first_digit) {
751                integer = scfx_to_digit(*s, numrep);
752                switch (numrep) {
753                  case SC_BIN:
754                  case SC_OCT:
755                  case SC_HEX:
756                    {
757                        if (integer >= (base >> 1))
758                            integer -= base; // two's complement
759                        break;
760                    }
761                  default:
762                    ;
763                }
764                first_digit = false;
765            } else {
766                integer *= base;
767                integer += scfx_to_digit(*s, numrep);
768            }
769        }
770    }
771
772    // [ . fraction ]
773    double fraction = 0.0;
774    if (frac_digits != 0) {
775        s++;  // skip '.'
776
777        bool first_digit = (int_digits == 0);
778        double scale = 1.0;
779        for (; s < end; s++) {
780            scale /= base;
781
782            if (first_digit) {
783                fraction = scfx_to_digit(*s, numrep);
784                switch (numrep) {
785                  case SC_BIN:
786                  case SC_OCT:
787                  case SC_HEX:
788                    {
789                        if (fraction >= (base >> 1))
790                            fraction -= base; // two's complement
791                        break;
792                    }
793                  default:
794                    ;
795                }
796                fraction *= scale;
797                first_digit = false;
798            } else {
799                fraction += scfx_to_digit(*s, numrep) * scale;
800            }
801        }
802    }
803
804    double exp =
805        (exponent != 0) ? std::pow((double) base, (double) exponent) : 1;
806
807    return (sign * (integer + fraction) * exp);
808}
809
810#undef SCFX_FAIL_IF_
811
812} // namespace sc_dt
813