From c8d3cb5fadfac8ad90fd81edc707d83051b275da Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 10 Sep 2018 20:37:19 -0700 Subject: systemc: Stop assuming picoseconds as the time resolution. Also adjust some code to avoid floating point rounding problems and integer overflow issues. Change-Id: Ib4b9c4cf4af00333951db5ce07819556141aa5da Reviewed-on: https://gem5-review.googlesource.com/c/12614 Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/systemc/core/sc_time.cc | 110 +++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/systemc/core/sc_time.cc b/src/systemc/core/sc_time.cc index 69d58e512..999fba2f9 100644 --- a/src/systemc/core/sc_time.cc +++ b/src/systemc/core/sc_time.cc @@ -33,6 +33,7 @@ #include "base/logging.hh" #include "base/types.hh" #include "python/pybind11/pybind.hh" +#include "sim/core.hh" #include "systemc/core/python.hh" #include "systemc/ext/core/sc_main.hh" #include "systemc/ext/core/sc_time.hh" @@ -62,6 +63,15 @@ double TimeUnitScale[] = { [SC_SEC] = 1.0 }; +Tick TimeUnitFrequency[] = { + [SC_FS] = 1ULL * 1000 * 1000 * 1000 * 1000 * 1000, + [SC_PS] = 1ULL * 1000 * 1000 * 1000 * 1000, + [SC_NS] = 1ULL * 1000 * 1000 * 1000, + [SC_US] = 1ULL * 1000 * 1000, + [SC_MS] = 1ULL * 1000, + [SC_SEC] = 1ULL +}; + bool timeFixed = false; bool pythonReady = false; @@ -80,8 +90,7 @@ std::vector toSet; void setWork(sc_time *time, double d, ::sc_core::sc_time_unit tu) { - //XXX Assuming the time resolution is 1ps. - double scale = TimeUnitScale[tu] / TimeUnitScale[SC_PS]; + double scale = TimeUnitScale[tu] * SimClock::Float::s; // Accellera claims there is a linux bug, and that these next two // lines work around them. volatile double tmp = d * scale + 0.5; @@ -100,6 +109,19 @@ fixTime() toSet.clear(); } +void +attemptToFixTime() +{ + // Only fix time once. + if (!timeFixed) { + timeFixed = true; + + // If we've run, python is working and we haven't fixed time yet. + if (pythonReady) + fixTime(); + } +} + void setGlobalFrequency(Tick ticks_per_second) { @@ -112,14 +134,8 @@ setGlobalFrequency(Tick ticks_per_second) void set(::sc_core::sc_time *time, double d, ::sc_core::sc_time_unit tu) { - // Only fix time once. - if (!timeFixed) { - timeFixed = true; - - // If we've run, python is working and we haven't fixed time yet. - if (pythonReady) - fixTime(); - } + if (d != 0) + attemptToFixTime(); if (pythonReady) { // Time should be working. Set up this sc_time. setWork(time, d, tu); @@ -155,8 +171,7 @@ sc_time::sc_time() : val(0) {} sc_time::sc_time(double d, sc_time_unit tu) { val = 0; - if (d != 0) - set(this, d, tu); + set(this, d, tu); } sc_time::sc_time(const sc_time &t) @@ -166,20 +181,14 @@ sc_time::sc_time(const sc_time &t) sc_time::sc_time(double d, bool scale) { - //XXX Assuming the time resolution is 1ps. - if (scale) - set(this, d * defaultUnit, SC_SEC); - else - set(this, d, SC_PS); + double scaler = scale ? defaultUnit : SimClock::Float::Hz; + set(this, d * scaler, SC_SEC); } sc_time::sc_time(sc_dt::uint64 v, bool scale) { - //XXX Assuming the time resolution is 1ps. - if (scale) - set(this, static_cast(v) * defaultUnit, SC_SEC); - else - set(this, static_cast(v), SC_PS); + double scaler = scale ? defaultUnit : SimClock::Float::Hz; + set(this, static_cast(v) * scaler, SC_SEC); } sc_time & @@ -203,10 +212,7 @@ sc_time::to_double() const double sc_time::to_seconds() const { - double d = to_double(); - //XXX Assuming the time resolution is 1ps. - double scale = TimeUnitScale[SC_PS] / TimeUnitScale[SC_SEC]; - return d * scale; + return to_double() * SimClock::Float::Hz; } const std::string @@ -287,9 +293,30 @@ sc_time::print(std::ostream &os) const if (val == 0) { os << "0 s"; } else { - //XXX Assuming the time resolution is 1ps. - sc_time_unit tu = SC_PS; - uint64_t scaled = val; + Tick frequency = SimClock::Frequency; + + // Shrink the frequency by scaling down the time period, ie converting + // it from cycles per second to cycles per millisecond, etc. + sc_time_unit tu = SC_SEC; + while (tu > 1 && (frequency % 1000 == 0)) { + tu = (sc_time_unit)((int)tu - 1); + frequency /= 1000; + } + + // Convert the frequency into a period. + Tick period; + if (frequency > 1) { + tu = (sc_time_unit)((int)tu - 1); + period = 1000 / frequency; + } else { + period = frequency; + } + + // Scale our integer value by the period. + uint64_t scaled = val * period; + + // Shrink the scaled time value by increasing the size of the units + // it's measured by, avoiding fractional parts. while (tu < SC_SEC && (scaled % 1000) == 0) { tu = (sc_time_unit)((int)tu + 1); scaled /= 1000; @@ -302,6 +329,8 @@ sc_time::print(std::ostream &os) const sc_time sc_time::from_value(sc_dt::uint64 u) { + if (u) + attemptToFixTime(); sc_time t; t.val = u; return t; @@ -398,16 +427,25 @@ sc_set_time_resolution(double d, sc_time_unit tu) "sc_time object(s) constructed"); } - // Normalize d to seconds. - d *= TimeUnitScale[tu]; - if (d < TimeUnitScale[SC_FS]) { + double seconds = d * TimeUnitScale[tu]; + if (seconds < TimeUnitScale[SC_FS]) { SC_REPORT_ERROR("(E514) set time resolution failed", "value smaller than 1 fs"); } - // Change d from a period to a frequency. - d = 1 / d; - // Convert to integer ticks. - Tick ticks_per_second = static_cast(d); + + if (seconds > defaultUnit) { + SC_REPORT_WARNING( + "(W516) default time unit changed to time resolution", ""); + defaultUnit = seconds; + } + + // Get rid of fractional parts of d. + while (d < 1.0 && tu > SC_FS) { + d *= 1000; + tu = (sc_time_unit)(tu - 1); + } + + Tick ticks_per_second = TimeUnitFrequency[tu] / static_cast(d); setGlobalFrequency(ticks_per_second); specified = true; } -- cgit v1.2.3