blob: bc35f2ab8cf2d5a836031b4a31218dc0ad40d21d [file] [log] [blame]
/*
* Copyright 2018 Google, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Gabe Black
*/
#include <vector>
#include "base/logging.hh"
#include "base/types.hh"
#include "python/pybind11/pybind.hh"
#include "systemc/core/python.hh"
#include "systemc/ext/core/sc_time.hh"
namespace sc_core
{
namespace
{
const char *TimeUnitNames[] = {
[SC_FS] = "fs",
[SC_PS] = "ps",
[SC_NS] = "ns",
[SC_US] = "us",
[SC_MS] = "ms",
[SC_SEC] = "s"
};
double TimeUnitScale[] = {
[SC_FS] = 1.0e-15,
[SC_PS] = 1.0e-12,
[SC_NS] = 1.0e-9,
[SC_US] = 1.0e-6,
[SC_MS] = 1.0e-3,
[SC_SEC] = 1.0
};
bool timeFixed = false;
bool pythonReady = false;
struct SetInfo
{
SetInfo(::sc_core::sc_time *time, double d, ::sc_core::sc_time_unit tu) :
time(time), d(d), tu(tu)
{}
::sc_core::sc_time *time;
double d;
::sc_core::sc_time_unit tu;
};
std::vector<SetInfo> 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];
// Accellera claims there is a linux bug, and that these next two
// lines work around them.
volatile double tmp = d * scale + 0.5;
*time = sc_time::from_value(static_cast<uint64_t>(tmp));
}
void
fixTime()
{
auto ticks = pybind11::module::import("m5.ticks");
auto fix_global_frequency = ticks.attr("fixGlobalFrequency");
fix_global_frequency();
for (auto &t: toSet)
setWork(t.time, t.d, t.tu);
toSet.clear();
}
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 (pythonReady) {
// Time should be working. Set up this sc_time.
setWork(time, d, tu);
} else {
// Time isn't set up yet. Defer setting up this sc_time.
toSet.emplace_back(time, d, tu);
}
}
class TimeSetter : public ::sc_gem5::PythonReadyFunc
{
public:
TimeSetter() : ::sc_gem5::PythonReadyFunc() {}
void
run() override
{
// Record that we've run and python/pybind should be usable.
pythonReady = true;
// If time is already fixed, let python know.
if (timeFixed)
fixTime();
}
} timeSetter;
} // anonymous namespace
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);
}
sc_time::sc_time(const sc_time &t)
{
val = t.val;
}
sc_time::sc_time(double d, bool scale)
{
//XXX Assuming the time resolution is 1ps, and the default unit is 1ns.
set(this, d, scale ? SC_NS : SC_PS);
}
sc_time::sc_time(sc_dt::uint64 v, bool scale)
{
//XXX Assuming the time resolution is 1ps, and the default unit is 1ns.
set(this, static_cast<double>(v), scale ? SC_NS : SC_PS);
}
sc_time &
sc_time::operator = (const sc_time &t)
{
val = t.val;
return *this;
}
sc_dt::uint64
sc_time::value() const
{
return val;
}
double
sc_time::to_double() const
{
return static_cast<double>(val);
}
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;
}
const std::string
sc_time::to_string() const
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return "";
}
bool
sc_time::operator == (const sc_time &t) const
{
return val == t.val;
}
bool
sc_time::operator != (const sc_time &t) const
{
return val != t.val;
}
bool
sc_time::operator < (const sc_time &t) const
{
return val < t.val;
}
bool
sc_time::operator <= (const sc_time &t) const
{
return val <= t.val;
}
bool
sc_time::operator > (const sc_time &t) const
{
return val > t.val;
}
bool
sc_time::operator >= (const sc_time &t) const
{
return val >= t.val;
}
sc_time &
sc_time::operator += (const sc_time &t)
{
val += t.val;
return *this;
}
sc_time &
sc_time::operator -= (const sc_time &t)
{
val -= t.val;
return *this;
}
sc_time &
sc_time::operator *= (double d)
{
val = static_cast<int64_t>(static_cast<double>(val) * d + 0.5);
return *this;
}
sc_time &
sc_time::operator /= (double d)
{
val = static_cast<int64_t>(static_cast<double>(val) / d + 0.5);
return *this;
}
void
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;
while (tu < SC_SEC && (scaled % 1000) == 0) {
tu = (sc_time_unit)((int)tu + 1);
scaled /= 1000;
}
os << scaled << ' ' << TimeUnitNames[tu];
}
}
sc_time
sc_time::from_value(sc_dt::uint64 u)
{
sc_time t;
t.val = u;
return t;
}
sc_time
sc_time::from_seconds(double d)
{
sc_time t;
set(&t, d, SC_SEC);
return t;
}
sc_time
sc_time::from_string(const char *str)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return sc_time();
}
const sc_time
operator + (const sc_time &a, const sc_time &b)
{
return sc_time::from_value(a.value() + b.value());
}
const sc_time
operator - (const sc_time &a, const sc_time &b)
{
return sc_time::from_value(a.value() - b.value());
}
const sc_time
operator * (const sc_time &t, double d)
{
volatile double tmp = static_cast<double>(t.value()) * d + 0.5;
return sc_time::from_value(static_cast<int64_t>(tmp));
}
const sc_time
operator * (double d, const sc_time &t)
{
volatile double tmp = d * static_cast<double>(t.value()) + 0.5;
return sc_time::from_value(static_cast<int64_t>(tmp));
}
const sc_time
operator / (const sc_time &t, double d)
{
volatile double tmp = static_cast<double>(t.value()) / d + 0.5;
return sc_time::from_value(static_cast<int64_t>(tmp));
}
double
operator / (const sc_time &t1, const sc_time &t2)
{
return t1.to_double() / t2.to_double();
}
std::ostream &
operator << (std::ostream &os, const sc_time &t)
{
t.print(os);
return os;
}
const sc_time SC_ZERO_TIME;
void
sc_set_time_resolution(double, sc_time_unit)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
}
sc_time
sc_get_time_resolution()
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return sc_time();
}
const sc_time &
sc_max_time()
{
static const sc_time MaxScTime = sc_time::from_value(MaxTick);
return MaxScTime;
}
void
sc_set_default_time_unit(double, sc_time_unit)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
}
sc_time
sc_get_default_time_unit()
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return *(sc_time *)nullptr;
}
sc_time_tuple::sc_time_tuple(const sc_time &)
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
}
bool
sc_time_tuple::has_value() const
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return false;
}
sc_dt::uint64
sc_time_tuple::value() const
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return 0;
}
const char *
sc_time_tuple::unit_symbol() const
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return "";
}
double
sc_time_tuple::to_double() const
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return 0.0;
}
std::string
sc_time_tuple::to_string() const
{
warn("%s not implemented.\n", __PRETTY_FUNCTION__);
return "";
}
} // namespace sc_core