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