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