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:
386 SC_REPORT_FATAL("assertion failed", "unexpected sc_numrep");
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