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_time.cpp --
23
24  Original Author: Martin Janssen, Synopsys, Inc., 2001-05-21
25
26  CHANGE LOG AT THE END OF THE FILE
27 *****************************************************************************/
28
29
30#include <math.h>
31#include <stdio.h>
32
33#include "sysc/kernel/sc_kernel_ids.h"
34#include "sysc/kernel/sc_simcontext.h"
35#include "sysc/kernel/sc_time.h"
36#include "sysc/utils/sc_utils_ids.h"
37
38#if !defined(PRIu64)
39#   if defined(_MSC_VER) || defined(__MINGW32__)
40#       define PRIu64 "I64u"
41#   else
42#       define PRIu64 "llu"
43#   endif
44#endif // PRIu64
45
46#ifdef SC_ENABLE_EARLY_MAXTIME_CREATION
47#  define SC_MAXTIME_ALLOWED_ 1
48#else
49#  define SC_MAXTIME_ALLOWED_ 0
50#endif
51
52namespace sc_core {
53
54static
55double time_values[] = {
56    1,       // fs
57    1e3,     // ps
58    1e6,     // ns
59    1e9,     // us
60    1e12,    // ms
61    1e15     // s
62};
63
64static
65const char* time_units[] = {
66    "fs",
67    "ps",
68    "ns",
69    "us",
70    "ms",
71    "s"
72};
73
74
75// ----------------------------------------------------------------------------
76//  CLASS : sc_time
77//
78//  The time class.
79// ----------------------------------------------------------------------------
80
81// constructors
82
83sc_time::sc_time( double v, sc_time_unit tu )
84: m_value( 0 )
85{
86    if( v != 0 ) {
87	sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
88	double scale_fac = time_values[tu] / time_params->time_resolution;
89	// linux bug workaround; don't change next two lines
90	volatile double tmp = v * scale_fac + 0.5;
91	m_value = SCAST<sc_dt::int64>( tmp );
92	time_params->time_resolution_fixed = true;
93    }
94}
95
96sc_time::sc_time( double v, sc_time_unit tu, sc_simcontext* simc )
97: m_value( 0 )
98{
99    if( v != 0 ) {
100	sc_time_params* time_params = simc->m_time_params;
101	double scale_fac = time_values[tu] / time_params->time_resolution;
102	// linux bug workaround; don't change next two lines
103	volatile double tmp = v * scale_fac + 0.5;
104	m_value = SCAST<sc_dt::int64>( tmp );
105	time_params->time_resolution_fixed = true;
106    }
107}
108
109sc_time::sc_time( double v, bool scale )
110: m_value( 0 )
111{
112    static bool warn_constructor=true;
113    if ( warn_constructor ) {
114        warn_constructor=false;
115        SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
116            "deprecated constructor: sc_time(double,bool)");
117    }
118
119    if( v != 0 ) {
120	sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
121	if( scale ) {
122	    double scale_fac = sc_dt::uint64_to_double(
123		time_params->default_time_unit );
124	    // linux bug workaround; don't change next two lines
125	    volatile double tmp = v * scale_fac + 0.5;
126	    m_value = SCAST<sc_dt::int64>( tmp );
127	} else {
128	    // linux bug workaround; don't change next two lines
129	    volatile double tmp = v + 0.5;
130	    m_value = SCAST<sc_dt::int64>( tmp );
131	}
132	time_params->time_resolution_fixed = true;
133    }
134}
135
136sc_time::sc_time( value_type v, bool scale )
137: m_value( 0 )
138{
139    static bool warn_constructor=true;
140    if ( warn_constructor ) {
141        warn_constructor=false;
142        SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
143            "deprecated constructor: sc_time(uint64,bool)");
144    }
145
146    if( v != 0 ) {
147	sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
148	if( scale ) {
149	    double scale_fac = sc_dt::uint64_to_double(
150		time_params->default_time_unit );
151	    // linux bug workaround; don't change next two lines
152	    volatile double tmp = sc_dt::uint64_to_double( v ) *
153		                  scale_fac + 0.5;
154	    m_value = SCAST<sc_dt::int64>( tmp );
155	} else {
156	    m_value = v;
157	}
158	time_params->time_resolution_fixed = true;
159    }
160}
161
162sc_time
163sc_time::from_value( value_type v )
164{
165    sc_time t;
166    if( v != 0 && !(SC_MAXTIME_ALLOWED_ && v == ~sc_dt::UINT64_ZERO) ) {
167        sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
168        time_params->time_resolution_fixed = true;
169    }
170    t.m_value = v;
171    return t;
172}
173
174
175// conversion functions
176
177double
178sc_time::to_default_time_units() const
179{
180    sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
181#   if SC_MAXTIME_ALLOWED_
182        if( m_value == 0 )
183            return 0.0;
184        time_params->time_resolution_fixed = true;
185#   endif // SC_MAXTIME_ALLOWED_
186    return ( sc_dt::uint64_to_double( m_value ) /
187	     sc_dt::uint64_to_double( time_params->default_time_unit ) );
188}
189
190double
191sc_time::to_seconds() const
192{
193    sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
194#   if SC_MAXTIME_ALLOWED_
195        if( m_value == 0 )
196            return 0.0;
197        time_params->time_resolution_fixed = true;
198#   endif // SC_MAXTIME_ALLOWED_
199    return ( sc_dt::uint64_to_double( m_value ) *
200	     time_params->time_resolution * 1e-15 );
201}
202
203const std::string
204sc_time::to_string() const
205{
206    value_type val = m_value;
207    if( val == 0 ) {
208	return std::string( "0 s" );
209    }
210    sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params;
211#   if SC_MAXTIME_ALLOWED_
212        time_params->time_resolution_fixed = true;
213#   endif // SC_MAXTIME_ALLOWED_
214    value_type tr = SCAST<sc_dt::int64>( time_params->time_resolution );
215    int n = 0;
216    while( ( tr % 10 ) == 0 ) {
217	tr /= 10;
218	n ++;
219    }
220    assert( tr == 1 );
221    while( ( val % 10 ) == 0 ) {
222	val /= 10;
223	n ++;
224    }
225    char buf[BUFSIZ];
226    std::sprintf( buf, "%" PRIu64, val );
227    std::string result( buf );
228    if( n >= 15 ) {
229	for( int i = n - 15; i > 0; -- i ) {
230	    result += "0";
231	}
232	result += " s";
233    } else {
234	for( int i = n % 3; i > 0; -- i ) {
235	    result += "0";
236	}
237	result += " ";
238	result += time_units[n / 3];
239    }
240    return result;
241}
242
243
244// print function
245
246void
247sc_time::print( ::std::ostream& os ) const
248{
249    os << to_string();
250}
251
252
253// ----------------------------------------------------------------------------
254//  STRUCT : sc_time_params
255//
256//  Struct that holds the time resolution and default time unit.
257// ----------------------------------------------------------------------------
258
259sc_time_params::sc_time_params()
260: time_resolution( 1000 ),		// default 1 ps
261  time_resolution_specified( false ),
262  time_resolution_fixed( false ),
263  default_time_unit( 1000 ),		// default 1 ns
264  default_time_unit_specified( false )
265{}
266
267sc_time_params::~sc_time_params()
268{}
269
270
271// ----------------------------------------------------------------------------
272
273// functions for accessing the time resolution and default time unit
274
275void
276sc_set_time_resolution( double v, sc_time_unit tu )
277{
278    // first perform the necessary checks
279
280    // must be positive
281    if( v < 0.0 ) {
282	SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_, "value not positive" );
283    }
284
285    // must be a power of ten
286    double dummy;
287#if defined( __HP_aCC ) || defined(__ppc__)
288    // aCC seems to have a bug in modf()
289    if( modf( log10( v < 1.0 ? 1.0/v : v ), &dummy ) != 0.0 ) {
290#else
291    if( modf( log10( v ), &dummy ) != 0.0 ) {
292#endif
293	SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_,
294			 "value not a power of ten" );
295    }
296
297    sc_simcontext* simc = sc_get_curr_simcontext();
298
299    // can only be specified during elaboration
300    if( sc_is_running() ) {
301	SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_, "simulation running" );
302    }
303
304    sc_time_params* time_params = simc->m_time_params;
305
306    // can be specified only once
307    if( time_params->time_resolution_specified ) {
308	SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_, "already specified" );
309    }
310
311    // can only be specified before any sc_time is constructed
312    if( time_params->time_resolution_fixed ) {
313	SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_,
314			 "sc_time object(s) constructed" );
315    }
316
317    // must be larger than or equal to 1 fs
318    volatile double resolution = v * time_values[tu];
319    if( resolution < 1.0 ) {
320	SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_,
321			 "value smaller than 1 fs" );
322    }
323
324    // recalculate the default time unit
325    volatile double time_unit = sc_dt::uint64_to_double(
326	time_params->default_time_unit ) *
327	( time_params->time_resolution / resolution );
328    if( time_unit < 1.0 ) {
329	SC_REPORT_WARNING( SC_ID_DEFAULT_TIME_UNIT_CHANGED_, 0 );
330	time_params->default_time_unit = 1;
331    } else {
332	time_params->default_time_unit = SCAST<sc_dt::int64>( time_unit );
333    }
334
335    time_params->time_resolution = resolution;
336    time_params->time_resolution_specified = true;
337}
338
339sc_time
340sc_get_time_resolution()
341{
342    return sc_time::from_value( sc_dt::UINT64_ONE );
343}
344
345
346void
347sc_set_default_time_unit( double v, sc_time_unit tu )
348{
349    static bool warn_default_time_unit=true;
350    if ( warn_default_time_unit )
351    {
352        warn_default_time_unit=false;
353        SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
354	    "deprecated function: sc_set_default_time_unit");
355    }
356
357    // first perform the necessary checks
358
359    // must be positive
360    if( v < 0.0 ) {
361	SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_, "value not positive" );
362    }
363
364    // must be a power of ten
365    double dummy;
366    if( modf( log10( v ), &dummy ) != 0.0 ) {
367	SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_,
368			 "value not a power of ten" );
369    }
370
371    sc_simcontext* simc = sc_get_curr_simcontext();
372
373    // can only be specified during elaboration
374    if( sc_is_running() ) {
375	SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_, "simulation running" );
376    }
377
378    sc_time_params* time_params = simc->m_time_params;
379
380    // can only be specified before any sc_time is constructed
381    if( time_params->time_resolution_fixed ) {
382        SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_,
383                         "sc_time object(s) constructed" );
384    }
385
386    // can be specified only once
387    if( time_params->default_time_unit_specified ) {
388	SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_, "already specified" );
389    }
390
391    // must be larger than or equal to the time resolution
392    volatile double time_unit = ( v * time_values[tu] ) /
393	                        time_params->time_resolution;
394    if( time_unit < 1.0 ) {
395	SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_,
396			 "value smaller than time resolution" );
397    }
398
399    time_params->default_time_unit = SCAST<sc_dt::int64>( time_unit );
400    time_params->default_time_unit_specified = true;
401}
402
403sc_time
404sc_get_default_time_unit()
405{
406    static bool warn_get_default_time_unit = true;
407    if ( warn_get_default_time_unit )
408    {
409        warn_get_default_time_unit=false;
410        SC_REPORT_INFO(SC_ID_IEEE_1666_DEPRECATION_,
411            "deprecated function: sc_get_default_time_unit");
412    }
413    return sc_time::from_value(
414              sc_get_curr_simcontext()->m_time_params->default_time_unit
415           );
416}
417
418
419// ----------------------------------------------------------------------------
420
421const sc_time SC_ZERO_TIME;
422
423#undef SC_MAXTIME_ALLOWED_
424
425} // namespace sc_core
426
427// $Log: sc_time.cpp,v $
428// Revision 1.7  2011/08/26 20:46:11  acg
429//  Andy Goodrich: moved the modification log to the end of the file to
430//  eliminate source line number skew when check-ins are done.
431//
432// Revision 1.6  2011/07/24 16:08:36  acg
433//  Philipp A. Hartmann: fix C99 format specifiers for Solaris.
434//
435// Revision 1.5  2011/02/18 20:27:14  acg
436//  Andy Goodrich: Updated Copyrights.
437//
438// Revision 1.4  2011/02/13 21:47:38  acg
439//  Andy Goodrich: update copyright notice.
440//
441// Revision 1.3  2011/01/19 23:21:50  acg
442//  Andy Goodrich: changes for IEEE 1666 2011
443//
444// Revision 1.2  2008/05/22 17:06:27  acg
445//  Andy Goodrich: updated copyright notice to include 2008.
446//
447// Revision 1.1.1.1  2006/12/15 20:20:05  acg
448// SystemC 2.3
449//
450// Revision 1.6  2006/01/26 21:04:55  acg
451//  Andy Goodrich: deprecation message changes and additional messages.
452//
453// Revision 1.5  2006/01/25 00:31:19  acg
454//  Andy Goodrich: Changed over to use a standard message id of
455//  SC_ID_IEEE_1666_DEPRECATION for all deprecation messages.
456//
457// Revision 1.4  2006/01/24 20:49:05  acg
458// Andy Goodrich: changes to remove the use of deprecated features within the
459// simulator, and to issue warning messages when deprecated features are used.
460//
461// Revision 1.3  2006/01/13 18:44:30  acg
462// Added $Log to record CVS changes into the source.
463//
464
465// Taf!
466