diff options
Diffstat (limited to 'src/systemc')
-rw-r--r-- | src/systemc/core/scheduler.cc | 22 | ||||
-rw-r--r-- | src/systemc/core/scheduler.hh | 20 | ||||
-rw-r--r-- | src/systemc/ext/channel/sc_in.hh | 77 | ||||
-rw-r--r-- | src/systemc/ext/channel/sc_inout.hh | 64 | ||||
-rw-r--r-- | src/systemc/ext/channel/sc_signal.hh | 16 | ||||
-rw-r--r-- | src/systemc/ext/core/sc_port.hh | 16 | ||||
-rw-r--r-- | src/systemc/ext/dt/fx/sc_fxnum.hh | 16 | ||||
-rw-r--r-- | src/systemc/ext/utils/sc_trace_file.hh | 5 | ||||
-rw-r--r-- | src/systemc/utils/SConscript | 2 | ||||
-rw-r--r-- | src/systemc/utils/sc_trace_file.cc | 315 | ||||
-rw-r--r-- | src/systemc/utils/tracefile.cc | 69 | ||||
-rw-r--r-- | src/systemc/utils/tracefile.hh | 279 | ||||
-rw-r--r-- | src/systemc/utils/vcd.cc | 703 | ||||
-rw-r--r-- | src/systemc/utils/vcd.hh | 154 |
14 files changed, 1579 insertions, 179 deletions
diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc index ae1aa899f..d79abb251 100644 --- a/src/systemc/core/scheduler.cc +++ b/src/systemc/core/scheduler.cc @@ -36,6 +36,7 @@ #include "systemc/ext/core/sc_main.hh" #include "systemc/ext/utils/sc_report.hh" #include "systemc/ext/utils/sc_report_handler.hh" +#include "systemc/utils/tracefile.hh" namespace sc_gem5 { @@ -48,8 +49,8 @@ Scheduler::Scheduler() : starvationEvent(this, false, StarvationPriority), _elaborationDone(false), _started(false), _stopNow(false), _status(StatusOther), maxTickEvent(this, false, MaxTickPriority), - _numCycles(0), _changeStamp(0), _current(nullptr), initDone(false), - runOnce(false) + timeAdvancesEvent(this, false, TimeAdvancesPriority), _numCycles(0), + _changeStamp(0), _current(nullptr), initDone(false), runOnce(false) {} Scheduler::~Scheduler() @@ -86,6 +87,8 @@ Scheduler::clear() deschedule(&starvationEvent); if (maxTickEvent.scheduled()) deschedule(&maxTickEvent); + if (timeAdvancesEvent.scheduled()) + deschedule(&timeAdvancesEvent); Process *p; while ((p = initList.getNext())) @@ -134,6 +137,8 @@ Scheduler::initPhase() initDone = true; status(StatusOther); + + scheduleTimeAdvancesEvent(); } void @@ -263,10 +268,13 @@ Scheduler::scheduleStarvationEvent() void Scheduler::runReady() { + scheduleTimeAdvancesEvent(); + bool empty = readyListMethods.empty() && readyListThreads.empty(); lastReadyTick = getCurTick(); // The evaluation phase. + status(StatusEvaluate); do { yield(); } while (getNextReady()); @@ -282,6 +290,8 @@ Scheduler::runReady() } runUpdate(); + if (!traceFiles.empty()) + trace(true); runDelta(); if (!runToTime && starved()) @@ -367,6 +377,7 @@ Scheduler::start(Tick max_tick, bool run_to_time) } schedule(&maxTickEvent, maxTick); + scheduleTimeAdvancesEvent(); // Return to gem5 to let it run events, etc. Fiber::primaryFiber()->run(); @@ -429,6 +440,13 @@ Scheduler::scheduleStop(bool finish_delta) schedule(&stopEvent); } +void +Scheduler::trace(bool delta) +{ + for (auto tf: traceFiles) + tf->trace(delta); +} + Scheduler scheduler; namespace { diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh index 8015260a3..ebe15462c 100644 --- a/src/systemc/core/scheduler.hh +++ b/src/systemc/core/scheduler.hh @@ -48,6 +48,8 @@ class Fiber; namespace sc_gem5 { +class TraceFile; + typedef NodeList<Process> ProcessList; typedef NodeList<Channel> ChannelList; @@ -280,6 +282,7 @@ class Scheduler timeSlots.erase(timeSlots.begin()); if (!runToTime && starved()) scheduleStarvationEvent(); + scheduleTimeAdvancesEvent(); } // Pending activity ignores gem5 activity, much like how a systemc @@ -357,6 +360,9 @@ class Scheduler Status status() { return _status; } void status(Status s) { _status = s; } + void registerTraceFile(TraceFile *tf) { traceFiles.insert(tf); } + void unregisterTraceFile(TraceFile *tf) { traceFiles.erase(tf); } + private: typedef const EventBase::Priority Priority; static Priority DefaultPriority = EventBase::Default_Pri; @@ -366,6 +372,7 @@ class Scheduler static Priority MaxTickPriority = DefaultPriority + 2; static Priority ReadyPriority = DefaultPriority + 3; static Priority StarvationPriority = ReadyPriority; + static Priority TimeAdvancesPriority = EventBase::Maximum_Pri; EventQueue *eq; @@ -440,6 +447,15 @@ class Scheduler } EventWrapper<Scheduler, &Scheduler::maxTickFunc> maxTickEvent; + void timeAdvances() { trace(false); } + EventWrapper<Scheduler, &Scheduler::timeAdvances> timeAdvancesEvent; + void + scheduleTimeAdvancesEvent() + { + if (!traceFiles.empty() && !timeAdvancesEvent.scheduled()) + schedule(&timeAdvancesEvent); + } + uint64_t _numCycles; uint64_t _changeStamp; @@ -457,6 +473,10 @@ class Scheduler ChannelList updateList; std::map<::Event *, Tick> eventsToSchedule; + + std::set<TraceFile *> traceFiles; + + void trace(bool delta); }; extern Scheduler scheduler; diff --git a/src/systemc/ext/channel/sc_in.hh b/src/systemc/ext/channel/sc_in.hh index b7170aed3..a76840161 100644 --- a/src/systemc/ext/channel/sc_in.hh +++ b/src/systemc/ext/channel/sc_in.hh @@ -34,9 +34,9 @@ #include "../core/sc_event.hh" #include "../core/sc_port.hh" +#include "../utils/sc_trace_file.hh" #include "sc_signal_in_if.hh" #include "sc_signal_inout_if.hh" -#include "warn_unimpl.hh" namespace sc_core { @@ -112,7 +112,14 @@ class sc_in : public sc_port<sc_signal_in_if<T>, 1> bind(p); } - virtual void end_of_elaboration() { /* Implementation defined. */ } + virtual void + end_of_elaboration() + { + for (auto params: traceParamsVec) + sc_trace(params->tf, (*this)->read(), params->name); + + traceParamsVec.clear(); + } const T &read() const { return (*this)->read(); } operator const T& () const { return (*this)->read(); } @@ -128,9 +135,17 @@ class sc_in : public sc_port<sc_signal_in_if<T>, 1> virtual const char *kind() const { return "sc_in"; } + void + add_trace(sc_trace_file *tf, const std::string &name) const + { + traceParamsVec.push_back(new sc_trace_params(tf, name)); + } + private: mutable sc_event_finder_t<sc_signal_in_if<T> > _valueChangedFinder; + mutable sc_trace_params_vec traceParamsVec; + // Disabled sc_in(const sc_in<T> &); sc_in<T> &operator = (const sc_in<T> &); @@ -138,9 +153,12 @@ class sc_in : public sc_port<sc_signal_in_if<T>, 1> template <class T> inline void -sc_trace(sc_trace_file *, const sc_in<T> &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_in<T> &i, const std::string &name) { - sc_channel_warn_unimpl(__PRETTY_FUNCTION__); + if (i.size()) + sc_trace(tf, i->read(), name); + else + i.add_trace(tf, name); } template <> @@ -236,7 +254,14 @@ class sc_in<bool> : public sc_port<sc_signal_in_if<bool>, 1> bind(p); } - virtual void end_of_elaboration() { /* Implementation defined. */ } + virtual void + end_of_elaboration() + { + for (auto params: traceParamsVec) + sc_trace(params->tf, (*this)->read(), params->name); + + traceParamsVec.clear(); + } const bool &read() const { return (*this)->read(); } operator const bool& () const { return (*this)->read(); } @@ -268,11 +293,19 @@ class sc_in<bool> : public sc_port<sc_signal_in_if<bool>, 1> virtual const char *kind() const { return "sc_in"; } + void + add_trace(sc_trace_file *tf, const std::string &name) const + { + traceParamsVec.push_back(new sc_trace_params(tf, name)); + } + private: mutable sc_event_finder_t<sc_signal_in_if<bool> > _valueChangedFinder; mutable sc_event_finder_t<sc_signal_in_if<bool> > _posFinder; mutable sc_event_finder_t<sc_signal_in_if<bool> > _negFinder; + mutable sc_trace_params_vec traceParamsVec; + // Disabled sc_in(const sc_in<bool> &); sc_in<bool> &operator = (const sc_in<bool> &); @@ -280,9 +313,13 @@ class sc_in<bool> : public sc_port<sc_signal_in_if<bool>, 1> template <> inline void -sc_trace<bool>(sc_trace_file *, const sc_in<bool> &, const std::string &) +sc_trace<bool>(sc_trace_file *tf, const sc_in<bool> &i, + const std::string &name) { - sc_channel_warn_unimpl(__PRETTY_FUNCTION__); + if (i.size()) + sc_trace(tf, i->read(), name); + else + i.add_trace(tf, name); } template <> @@ -383,7 +420,14 @@ class sc_in<sc_dt::sc_logic> : bind(p); } - virtual void end_of_elaboration() { /* Implementation defined. */ } + virtual void + end_of_elaboration() + { + for (auto params: traceParamsVec) + sc_trace(params->tf, (*this)->read(), params->name); + + traceParamsVec.clear(); + } const sc_dt::sc_logic &read() const { return (*this)->read(); } operator const sc_dt::sc_logic& () const { return (*this)->read(); } @@ -407,12 +451,20 @@ class sc_in<sc_dt::sc_logic> : virtual const char *kind() const { return "sc_in"; } + void + add_trace(sc_trace_file *tf, const std::string &name) const + { + traceParamsVec.push_back(new sc_trace_params(tf, name)); + } + private: mutable sc_event_finder_t<sc_signal_in_if<sc_dt::sc_logic> > _valueChangedFinder; mutable sc_event_finder_t<sc_signal_in_if<sc_dt::sc_logic> > _posFinder; mutable sc_event_finder_t<sc_signal_in_if<sc_dt::sc_logic> > _negFinder; + mutable sc_trace_params_vec traceParamsVec; + // Disabled sc_in(const sc_in<sc_dt::sc_logic> &); sc_in<sc_dt::sc_logic> &operator = (const sc_in<sc_dt::sc_logic> &); @@ -420,10 +472,13 @@ class sc_in<sc_dt::sc_logic> : template <> inline void -sc_trace<sc_dt::sc_logic>( - sc_trace_file *, const sc_in<sc_dt::sc_logic> &, const std::string &) +sc_trace<sc_dt::sc_logic>(sc_trace_file *tf, const sc_in<sc_dt::sc_logic> &i, + const std::string &name) { - sc_channel_warn_unimpl(__PRETTY_FUNCTION__); + if (i.size()) + sc_trace(tf, i->read(), name); + else + i.add_trace(tf, name); } } // namespace sc_core diff --git a/src/systemc/ext/channel/sc_inout.hh b/src/systemc/ext/channel/sc_inout.hh index 54b0ae7da..7f19443d5 100644 --- a/src/systemc/ext/channel/sc_inout.hh +++ b/src/systemc/ext/channel/sc_inout.hh @@ -35,8 +35,8 @@ #include "../core/sc_event.hh" #include "../core/sc_port.hh" #include "../dt/bit/sc_logic.hh" +#include "../utils/sc_trace_file.hh" #include "sc_signal_inout_if.hh" -#include "warn_unimpl.hh" namespace sc_dt { @@ -111,6 +111,11 @@ class sc_inout : public sc_port<sc_signal_inout_if<T>, 1> delete initValue; initValue = nullptr; } + + for (auto params: traceParamsVec) + sc_trace(params->tf, (*this)->read(), params->name); + + traceParamsVec.clear(); } const T &read() const { return (*this)->read(); } @@ -159,19 +164,30 @@ class sc_inout : public sc_port<sc_signal_inout_if<T>, 1> virtual const char *kind() const { return "sc_inout"; } + void + add_trace(sc_trace_file *tf, const std::string &name) const + { + traceParamsVec.push_back(new sc_trace_params(tf, name)); + } + private: T *initValue; mutable sc_event_finder_t<sc_signal_inout_if<T> > _valueChangedFinder; + mutable sc_trace_params_vec traceParamsVec; + // Disabled sc_inout(const sc_inout<T> &); }; template <class T> inline void -sc_trace(sc_trace_file *, const sc_inout<T> &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_inout<T> &i, const std::string &name) { - sc_channel_warn_unimpl(__PRETTY_FUNCTION__); + if (i.size()) + sc_trace(tf, i->read(), name); + else + i.add_trace(tf, name); } template <> @@ -259,6 +275,11 @@ class sc_inout<bool> : public sc_port<sc_signal_inout_if<bool>, 1> delete initValue; initValue = nullptr; } + + for (auto params: traceParamsVec) + sc_trace(params->tf, (*this)->read(), params->name); + + traceParamsVec.clear(); } const bool &read() const { return (*this)->read(); } @@ -314,21 +335,32 @@ class sc_inout<bool> : public sc_port<sc_signal_inout_if<bool>, 1> virtual const char *kind() const { return "sc_inout"; } + void + add_trace(sc_trace_file *tf, const std::string &name) const + { + traceParamsVec.push_back(new sc_trace_params(tf, name)); + } + private: bool *initValue; mutable sc_event_finder_t<sc_signal_inout_if<bool> > _valueChangedFinder; mutable sc_event_finder_t<sc_signal_inout_if<bool> > _posFinder; mutable sc_event_finder_t<sc_signal_inout_if<bool> > _negFinder; + mutable sc_trace_params_vec traceParamsVec; + // Disabled sc_inout(const sc_inout<bool> &); }; template <> inline void sc_trace<bool>( - sc_trace_file *, const sc_inout<bool> &, const std::string &) + sc_trace_file *tf, const sc_inout<bool> &i, const std::string &name) { - sc_channel_warn_unimpl(__PRETTY_FUNCTION__); + if (i.size()) + sc_trace(tf, i->read(), name); + else + i.add_trace(tf, name); } template <> @@ -433,6 +465,11 @@ class sc_inout<sc_dt::sc_logic> : delete initValue; initValue = nullptr; } + + for (auto params: traceParamsVec) + sc_trace(params->tf, (*this)->read(), params->name); + + traceParamsVec.clear(); } const sc_dt::sc_logic &read() const { return (*this)->read(); } @@ -488,6 +525,12 @@ class sc_inout<sc_dt::sc_logic> : virtual const char *kind() const { return "sc_inout"; } + void + add_trace(sc_trace_file *tf, const std::string &name) const + { + traceParamsVec.push_back(new sc_trace_params(tf, name)); + } + private: sc_dt::sc_logic *initValue; mutable sc_event_finder_t< @@ -495,16 +538,21 @@ class sc_inout<sc_dt::sc_logic> : mutable sc_event_finder_t<sc_signal_inout_if<sc_dt::sc_logic> > _posFinder; mutable sc_event_finder_t<sc_signal_inout_if<sc_dt::sc_logic> > _negFinder; + mutable sc_trace_params_vec traceParamsVec; + // Disabled sc_inout(const sc_inout<sc_dt::sc_logic> &); }; template <> inline void -sc_trace<sc_dt::sc_logic>(sc_trace_file *, const sc_inout<sc_dt::sc_logic> &, - const std::string &) +sc_trace<sc_dt::sc_logic>(sc_trace_file *tf, + const sc_inout<sc_dt::sc_logic> &i, const std::string &name) { - sc_channel_warn_unimpl(__PRETTY_FUNCTION__); + if (i.size()) + sc_trace(tf, i->read(), name); + else + i.add_trace(tf, name); } } // namespace sc_core diff --git a/src/systemc/ext/channel/sc_signal.hh b/src/systemc/ext/channel/sc_signal.hh index bbe2d0116..7c0183763 100644 --- a/src/systemc/ext/channel/sc_signal.hh +++ b/src/systemc/ext/channel/sc_signal.hh @@ -45,22 +45,6 @@ namespace sc_core { class sc_port_base; -class sc_trace_file; - -// Nonstandard -// Despite having a warning "FOR INTERNAL USE ONLY!" in all caps above this -// class definition in the Accellera implementation, it appears in their -// examples and test programs, and so we need to have it here as well. -struct sc_trace_params -{ - sc_trace_file *tf; - std::string name; - - sc_trace_params(sc_trace_file *tf, const std::string &name) : - tf(tf), name(name) - {} -}; -typedef std::vector<sc_trace_params *> sc_trace_params_vec; template <class T, sc_writer_policy WRITER_POLICY=SC_ONE_WRITER> class sc_signal : public sc_signal_inout_if<T>, diff --git a/src/systemc/ext/core/sc_port.hh b/src/systemc/ext/core/sc_port.hh index c9d436ec3..3586fec73 100644 --- a/src/systemc/ext/core/sc_port.hh +++ b/src/systemc/ext/core/sc_port.hh @@ -47,6 +47,22 @@ namespace sc_core { class sc_interface; +class sc_trace_file; + +// Nonstandard +// Despite having a warning "FOR INTERNAL USE ONLY!" in all caps above this +// class definition in the Accellera implementation, it appears in their +// examples and test programs, and so we need to have it here as well. +struct sc_trace_params +{ + sc_trace_file *tf; + std::string name; + + sc_trace_params(sc_trace_file *tf, const std::string &name) : + tf(tf), name(name) + {} +}; +typedef std::vector<sc_trace_params *> sc_trace_params_vec; enum sc_port_policy { diff --git a/src/systemc/ext/dt/fx/sc_fxnum.hh b/src/systemc/ext/dt/fx/sc_fxnum.hh index 1138646f3..8a0b7f612 100644 --- a/src/systemc/ext/dt/fx/sc_fxnum.hh +++ b/src/systemc/ext/dt/fx/sc_fxnum.hh @@ -66,13 +66,11 @@ #include "sc_fxval.hh" #include "scfx_params.hh" -namespace sc_core +namespace sc_gem5 { -class vcd_sc_fxnum_trace; -class vcd_sc_fxnum_fast_trace; -class wif_sc_fxnum_trace; -class wif_sc_fxnum_fast_trace; +template <typename T, typename B> +class TraceValFxnumBase; } // namespace sc_core @@ -490,8 +488,8 @@ class sc_fxnum friend class sc_fxnum_fast_bitref; friend class sc_fxnum_fast_subref; - friend class sc_core::vcd_sc_fxnum_trace; - friend class sc_core::wif_sc_fxnum_trace; + template <typename T, typename B> + friend class sc_gem5::TraceValFxnumBase; protected: sc_fxnum_observer *observer() const; @@ -851,8 +849,8 @@ class sc_fxnum_fast friend class sc_fxnum_fast_bitref; friend class sc_fxnum_fast_subref; - friend class sc_core::vcd_sc_fxnum_fast_trace; - friend class sc_core::wif_sc_fxnum_fast_trace; + template <typename T, typename B> + friend class sc_gem5::TraceValFxnumBase; protected: sc_fxnum_fast_observer *observer() const; diff --git a/src/systemc/ext/utils/sc_trace_file.hh b/src/systemc/ext/utils/sc_trace_file.hh index 0b4b0d02b..09f5bb254 100644 --- a/src/systemc/ext/utils/sc_trace_file.hh +++ b/src/systemc/ext/utils/sc_trace_file.hh @@ -63,7 +63,12 @@ class sc_time; class sc_trace_file { + protected: + sc_trace_file(); + public: + virtual ~sc_trace_file(); + virtual void set_time_unit(double, sc_time_unit) = 0; }; diff --git a/src/systemc/utils/SConscript b/src/systemc/utils/SConscript index f925293ac..5aaea544d 100644 --- a/src/systemc/utils/SConscript +++ b/src/systemc/utils/SConscript @@ -33,4 +33,6 @@ if env['USE_SYSTEMC']: Source('sc_report_handler.cc') Source('sc_trace_file.cc') Source('sc_vector.cc') + Source('tracefile.cc') + Source('vcd.cc') Source('warn_unimpl.cc') diff --git a/src/systemc/utils/sc_trace_file.cc b/src/systemc/utils/sc_trace_file.cc index 2ac702daa..cc9ceef37 100644 --- a/src/systemc/utils/sc_trace_file.cc +++ b/src/systemc/utils/sc_trace_file.cc @@ -27,390 +27,439 @@ * Authors: Gabe Black */ +#include <vector> + #include "base/logging.hh" +#include "systemc/core/scheduler.hh" +#include "systemc/ext/channel/sc_signal_in_if.hh" +#include "systemc/ext/core/sc_event.hh" +#include "systemc/ext/core/sc_time.hh" +#include "systemc/ext/dt/bit/sc_bv_base.hh" +#include "systemc/ext/dt/bit/sc_logic.hh" +#include "systemc/ext/dt/bit/sc_lv_base.hh" +#include "systemc/ext/dt/fx/sc_fxnum.hh" +#include "systemc/ext/dt/fx/sc_fxval.hh" +#include "systemc/ext/dt/int/sc_int_base.hh" +#include "systemc/ext/dt/int/sc_signed.hh" +#include "systemc/ext/dt/int/sc_uint_base.hh" +#include "systemc/ext/dt/int/sc_unsigned.hh" #include "systemc/ext/utils/sc_trace_file.hh" +#include "systemc/utils/vcd.hh" namespace sc_core { +sc_trace_file::sc_trace_file() {} +sc_trace_file::~sc_trace_file() {} + sc_trace_file * sc_create_vcd_trace_file(const char *name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); - return nullptr; + auto tf = new ::sc_gem5::VcdTraceFile(name); + ::sc_gem5::scheduler.registerTraceFile(tf); + return tf; } void sc_close_vcd_trace_file(sc_trace_file *tf) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_gem5::scheduler.unregisterTraceFile( + static_cast<::sc_gem5::TraceFile *>(tf)); + delete tf; } void sc_write_comment(sc_trace_file *tf, const std::string &comment) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->writeComment(comment); } void -sc_trace(sc_trace_file *, const bool &, const std::string &) +sc_trace(sc_trace_file *tf, const bool &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const bool *, const std::string &) +sc_trace(sc_trace_file *tf, const bool *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const float &, const std::string &) +sc_trace(sc_trace_file *tf, const float &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const float *, const std::string &) +sc_trace(sc_trace_file *tf, const float *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const double &, const std::string &) +sc_trace(sc_trace_file *tf, const double &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const double *, const std::string &) +sc_trace(sc_trace_file *tf, const double *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_logic &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_logic &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_logic *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_logic *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_int_base &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_int_base &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_int_base *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_int_base *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_uint_base &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_uint_base &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_uint_base *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_uint_base *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_signed &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_signed &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_signed *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_signed *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_unsigned &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_unsigned &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_unsigned *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_unsigned *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_bv_base &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_bv_base &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_bv_base *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_bv_base *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_lv_base &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_lv_base &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_lv_base *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_lv_base *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxval &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxval &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxval *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxval *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxval_fast &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxval_fast &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxval_fast *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxval_fast *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxnum &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxnum &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxnum *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxnum *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxnum_fast &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxnum_fast &v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_dt::sc_fxnum_fast *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_dt::sc_fxnum_fast *v, + const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_event &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_event &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_event *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_event *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const sc_time &, const std::string &) +sc_trace(sc_trace_file *tf, const sc_time &v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name); } void -sc_trace(sc_trace_file *, const sc_time *, const std::string &) +sc_trace(sc_trace_file *tf, const sc_time *v, const std::string &name) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name); } void -sc_trace(sc_trace_file *, const unsigned char &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned char &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const unsigned char *, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned char *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const unsigned short &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned short &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const unsigned short *, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned short *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const unsigned int &, const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned int &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const unsigned int *, const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned int *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const unsigned long &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned long &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const unsigned long *, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const unsigned long *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const char &, const std::string &, int width) +sc_trace(sc_trace_file *tf, const char &v, const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const char *, const std::string &, int width) +sc_trace(sc_trace_file *tf, const char *v, const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const short &, const std::string &, int width) +sc_trace(sc_trace_file *tf, const short &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const short *, const std::string &, int width) +sc_trace(sc_trace_file *tf, const short *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const int &, const std::string &, int width) +sc_trace(sc_trace_file *tf, const int &v, const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const int *, const std::string &, int width) +sc_trace(sc_trace_file *tf, const int *v, const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const long &, const std::string &, int width) +sc_trace(sc_trace_file *tf, const long &v, const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const long *, const std::string &, int width) +sc_trace(sc_trace_file *tf, const long *v, const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const sc_dt::int64 &, const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_dt::int64 &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const sc_dt::int64 *, const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_dt::int64 *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const sc_dt::uint64 &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_dt::uint64 &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(&v, name, width); } void -sc_trace(sc_trace_file *, const sc_dt::uint64 *, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_dt::uint64 *v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->addTraceVal(v, name, width); } void -sc_trace(sc_trace_file *, const sc_signal_in_if<char> &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_signal_in_if<char> &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)-> + addTraceVal(&v.read(), name, width); } void -sc_trace(sc_trace_file *, const sc_signal_in_if<short> &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_signal_in_if<short> &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)-> + addTraceVal(&v.read(), name, width); } void -sc_trace(sc_trace_file *, const sc_signal_in_if<int> &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_signal_in_if<int> &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)-> + addTraceVal(&v.read(), name, width); } void -sc_trace(sc_trace_file *, const sc_signal_in_if<long> &, - const std::string &, int width) +sc_trace(sc_trace_file *tf, const sc_signal_in_if<long> &v, + const std::string &name, int width) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)-> + addTraceVal(&v.read(), name, width); } void -sc_trace(sc_trace_file *, const unsigned int &, - const std::string &, const char **enum_literals) +sc_trace(sc_trace_file *tf, const unsigned int &v, + const std::string &name, const char **enum_literals) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)-> + addTraceVal(&v, name, enum_literals); } void -sc_trace_delta_cycles(sc_trace_file *, bool on) +sc_trace_delta_cycles(sc_trace_file *tf, bool on) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + static_cast<::sc_gem5::TraceFile *>(tf)->traceDeltas(on); } } // namespace sc_core diff --git a/src/systemc/utils/tracefile.cc b/src/systemc/utils/tracefile.cc new file mode 100644 index 000000000..20091c307 --- /dev/null +++ b/src/systemc/utils/tracefile.cc @@ -0,0 +1,69 @@ +/* + * 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 "systemc/utils/tracefile.hh" + +#include <ctime> +#include <iomanip> + +#include "base/logging.hh" +#include "base/output.hh" +#include "sim/core.hh" +#include "systemc/ext/core/sc_main.hh" +#include "systemc/ext/utils/functions.hh" + +namespace sc_gem5 +{ + +TraceFile::TraceFile(const std::string &name) : + _os(simout.create(name, true, true)), timeUnitTicks(0), + timeUnitValue(1.0), timeUnitUnit(::sc_core::SC_PS), _traceDeltas(false) +{} + +TraceFile::~TraceFile() +{ + simout.close(_os); +} + +std::ostream &TraceFile::stream() { return *_os->stream(); } + +void +TraceFile::set_time_unit(double d, ::sc_core::sc_time_unit tu) +{ + timeUnitValue = d; + timeUnitUnit = tu; +} + +void +TraceFile::finalizeTime() +{ + timeUnitTicks = ::sc_core::sc_time(timeUnitValue, timeUnitUnit).value(); +} + +} // namespace sc_gem5 diff --git a/src/systemc/utils/tracefile.hh b/src/systemc/utils/tracefile.hh new file mode 100644 index 000000000..8e751e4ec --- /dev/null +++ b/src/systemc/utils/tracefile.hh @@ -0,0 +1,279 @@ +/* + * 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 + */ + +#ifndef __SYSTEMC_UTILS_TRACEFILE_HH__ +#define __SYSTEMC_UTILS_TRACEFILE_HH__ + +#include <iostream> +#include <string> +#include <vector> + +#include "systemc/core/event.hh" +#include "systemc/ext/channel/sc_signal_in_if.hh" +#include "systemc/ext/core/sc_event.hh" +#include "systemc/ext/dt/fx/sc_fxnum.hh" +#include "systemc/ext/utils/sc_trace_file.hh" + +class OutputStream; + +namespace sc_gem5 +{ + +class TraceValBase +{ + protected: + int _width; + + public: + TraceValBase(int _width) : _width(_width) {} + virtual ~TraceValBase() {} + + int width() { return _width; } + + virtual void finalize() {}; + virtual bool check() = 0; +}; + +template <typename T, typename Base=TraceValBase> +class TraceVal : public Base +{ + private: + const T *t; + T oldVal; + + public: + TraceVal(const T *_t, int _width) : Base(_width), t(_t), oldVal(*t) + {} + ~TraceVal() {} + + void finalize() override { oldVal = *t; } + const T &value() { return oldVal; } + + bool + check() override + { + bool changed = (*t != oldVal); + oldVal = *t; + return changed; + } +}; + +template <typename T, typename Base> +class TraceVal<::sc_core::sc_signal_in_if<T>, Base> : public Base +{ + private: + const ::sc_core::sc_signal_in_if<T> *iface; + T oldVal; + + public: + TraceVal(const ::sc_core::sc_signal_in_if<T> *_iface, int _width) : + Base(_width), iface(_iface), oldVal(iface->read()) + {} + ~TraceVal() {} + + void finalize() override { oldVal = iface->read(); } + const T &value() { return oldVal; } + + bool + check() override + { + T newVal = iface->read(); + bool changed = (newVal != oldVal); + oldVal = newVal; + return changed; + } +}; + +template <typename Base> +class TraceVal<::sc_core::sc_event, Base> : public Base +{ + private: + bool triggered; + uint64_t oldStamp; + const Event *event; + + public: + TraceVal(const ::sc_core::sc_event *_event, int _width) : + Base(_width), triggered(false), oldStamp(0), + event(Event::getFromScEvent(_event)) + {} + ~TraceVal() {} + + bool value() { return triggered; } + void finalize() override { oldStamp = event->triggeredStamp(); } + + bool + check() override + { + uint64_t newStamp = event->triggeredStamp(); + triggered = (oldStamp != newStamp); + oldStamp = newStamp; + return triggered; + } +}; + +template <typename T, typename Base> +class TraceValFxnumBase : public Base +{ + private: + const T *t; + T oldVal; + + public: + TraceValFxnumBase(const T *_t, int _width) : + Base(_width), t(_t), + oldVal(_t->m_params.type_params(), _t->m_params.enc(), + _t->m_params.cast_switch(), 0) + {} + ~TraceValFxnumBase() {} + + void + finalize() override + { + oldVal = *t; + this->_width = t->wl(); + } + + const T &value() { return oldVal; } + + bool + check() override + { + bool changed = (*t != oldVal); + oldVal = *t; + return changed; + } +}; + +template <typename Base> +class TraceVal<::sc_dt::sc_fxnum, Base> : + public TraceValFxnumBase<::sc_dt::sc_fxnum, Base> +{ + public: + using TraceValFxnumBase<::sc_dt::sc_fxnum, Base>::TraceValFxnumBase; + ~TraceVal() {} +}; + +template <typename Base> +class TraceVal<::sc_dt::sc_fxnum_fast, Base> : + public TraceValFxnumBase<::sc_dt::sc_fxnum_fast, Base> +{ + public: + using TraceValFxnumBase<::sc_dt::sc_fxnum_fast, Base>::TraceValFxnumBase; + ~TraceVal() {} +}; + +class TraceFile : public sc_core::sc_trace_file +{ + protected: + OutputStream *_os; + uint64_t timeUnitTicks; + double timeUnitValue; + ::sc_core::sc_time_unit timeUnitUnit; + + bool _traceDeltas; + + TraceFile(const std::string &name); + + std::ostream &stream(); + + public: + ~TraceFile(); + + void traceDeltas(bool on) { _traceDeltas = on; } + + void set_time_unit(double, ::sc_core::sc_time_unit) override; + void finalizeTime(); + + virtual void trace(bool delta) = 0; + + virtual void addTraceVal(const bool *v, const std::string &name) = 0; + virtual void addTraceVal(const float *v, const std::string &name) = 0; + virtual void addTraceVal(const double *v, const std::string &name) = 0; + + virtual void addTraceVal(const sc_dt::sc_logic *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_int_base *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_uint_base *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_signed *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_unsigned *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_bv_base *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_lv_base *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_fxval *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_fxval_fast *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_fxnum *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_dt::sc_fxnum_fast *v, + const std::string &name) = 0; + + virtual void addTraceVal(const sc_core::sc_event *v, + const std::string &name) = 0; + virtual void addTraceVal(const sc_core::sc_time *v, + const std::string &name) = 0; + + virtual void addTraceVal(const unsigned char *v, + const std::string &name, int width) = 0; + virtual void addTraceVal(const char *v, const std::string &name, + int width) = 0; + virtual void addTraceVal(const unsigned short *v, + const std::string &name, int width) = 0; + virtual void addTraceVal(const short *v, const std::string &name, + int width) = 0; + virtual void addTraceVal(const unsigned int *v, + const std::string &name, int width) = 0; + virtual void addTraceVal(const int *v, const std::string &name, + int width) = 0; + virtual void addTraceVal(const unsigned long *v, + const std::string &name, int width) = 0; + virtual void addTraceVal(const long *v, const std::string &name, + int width) = 0; + + virtual void addTraceVal(const sc_dt::int64 *v, + const std::string &name, int width) = 0; + virtual void addTraceVal(const sc_dt::uint64 *v, + const std::string &name, int width) = 0; + + virtual void addTraceVal(const unsigned int *, + const std::string &name, + const char **literals) = 0; + + virtual void writeComment(const std::string &comment) = 0; +}; + +} // namespace sc_gem5 + +#endif // __SYSTEMC_UTILS_TRACEFILE_HH__ diff --git a/src/systemc/utils/vcd.cc b/src/systemc/utils/vcd.cc new file mode 100644 index 000000000..83e6b50e8 --- /dev/null +++ b/src/systemc/utils/vcd.cc @@ -0,0 +1,703 @@ +/* + * 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 "systemc/utils/vcd.hh" + +#include <ctime> +#include <iomanip> + +#include "base/bitfield.hh" +#include "base/cprintf.hh" +#include "base/logging.hh" +#include "systemc/core/scheduler.hh" +#include "systemc/ext/core/sc_event.hh" +#include "systemc/ext/core/sc_main.hh" +#include "systemc/ext/core/sc_time.hh" +#include "systemc/ext/dt/bit/sc_bv_base.hh" +#include "systemc/ext/dt/bit/sc_logic.hh" +#include "systemc/ext/dt/bit/sc_lv_base.hh" +#include "systemc/ext/dt/fx/sc_fxnum.hh" +#include "systemc/ext/dt/fx/sc_fxval.hh" +#include "systemc/ext/dt/int/sc_int_base.hh" +#include "systemc/ext/dt/int/sc_signed.hh" +#include "systemc/ext/dt/int/sc_uint_base.hh" +#include "systemc/ext/dt/int/sc_unsigned.hh" +#include "systemc/ext/utils/functions.hh" + +namespace sc_gem5 +{ + +namespace +{ + +std::string +cleanName(std::string name) +{ + for (int i = 0; i < name.length(); i++) { + if (name[i] == '[') + name[i] = '('; + else if (name[i] == ']') + name[i] = ')'; + } + return name; +} + +} // anonymous namespace + +class VcdTraceValBase : public TraceValBase +{ + protected: + std::string _vcdName; + + const char * + stripLeadingBits(const char *orig) + { + const char first = orig[0]; + + if (first != 'z' && first != 'x' && first != '0') + return orig; + + const char *res = orig; + while (*++res == first) {} + + if (first != '0' || *res != '1') + res--; + + return res; + } + + char + scLogicToVcdState(char in) + { + switch (in) { + case 'U': + case 'X': + case 'W': + case 'D': + return 'x'; + case '0': + case 'L': + return '0'; + case '1': + case 'H': + return '1'; + case 'Z': + return 'z'; + default: + return '?'; + } + } + + void + printVal(std::ostream &os, const std::string &rep) + { + switch (width()) { + case 0: + return; + case 1: + os << rep << vcdName() << std::endl;; + return; + default: + os << "b" << stripLeadingBits(rep.c_str()) << " " << + vcdName() << std::endl; + return; + } + } + + public: + VcdTraceValBase(int width) : TraceValBase(width) {} + ~VcdTraceValBase() {} + + void vcdName(const std::string &vcd_name) { _vcdName = vcd_name; } + const std::string &vcdName() { return _vcdName; } + virtual std::string vcdType() { return "wire"; } + + virtual void output(std::ostream &os) = 0; +}; + +void +VcdTraceScope::addValue(const std::string &name, VcdTraceValBase *value) +{ + size_t pos = name.find_first_of('.'); + if (pos == std::string::npos) { + values.emplace_back(name, value); + } else { + std::string sname = name.substr(0, pos); + auto it = scopes.find(sname); + if (it == scopes.end()) + it = scopes.emplace(sname, new VcdTraceScope).first; + it->second->addValue(name.substr(pos + 1), value); + } +} + +void +VcdTraceScope::output(const std::string &name, std::ostream &os) +{ + os << "$scope module " << name << " $end" << std::endl; + + for (auto &p: values) { + const std::string &name = p.first; + VcdTraceValBase *value = p.second; + + int w = value->width(); + if (w <= 0) { + std::string msg = csprintf("'%s' has 0 bits", name); + // The typo in this error message is intentional to match the + // Accellera output. + SC_REPORT_ERROR("(E710) object cannot not be traced", msg.c_str()); + return; + } + + std::string clean_name = cleanName(name); + if (w == 1) { + ccprintf(os, "$var %s % 3d %s %s $end\n", + value->vcdType(), w, value->vcdName(), clean_name); + } else { + ccprintf(os, "$var %s % 3d %s %s [%d:0] $end\n", + value->vcdType(), w, value->vcdName(), clean_name, w - 1); + } + } + + for (auto &p: scopes) + p.second->output(p.first, os); + + os << "$upscope $end" << std::endl; +} + +template <typename T> +class VcdTraceVal : public TraceVal<T, VcdTraceValBase> +{ + public: + typedef T TracedType; + + VcdTraceVal(const T* t, const std::string &vcd_name, int width) : + TraceVal<T, VcdTraceValBase>(t, width) + { + this->vcdName(vcd_name); + } +}; + +std::string +VcdTraceFile::nextSignalName() +{ + std::string name(_nextName); + + bool carry = false; + int pos = NextNameChars - 1; + do { + carry = (_nextName[pos] == 'z'); + if (carry) + _nextName[pos--] = 'a'; + else + _nextName[pos--]++; + } while (carry && pos >= 0); + + return name; +} + +void +VcdTraceFile::initialize() +{ + finalizeTime(); + + // Date. + stream() << "$date" << std::endl; + time_t long_time; + time(&long_time); + struct tm *p_tm = localtime(&long_time); + stream() << std::put_time(p_tm, " %b %d, %Y %H:%M:%S\n"); + stream() << "$end" << std::endl << std::endl; + + // Version. + stream() << "$version" << std::endl; + stream() << " " << ::sc_core::sc_version() << std::endl; + stream() << "$end" << std::endl << std::endl; + + // Timescale. + stream() << "$timescale" << std::endl; + stream() << " " << ::sc_core::sc_time::from_value(timeUnitTicks) << + std::endl; + stream() << "$end" << std::endl << std::endl; + + for (auto tv: traceVals) + tv->finalize(); + + topScope.output("SystemC", stream()); + + stream() << "$enddefinitions $end" << std::endl << std::endl; + + Tick now = scheduler.getCurTick(); + + std::string timedump_comment = + csprintf("All initial values are dumped below at time " + "%g sec = %g timescale units.", + static_cast<double>(now) / SimClock::Float::s, + static_cast<double>(now / timeUnitTicks)); + writeComment(timedump_comment); + + lastPrintedTime = now / timeUnitTicks; + + stream() << "$dumpvars" << std::endl; + for (auto tv: traceVals) + tv->output(stream()); + stream() << "$end" << std::endl << std::endl; + + initialized = true; +} + +VcdTraceFile::~VcdTraceFile() +{ + for (auto tv: traceVals) + delete tv; + traceVals.clear(); + + if (timeUnitTicks) + ccprintf(stream(), "#%u\n", scheduler.getCurTick() / timeUnitTicks); +} + +void +VcdTraceFile::trace(bool delta) +{ + if (!delta) + deltasAtNow = 0; + + uint64_t deltaOffset = deltasAtNow; + + if (delta) + deltaOffset = deltasAtNow++; + + if (_traceDeltas != delta) + return; + + if (!initialized) { + initialize(); + return; + } + + Tick now = scheduler.getCurTick() / timeUnitTicks + deltaOffset; + + if (now <= lastPrintedTime) { + // TODO warn about reversed time? + return; + } + + bool time_printed = false; + for (auto tv: traceVals) { + if (tv->check()) { + if (!time_printed) { + lastPrintedTime = now; + ccprintf(stream(), "#%u\n", now); + time_printed = true; + } + + tv->output(stream()); + } + } + if (time_printed) + stream() << std::endl; +} + +class VcdTraceValBool : public VcdTraceVal<bool> +{ + public: + using VcdTraceVal<bool>::VcdTraceVal; + + void + output(std::ostream &os) override + { + printVal(os, this->value() ? "1" : "0"); + } +}; + +void +VcdTraceFile::addTraceVal(const bool *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValBool>(v, name); +} + +template <typename T> +class VcdTraceValFloat : public VcdTraceVal<T> +{ + public: + using VcdTraceVal<T>::VcdTraceVal; + + std::string vcdType() override { return "real"; } + + void + output(std::ostream &os) override + { + ccprintf(os, "r%.16g %s\n", this->value(), this->vcdName()); + } +}; + +void +VcdTraceFile::addTraceVal(const float *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValFloat<float>>(v, name); +} +void +VcdTraceFile::addTraceVal(const double *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValFloat<double>>(v, name); +} + +class VcdTraceValScLogic : public VcdTraceVal<sc_dt::sc_logic> +{ + public: + using VcdTraceVal<sc_dt::sc_logic>::VcdTraceVal; + + void + output(std::ostream &os) override + { + char str[2] = { + scLogicToVcdState(value().to_char()), + '\0' + }; + printVal(os, str); + } +}; + +void +VcdTraceFile::addTraceVal(const sc_dt::sc_logic *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValScLogic>(v, name); +} + +template <typename T> +class VcdTraceValFinite : public VcdTraceVal<T> +{ + public: + using VcdTraceVal<T>::VcdTraceVal; + + void + finalize() override + { + VcdTraceVal<T>::finalize(); + this->_width = this->value().length(); + } + + void + output(std::ostream &os) override + { + std::string str; + const int w = this->width(); + + str.reserve(w); + for (int i = w - 1; i >= 0; i--) + str += this->value()[i].to_bool() ? '1' : '0'; + + this->printVal(os, str); + } +}; + +void +VcdTraceFile::addTraceVal(const sc_dt::sc_int_base *v, + const std::string &name) +{ + addNewTraceVal<VcdTraceValFinite<sc_dt::sc_int_base>>(v, name); +} +void +VcdTraceFile::addTraceVal(const sc_dt::sc_uint_base *v, + const std::string &name) +{ + addNewTraceVal<VcdTraceValFinite<sc_dt::sc_uint_base>>(v, name); +} + +void +VcdTraceFile::addTraceVal(const sc_dt::sc_signed *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValFinite<sc_dt::sc_signed>>(v, name); +} +void +VcdTraceFile::addTraceVal(const sc_dt::sc_unsigned *v, + const std::string &name) +{ + addNewTraceVal<VcdTraceValFinite<sc_dt::sc_unsigned>>(v, name); +} + +template <typename T> +class VcdTraceValLogic : public VcdTraceVal<T> +{ + public: + using VcdTraceVal<T>::VcdTraceVal; + + void + finalize() override + { + VcdTraceVal<T>::finalize(); + this->_width = this->value().length(); + } + + void + output(std::ostream &os) override + { + this->printVal(os, this->value().to_string()); + } +}; + +void +VcdTraceFile::addTraceVal(const sc_dt::sc_bv_base *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValLogic<::sc_dt::sc_bv_base>>(v, name); +} +void +VcdTraceFile::addTraceVal(const sc_dt::sc_lv_base *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValLogic<::sc_dt::sc_lv_base>>(v, name); +} + +template <typename T> +class VcdTraceValFxval : public VcdTraceVal<T> +{ + public: + using VcdTraceVal<T>::VcdTraceVal; + + std::string vcdType() override { return "real"; } + + void + output(std::ostream &os) override + { + ccprintf(os, "r%.16g %s\n", + this->value().to_double(), this->vcdName()); + } +}; + +void +VcdTraceFile::addTraceVal(const sc_dt::sc_fxval *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValFxval<sc_dt::sc_fxval>>(v, name); +} +void +VcdTraceFile::addTraceVal(const sc_dt::sc_fxval_fast *v, + const std::string &name) +{ + addNewTraceVal<VcdTraceValFxval<sc_dt::sc_fxval_fast>>(v, name); +} + +template <typename T> +class VcdTraceValFxnum : public VcdTraceVal<T> +{ + public: + using VcdTraceVal<T>::VcdTraceVal; + + void + output(std::ostream &os) override + { + std::string str; + const int w = this->width(); + + str.reserve(w); + for (int i = w - 1; i >= 0; i--) + str += this->value()[i] ? '1' : '0'; + + this->printVal(os, str); + } +}; + +void +VcdTraceFile::addTraceVal(const sc_dt::sc_fxnum *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValFxnum<::sc_dt::sc_fxnum>>(v, name); +} +void +VcdTraceFile::addTraceVal(const sc_dt::sc_fxnum_fast *v, + const std::string &name) +{ + addNewTraceVal<VcdTraceValFxnum<::sc_dt::sc_fxnum_fast>>(v, name); +} + +class VcdTraceValEvent : public VcdTraceVal<::sc_core::sc_event> +{ + public: + using VcdTraceVal<::sc_core::sc_event>::VcdTraceVal; + + std::string vcdType() override { return "event"; } + + void + output(std::ostream &os) override + { + if (value()) + printVal(os, "1"); + else + os << std::endl; + } +}; + +void +VcdTraceFile::addTraceVal(const sc_core::sc_event *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValEvent>(v, name); +} + +class VcdTraceValTime : public VcdTraceVal<::sc_core::sc_time> +{ + private: + static const int TimeWidth = 64; + + public: + using VcdTraceVal<::sc_core::sc_time>::VcdTraceVal; + + std::string vcdType() override { return "time"; } + + void + finalize() override + { + VcdTraceVal<::sc_core::sc_time>::finalize(); + _width = TimeWidth; + } + + void + output(std::ostream &os) override + { + char str[TimeWidth + 1]; + str[TimeWidth] = '\0'; + + const uint64_t val = value().value(); + for (int i = 0; i < TimeWidth; i++) + str[i] = ::bits(val, TimeWidth - i - 1) ? '1' : '0'; + + printVal(os, str); + } +}; +void +VcdTraceFile::addTraceVal(const sc_core::sc_time *v, const std::string &name) +{ + addNewTraceVal<VcdTraceValTime>(v, name); +} + +template <typename T> +class VcdTraceValInt : public VcdTraceVal<T> +{ + public: + using VcdTraceVal<T>::VcdTraceVal; + + void + output(std::ostream &os) override + { + const int w = this->width(); + char str[w + 1]; + str[w] = '\0'; + + const uint64_t val = + static_cast<uint64_t>(this->value()) & ::mask(sizeof(T) * 8); + + if (::mask(w) < val) { + for (int i = 0; i < w; i++) + str[i] = 'x'; + } else { + for (int i = 0; i < w; i++) + str[i] = ::bits(val, w - i - 1) ? '1' : '0'; + } + + this->printVal(os, str); + } +}; + +void +VcdTraceFile::addTraceVal(const unsigned char *v, const std::string &name, + int width) +{ + addNewTraceVal<VcdTraceValInt<unsigned char>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const char *v, const std::string &name, int width) +{ + addNewTraceVal<VcdTraceValInt<char>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const unsigned short *v, const std::string &name, + int width) +{ + addNewTraceVal<VcdTraceValInt<unsigned short>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const short *v, const std::string &name, int width) +{ + addNewTraceVal<VcdTraceValInt<short>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const unsigned int *v, const std::string &name, + int width) +{ + addNewTraceVal<VcdTraceValInt<unsigned int>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const int *v, const std::string &name, int width) +{ + addNewTraceVal<VcdTraceValInt<int>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const unsigned long *v, const std::string &name, + int width) +{ + addNewTraceVal<VcdTraceValInt<unsigned long>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const long *v, const std::string &name, int width) +{ + addNewTraceVal<VcdTraceValInt<long>>(v, name, width); +} + +void +VcdTraceFile::addTraceVal(const sc_dt::int64 *v, const std::string &name, + int width) +{ + addNewTraceVal<VcdTraceValInt<sc_dt::int64>>(v, name, width); +} +void +VcdTraceFile::addTraceVal(const sc_dt::uint64 *v, const std::string &name, + int width) +{ + addNewTraceVal<VcdTraceValInt<sc_dt::uint64>>(v, name, width); +} + +void +VcdTraceFile::addTraceVal(const unsigned int *v, const std::string &name, + const char **literals) +{ + uint64_t count = 0; + while (*literals++) + count++; + + int bits = 0; + while (count >> bits) + bits++; + + addNewTraceVal<VcdTraceValInt<unsigned int>>(v, name, bits); +} + +void +VcdTraceFile::writeComment(const std::string &comment) +{ + stream() << "$comment" << std::endl; + stream() << comment << std::endl; + stream() << "$end" << std::endl << std::endl; +} + +} // namespace sc_gem5 diff --git a/src/systemc/utils/vcd.hh b/src/systemc/utils/vcd.hh new file mode 100644 index 000000000..dce7f4607 --- /dev/null +++ b/src/systemc/utils/vcd.hh @@ -0,0 +1,154 @@ +/* + * 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 + */ + +#ifndef __SYSTEMC_UTILS_VCD_HH__ +#define __SYSTEMC_UTILS_VCD_HH__ + +#include <map> + +#include "systemc/utils/tracefile.hh" + +namespace sc_gem5 +{ + +class VcdTraceValBase; + +class VcdTraceScope +{ + private: + std::vector<std::pair<std::string, VcdTraceValBase *>> values; + std::map<std::string, VcdTraceScope *> scopes; + + public: + void addValue(const std::string &name, VcdTraceValBase *value); + void output(const std::string &name, std::ostream &os); +}; + +class VcdTraceFile : public TraceFile +{ + private: + Tick lastPrintedTime; + uint64_t deltasAtNow; + + static const int NextNameChars = 5; + char _nextName[NextNameChars + 1]; + std::string nextSignalName(); + + bool initialized; + void initialize(); + + std::vector<VcdTraceValBase *> traceVals; + VcdTraceScope topScope; + + public: + VcdTraceFile(const std::string &name) : + TraceFile(name + ".vcd"), lastPrintedTime(0), deltasAtNow(0), + initialized(false) + { + _nextName[NextNameChars] = '\0'; + for (int i = 0; i < NextNameChars; i++) + _nextName[i] = 'a'; + } + ~VcdTraceFile(); + + void trace(bool delta) override; + + template<typename TV> + void + addNewTraceVal(const typename TV::TracedType *v, const std::string &name, + int width=1) + { + VcdTraceValBase *tv = new TV(v, nextSignalName(), width); + traceVals.push_back(tv); + topScope.addValue(name, tv); + } + + void addTraceVal(const bool *v, const std::string &name) override; + void addTraceVal(const float *v, const std::string &name) override; + void addTraceVal(const double *v, const std::string &name) override; + + void addTraceVal(const sc_dt::sc_logic *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_int_base *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_uint_base *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_signed *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_unsigned *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_bv_base *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_lv_base *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_fxval *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_fxval_fast *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_fxnum *v, + const std::string &name) override; + void addTraceVal(const sc_dt::sc_fxnum_fast *v, + const std::string &name) override; + + void addTraceVal(const sc_core::sc_event *v, + const std::string &name) override; + void addTraceVal(const sc_core::sc_time *v, + const std::string &name) override; + + void addTraceVal(const unsigned char *v, + const std::string &name, int width) override; + void addTraceVal(const char *v, const std::string &name, + int width) override; + void addTraceVal(const unsigned short *v, + const std::string &name, int width) override; + void addTraceVal(const short *v, const std::string &name, + int width) override; + void addTraceVal(const unsigned int *v, + const std::string &name, int width) override; + void addTraceVal(const int *v, const std::string &name, + int width) override; + void addTraceVal(const unsigned long *v, + const std::string &name, int width) override; + void addTraceVal(const long *v, const std::string &name, + int width) override; + + void addTraceVal(const sc_dt::int64 *v, + const std::string &name, int width) override; + void addTraceVal(const sc_dt::uint64 *v, + const std::string &name, int width) override; + + void addTraceVal(const unsigned int *, const std::string &name, + const char **literals) override; + + void writeComment(const std::string &comment) override; +}; + +} // namespace sc_gem5 + +#endif // __SYSTEMC_UTILS_VCD_HH__ |