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