diff --git a/src/sysc/kernel/sc_time.cpp b/src/sysc/kernel/sc_time.cpp index aa318cbed..23e6fd26f 100644 --- a/src/sysc/kernel/sc_time.cpp +++ b/src/sysc/kernel/sc_time.cpp @@ -69,6 +69,17 @@ const char* time_units[] = { "ys" }; + +static void inline time_params_freeze( sc_time_params* tp ) +{ + tp->time_resolution_fixed.store( true, std::memory_order_relaxed ); +} + +[[nodiscard]] static bool inline time_params_frozen( sc_time_params* tp ) +{ + return tp->time_resolution_fixed.load(); +} + // ---------------------------------------------------------------------------- // CLASS : sc_time_tuple // @@ -78,17 +89,12 @@ const char* time_units[] = { void sc_time_tuple::init( value_type val ) { - sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params; - time_params->time_resolution_fixed = true; - - auto tr_log10 = std::log10( time_params->time_resolution ); - auto scale = static_cast( tr_log10 ); - - [[maybe_unused]] double ignored = 0.0; - sc_assert( std::modf( tr_log10, &ignored ) == 0.0 ); + auto * time_params = sc_get_curr_simcontext()->m_time_params; + time_params_freeze( time_params ); constexpr unsigned tu_max = sizeof(time_units) / sizeof(time_units[0])-1; - unsigned tu = tu_max - (scale / 3); + auto scale = time_params->time_resolution_log10; + auto tu = tu_max - (scale / 3); while( tu > 0 && ( val % 10 ) == 0 ) { val /= 10; scale++; @@ -149,13 +155,12 @@ from_value_and_unit( double v, sc_time_unit tu, sc_time_params* tp ) { sc_time::value_type t = 0; if( v != 0 ) { + time_params_freeze( tp ); double scale_fac = time_values[5-tu] / tp->time_resolution; // sc_time_unit constants have offset of 5 // linux bug workaround; don't change next two lines volatile double tmp = v * scale_fac + 0.5; t = static_cast( tmp ); - tp->time_resolution_fixed = true; } - return t; } @@ -225,7 +230,8 @@ sc_time::sc_time( double v, bool scale ) } if( v != 0 ) { - sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params; + auto * time_params = sc_get_curr_simcontext()->m_time_params; + time_params_freeze( time_params ); if( scale ) { double scale_fac = sc_dt::uint64_to_double( time_params->default_time_unit ); // linux bug workaround; don't change next two lines @@ -236,7 +242,6 @@ sc_time::sc_time( double v, bool scale ) volatile double tmp = v + 0.5; m_value = static_cast( tmp ); } - time_params->time_resolution_fixed = true; } } @@ -251,7 +256,8 @@ sc_time::sc_time( value_type v, bool scale ) } if( v != 0 ) { - sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params; + auto * time_params = sc_get_curr_simcontext()->m_time_params; + time_params_freeze( time_params ); if( scale ) { double scale_fac = sc_dt::uint64_to_double( time_params->default_time_unit ); @@ -261,7 +267,6 @@ sc_time::sc_time( value_type v, bool scale ) } else { m_value = v; } - time_params->time_resolution_fixed = true; } } @@ -280,8 +285,8 @@ sc_time::from_value( value_type v ) { sc_time t; if( v != 0 && v != ~sc_dt::UINT64_ZERO ) { - sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params; - time_params->time_resolution_fixed = true; + auto * time_params = sc_get_curr_simcontext()->m_time_params; + time_params_freeze( time_params ); } t.m_value = v; return t; @@ -293,10 +298,12 @@ sc_time::from_value( value_type v ) double sc_time::to_default_time_units() const { - sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params; if( m_value == 0 ) return 0.0; - time_params->time_resolution_fixed = true; + + auto * time_params = sc_get_curr_simcontext()->m_time_params; + time_params_freeze( time_params ); + return ( sc_dt::uint64_to_double( m_value ) / sc_dt::uint64_to_double( time_params->default_time_unit ) ); } @@ -304,10 +311,12 @@ sc_time::to_default_time_units() const double sc_time::to_seconds() const { - sc_time_params* time_params = sc_get_curr_simcontext()->m_time_params; if( m_value == 0 ) return 0.0; - time_params->time_resolution_fixed = true; + + auto * time_params = sc_get_curr_simcontext()->m_time_params; + time_params_freeze( time_params ); + return ( sc_dt::uint64_to_double( m_value ) * ( time_params->time_resolution / time_values[0] ) ); } @@ -330,16 +339,13 @@ sc_time::print( ::std::ostream& os ) const sc_time_params::sc_time_params() : time_resolution( time_values[4] ), // default 1 ps + time_resolution_log10( static_cast(log10(time_resolution)) ), time_resolution_specified( false ), time_resolution_fixed( false ), default_time_unit( 1000 ), // default 1 ns default_time_unit_specified( false ) {} -sc_time_params::~sc_time_params() -{} - - // ---------------------------------------------------------------------------- // functions for accessing the time resolution and default time unit @@ -359,14 +365,12 @@ sc_set_time_resolution( double v, sc_time_unit tu ) SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_, "value not a power of ten" ); } - sc_simcontext* simc = sc_get_curr_simcontext(); - // can only be specified during elaboration if( sc_is_running() ) { SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_, "simulation running" ); } - sc_time_params* time_params = simc->m_time_params; + auto * time_params = sc_get_curr_simcontext()->m_time_params; // can be specified only once if( time_params->time_resolution_specified ) { @@ -374,7 +378,7 @@ sc_set_time_resolution( double v, sc_time_unit tu ) } // can only be specified before any sc_time is constructed - if( time_params->time_resolution_fixed ) { + if( time_params_frozen( time_params ) ) { SC_REPORT_ERROR( SC_ID_SET_TIME_RESOLUTION_, "sc_time object(s) constructed" ); } @@ -395,6 +399,7 @@ sc_set_time_resolution( double v, sc_time_unit tu ) } time_params->time_resolution = resolution; + time_params->time_resolution_log10 = static_cast( log10( resolution ) ); time_params->time_resolution_specified = true; } @@ -430,19 +435,16 @@ sc_set_default_time_unit( double v, sc_time_unit tu ) "value not a power of ten" ); } - sc_simcontext* simc = sc_get_curr_simcontext(); - // can only be specified during elaboration if( sc_is_running() ) { SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_, "simulation running" ); } - sc_time_params* time_params = simc->m_time_params; + auto * time_params = sc_get_curr_simcontext()->m_time_params; // can only be specified before any sc_time is constructed - if( time_params->time_resolution_fixed ) { - SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_, - "sc_time object(s) constructed" ); + if( time_params_frozen( time_params ) ) { + SC_REPORT_ERROR( SC_ID_SET_DEFAULT_TIME_UNIT_, "sc_time object(s) constructed" ); } // can be specified only once diff --git a/src/sysc/kernel/sc_time.h b/src/sysc/kernel/sc_time.h index 283f69eb4..9d4427da9 100644 --- a/src/sysc/kernel/sc_time.h +++ b/src/sysc/kernel/sc_time.h @@ -34,6 +34,7 @@ #include "sysc/datatypes/int/sc_nbdefs.h" #include "sysc/datatypes/fx/scfx_ieee.h" +#include #include #include @@ -460,15 +461,15 @@ operator << ( ::std::ostream& os, const sc_time& t ) struct SC_API sc_time_params { - double time_resolution; // in yocto seconds - bool time_resolution_specified; - bool time_resolution_fixed; + double time_resolution; // in yocto seconds + unsigned time_resolution_log10; + bool time_resolution_specified; + std::atomic time_resolution_fixed; sc_time::value_type default_time_unit; // in time resolution bool default_time_unit_specified; sc_time_params(); - ~sc_time_params(); }; diff --git a/tests/systemc/kernel/sc_time/test19/test19.cpp b/tests/systemc/kernel/sc_time/test19/test19.cpp index 7f4c1b066..e4930fec8 100644 --- a/tests/systemc/kernel/sc_time/test19/test19.cpp +++ b/tests/systemc/kernel/sc_time/test19/test19.cpp @@ -32,14 +32,15 @@ void check_time( const sc_time& t, sc_time_unit tu, const std::string & str ) { sc_time_tuple tp = t; +#ifndef BENCHMARK std::cout << t.to_string() << ", value=" << t.value() << std::endl; std::cout << " "; if( tp.has_value() ) std::cout << "t.value=" << tp.value(); else std::cout << "t.double=" << tp.to_double(); - std::cout << ", t.unit=" << tp.unit_symbol() - << std::endl; + std::cout << ", t.unit=" << tp.unit_symbol() << std::endl; +#endif // BENCHMARK sc_assert( tp.has_value() ); sc_assert( t.to_string() == str ); @@ -50,10 +51,26 @@ void check_time( const sc_time& t, sc_time_unit tu, const std::string & str ) sc_assert( t == u ); sc_assert( u == tp ); sc_assert( tp.unit() == sc_time_tuple(u).unit() ); +} + +#ifdef BENCHMARK +int test_iteration(); +int sc_main( int, char*[] ) +{ + sc_report_handler::set_actions( SC_WARNING, SC_DO_NOTHING ); + + static const int iterations = 20'000; + for(int i = 0; i < iterations; ++i ) { + test_iteration(); + } + return 0; } +int test_iteration() +#else int sc_main( int, char*[] ) +#endif { sc_report_handler::set_actions( SC_ID_SET_TIME_RESOLUTION_, SC_DO_NOTHING ); sc_report_handler::set_actions( SC_ID_TIME_CONVERSION_FAILED_, SC_DISPLAY ); @@ -77,7 +94,9 @@ int sc_main( int, char*[] ) for( auto res : resolutions ) { sc_set_time_resolution( res, resunit ); +#ifndef BENCHMARK std::cout << "\nResolution = " << sc_get_time_resolution() << std::endl; +#endif // BENCHMARK check_time( sc_time( 10, SC_NS), SC_NS, "10 ns" ); check_time( sc_time( 100, SC_NS), SC_NS, "100 ns" ); @@ -98,12 +117,16 @@ int sc_main( int, char*[] ) { sc_set_time_resolution(1, SC_SEC); +#ifndef BENCHMARK std::cout << "\nResolution = " << sc_get_time_resolution() << std::endl; +#endif // BENCHMARK auto t = sc_core::sc_time(1, SC_SEC); check_time( t, SC_SEC, "1 s"); } +#ifndef BENCHMARK cout << "\nProgram completed" << endl; +#endif // BENCHMARK return 0; }