From 7bc110ce5c12f47105e851a1a54c26a83eba6b87 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 14 Sep 2018 00:04:22 -0700 Subject: [PATCH] systemc: Refactor sensitivities. Dynamic and Static sensitivities used to be represented by the same classes, even though they're (almost) disjoint in how they worked. Also timeouts, which can be used alongside dynamic sensitivities, were handled by the sensitivities themselves. That meant that the sensitivity mechanism had to mix in more types of behaviors, increasing complexity. Also, the non-standard timed_out function Accellera includes is harder to implement if the path for timeouts and regular sensitivities are mixed together. This change splits up dynamic and static sensitivities and splits out timeouts. It also immitates the ordering Accellera uses when going through sensitivities for an event. Static sensitivities are triggered first in reverse order (why?), and then dynamic sensitivities are triggered in what amounts to reverse order. To delete a sensitivity which has been handled, it's swapped with the one in the last position, and then the vector is truncated to drop it at the end. This has the net effect of stirring the dynamic sensitivities, and isn't easily immitated using a different approach, even if other approaches would be more straightforward. Double check addSensitivity for event.hh Change-Id: I1e73dce386b95f68e9d6737deb8bed70ef717e0d Reviewed-on: https://gem5-review.googlesource.com/c/12805 Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/systemc/core/SConscript | 1 + src/systemc/core/event.cc | 13 +- src/systemc/core/event.hh | 41 ++++- src/systemc/core/process.cc | 154 +++++++---------- src/systemc/core/process.hh | 277 ++---------------------------- src/systemc/core/sc_module.cc | 52 +++--- src/systemc/core/sc_sensitive.cc | 8 +- src/systemc/core/sc_spawn.cc | 10 +- src/systemc/core/sensitivity.cc | 182 ++++++++++++++++++++ src/systemc/core/sensitivity.hh | 279 +++++++++++++++++++++++++++++++ src/systemc/ext/core/sc_event.hh | 8 +- src/systemc/ext/core/sc_port.hh | 8 +- 12 files changed, 633 insertions(+), 400 deletions(-) create mode 100644 src/systemc/core/sensitivity.cc create mode 100644 src/systemc/core/sensitivity.hh diff --git a/src/systemc/core/SConscript b/src/systemc/core/SConscript index 4814e6afa..1d291ef4d 100644 --- a/src/systemc/core/SConscript +++ b/src/systemc/core/SConscript @@ -40,6 +40,7 @@ if env['USE_SYSTEMC']: Source('python.cc') Source('scheduler.cc') Source('sched_event.cc') + Source('sensitivity.cc') Source('sc_attr.cc') Source('sc_event.cc') diff --git a/src/systemc/core/event.cc b/src/systemc/core/event.cc index 61fa80c8b..0daca12e1 100644 --- a/src/systemc/core/event.cc +++ b/src/systemc/core/event.cc @@ -145,9 +145,18 @@ Event::notify() if (delayedNotify.scheduled()) scheduler.deschedule(&delayedNotify); - auto local_sensitivities = sensitivities; - for (auto s: local_sensitivities) + for (auto s: staticSensitivities) s->notify(this); + DynamicSensitivities &ds = dynamicSensitivities; + int size = ds.size(); + int pos = 0; + while (pos < size) { + if (ds[pos]->notify(this)) + ds[pos] = ds[--size]; + else + pos++; + } + ds.resize(size); } void diff --git a/src/systemc/core/event.hh b/src/systemc/core/event.hh index c39053be8..bb1d0a0d6 100644 --- a/src/systemc/core/event.hh +++ b/src/systemc/core/event.hh @@ -37,7 +37,9 @@ #include "sim/eventq.hh" #include "systemc/core/list.hh" #include "systemc/core/object.hh" +#include "systemc/core/process.hh" #include "systemc/core/sched_event.hh" +#include "systemc/core/sensitivity.hh" #include "systemc/ext/core/sc_prim.hh" #include "systemc/ext/core/sc_time.hh" @@ -93,8 +95,40 @@ class Event return e->_gem5_event; } - void addSensitivity(Sensitivity *s) const { sensitivities.push_back(s); } - void delSensitivity(Sensitivity *s) const { sensitivities.remove(s); } + void + addSensitivity(StaticSensitivity *s) const + { + // Insert static sensitivities in reverse order to match Accellera's + // implementation. + staticSensitivities.insert(staticSensitivities.begin(), s); + } + void + delSensitivity(StaticSensitivity *s) const + { + for (auto &t: staticSensitivities) { + if (t == s) { + t = staticSensitivities.back(); + staticSensitivities.pop_back(); + break; + } + } + } + void + addSensitivity(DynamicSensitivity *s) const + { + dynamicSensitivities.push_back(s); + } + void + delSensitivity(DynamicSensitivity *s) const + { + for (auto &t: dynamicSensitivities) { + if (t == s) { + t = dynamicSensitivities.back(); + dynamicSensitivities.pop_back(); + break; + } + } + } private: sc_core::sc_event *_sc_event; @@ -107,7 +141,8 @@ class Event ScEvent delayedNotify; - mutable std::list sensitivities; + mutable StaticSensitivities staticSensitivities; + mutable DynamicSensitivities dynamicSensitivities; }; extern Events topLevelEvents; diff --git a/src/systemc/core/process.cc b/src/systemc/core/process.cc index 1c7a9d72e..e977713f4 100644 --- a/src/systemc/core/process.cc +++ b/src/systemc/core/process.cc @@ -40,85 +40,6 @@ namespace sc_gem5 { -SensitivityTimeout::SensitivityTimeout(Process *p, ::sc_core::sc_time t) : - Sensitivity(p), timeoutEvent([this]() { this->timeout(); }) -{ - scheduler.schedule(&timeoutEvent, t); -} - -SensitivityTimeout::~SensitivityTimeout() -{ - if (timeoutEvent.scheduled()) - scheduler.deschedule(&timeoutEvent); -} - -void -SensitivityTimeout::timeout() -{ - notify(); -} - -SensitivityEvent::SensitivityEvent( - Process *p, const ::sc_core::sc_event *e) : Sensitivity(p), event(e) -{ - Event::getFromScEvent(event)->addSensitivity(this); -} - -SensitivityEvent::~SensitivityEvent() -{ - Event::getFromScEvent(event)->delSensitivity(this); -} - -SensitivityEventAndList::SensitivityEventAndList( - Process *p, const ::sc_core::sc_event_and_list *list) : - Sensitivity(p), list(list), count(0) -{ - for (auto e: list->events) - Event::getFromScEvent(e)->addSensitivity(this); -} - -SensitivityEventAndList::~SensitivityEventAndList() -{ - for (auto e: list->events) - Event::getFromScEvent(e)->delSensitivity(this); -} - -void -SensitivityEventAndList::notifyWork(Event *e) -{ - e->delSensitivity(this); - count++; - if (count == list->events.size()) - satisfy(); -} - -SensitivityEventOrList::SensitivityEventOrList( - Process *p, const ::sc_core::sc_event_or_list *list) : - Sensitivity(p), list(list) -{ - for (auto e: list->events) - Event::getFromScEvent(e)->addSensitivity(this); -} - -SensitivityEventOrList::~SensitivityEventOrList() -{ - for (auto e: list->events) - Event::getFromScEvent(e)->delSensitivity(this); -} - -void -SensitivityTimeoutAndEventAndList::notifyWork(Event *e) -{ - if (e) { - // An event went off which must be part of the sc_event_and_list. - SensitivityEventAndList::notifyWork(e); - } else { - // There's no inciting event, so this must be a timeout. - satisfy(true); - } -} - - class UnwindExceptionReset : public ::sc_core::sc_unwind_exception { public: @@ -195,7 +116,7 @@ Process::disable(bool inc_kids) forEachKid([](Process *p) { p->disable(true); }); if (!::sc_core::sc_allow_process_control_corners && - dynamic_cast(dynamicSensitivity)) { + timeoutEvent.scheduled()) { std::string message("attempt to disable a thread with timeout wait: "); message += name(); SC_REPORT_ERROR("Undefined process control interaction", @@ -317,12 +238,8 @@ Process::syncResetOff(bool inc_kids) void Process::finalize() { - for (auto &s: pendingStaticSensitivities) { - s->finalize(staticSensitivities); - delete s; - s = nullptr; - } - pendingStaticSensitivities.clear(); + for (auto s: staticSensitivities) + s->finalize(); }; void @@ -346,26 +263,66 @@ Process::run() } void -Process::addStatic(PendingSensitivity *s) +Process::addStatic(StaticSensitivity *s) { - pendingStaticSensitivities.push_back(s); + staticSensitivities.push_back(s); } void -Process::setDynamic(Sensitivity *s) +Process::setDynamic(DynamicSensitivity *s) { - delete dynamicSensitivity; + if (dynamicSensitivity) { + dynamicSensitivity->clear(); + delete dynamicSensitivity; + } dynamicSensitivity = s; + if (dynamicSensitivity) + dynamicSensitivity->finalize(); +} + +void +Process::cancelTimeout() +{ + if (timeoutEvent.scheduled()) + scheduler.deschedule(&timeoutEvent); +} + +void +Process::setTimeout(::sc_core::sc_time t) +{ + cancelTimeout(); + scheduler.schedule(&timeoutEvent, t); +} + +void +Process::timeout() +{ + // A process is considered timed_out only if it was also waiting for an + // event but got a timeout instead. + _timedOut = (dynamicSensitivity != nullptr); + + setDynamic(nullptr); + if (disabled()) + return; + + ready(); } void Process::satisfySensitivity(Sensitivity *s) { // If there's a dynamic sensitivity and this wasn't it, ignore. - if (dynamicSensitivity && dynamicSensitivity != s) + if ((dynamicSensitivity || timeoutEvent.scheduled()) && + dynamicSensitivity != s) { return; + } - setDynamic(nullptr); + _timedOut = false; + // This sensitivity should already be cleared by this point, or the event + // which triggered it will take care of it. + delete dynamicSensitivity; + dynamicSensitivity = nullptr; + cancelTimeout(); ready(); } @@ -394,8 +351,9 @@ Process::lastReport(::sc_core::sc_report *report) ::sc_core::sc_report *Process::lastReport() const { return _lastReport.get(); } Process::Process(const char *name, ProcessFuncWrapper *func, bool internal) : - ::sc_core::sc_process_b(name), excWrapper(nullptr), func(func), - _internal(internal), _timedOut(false), _dontInitialize(false), + ::sc_core::sc_process_b(name), excWrapper(nullptr), + timeoutEvent([this]() { this->timeout(); }), + func(func), _internal(internal), _timedOut(false), _dontInitialize(false), _needsStart(true), _isUnwinding(false), _terminated(false), _suspended(false), _disabled(false), _syncReset(false), refCount(0), stackSize(::Fiber::DefaultStackSize), dynamicSensitivity(nullptr) @@ -413,10 +371,12 @@ Process::terminate() _suspendedReady = false; _suspended = false; _syncReset = false; - delete dynamicSensitivity; - dynamicSensitivity = nullptr; - for (auto s: staticSensitivities) + clearDynamic(); + cancelTimeout(); + for (auto s: staticSensitivities) { + s->clear(); delete s; + } staticSensitivities.clear(); _terminatedEvent.notify(); diff --git a/src/systemc/core/process.hh b/src/systemc/core/process.hh index d399d7a3d..0a312e28e 100644 --- a/src/systemc/core/process.hh +++ b/src/systemc/core/process.hh @@ -35,19 +35,14 @@ #include #include "base/fiber.hh" -#include "sim/eventq.hh" #include "systemc/core/bindinfo.hh" -#include "systemc/core/event.hh" #include "systemc/core/list.hh" #include "systemc/core/object.hh" #include "systemc/core/sched_event.hh" +#include "systemc/core/sensitivity.hh" #include "systemc/ext/core/sc_event.hh" -#include "systemc/ext/core/sc_export.hh" -#include "systemc/ext/core/sc_interface.hh" #include "systemc/ext/core/sc_module.hh" -#include "systemc/ext/core/sc_port.hh" #include "systemc/ext/core/sc_process_handle.hh" -#include "systemc/ext/utils/sc_report.hh" namespace sc_core { @@ -62,233 +57,6 @@ namespace sc_gem5 class ScHalt {}; -class Sensitivity -{ - protected: - Process *process; - - public: - Sensitivity(Process *p) : process(p) {} - virtual ~Sensitivity() {} - - void satisfy(bool timedOut=false); - - virtual void notifyWork(Event *e) { satisfy(); } - void notify(Event *e); - void notify() { notify(nullptr); } - - const std::string name(); -}; - -class SensitivityTimeout : virtual public Sensitivity -{ - private: - void timeout(); - ScEvent timeoutEvent; - - public: - SensitivityTimeout(Process *p, ::sc_core::sc_time t); - ~SensitivityTimeout(); -}; - -class SensitivityEvent : virtual public Sensitivity -{ - private: - const ::sc_core::sc_event *event; - - public: - SensitivityEvent(Process *p, const ::sc_core::sc_event *e); - ~SensitivityEvent(); -}; - -//XXX This sensitivity can't be reused. To reset it, it has to be deleted and -//recreated. That works for dynamic sensitivities, but not for static. -//Fortunately processes can't be statically sensitive to sc_event_and_lists. -class SensitivityEventAndList : virtual public Sensitivity -{ - private: - const ::sc_core::sc_event_and_list *list; - int count; - - public: - SensitivityEventAndList( - Process *p, const ::sc_core::sc_event_and_list *list); - ~SensitivityEventAndList(); - - void notifyWork(Event *e) override; -}; - -class SensitivityEventOrList : virtual public Sensitivity -{ - private: - const ::sc_core::sc_event_or_list *list; - - public: - SensitivityEventOrList( - Process *p, const ::sc_core::sc_event_or_list *list); - ~SensitivityEventOrList(); -}; - -// Combined sensitivities. These trigger when any of their parts do. - -class SensitivityTimeoutAndEvent : - public SensitivityTimeout, public SensitivityEvent -{ - public: - SensitivityTimeoutAndEvent( - Process *p, ::sc_core::sc_time t, const ::sc_core::sc_event *e) : - Sensitivity(p), SensitivityTimeout(p, t), SensitivityEvent(p, e) - {} - - void notifyWork(Event *e) override { satisfy(e == nullptr); } -}; - -class SensitivityTimeoutAndEventAndList : - public SensitivityTimeout, public SensitivityEventAndList -{ - public: - SensitivityTimeoutAndEventAndList( - Process *p, ::sc_core::sc_time t, - const ::sc_core::sc_event_and_list *eal) : - Sensitivity(p), SensitivityTimeout(p, t), - SensitivityEventAndList(p, eal) - {} - - void notifyWork(Event *e) override; -}; - -class SensitivityTimeoutAndEventOrList : - public SensitivityTimeout, public SensitivityEventOrList -{ - public: - SensitivityTimeoutAndEventOrList( - Process *p, ::sc_core::sc_time t, - const ::sc_core::sc_event_or_list *eol) : - Sensitivity(p), SensitivityTimeout(p, t), - SensitivityEventOrList(p, eol) - {} - - void notifyWork(Event *e) override { satisfy(e == nullptr); } -}; - -typedef std::vector Sensitivities; - - -/* - * Pending sensitivities. These are records of sensitivities to install later, - * once all the information to configure them is available. - */ - -class PendingSensitivity -{ - protected: - Process *process; - - public: - virtual void finalize(Sensitivities &s) = 0; - PendingSensitivity(Process *p) : process(p) {} - virtual ~PendingSensitivity() {} -}; - -class PendingSensitivityEvent : public PendingSensitivity -{ - private: - const sc_core::sc_event *event; - - public: - PendingSensitivityEvent(Process *p, const sc_core::sc_event *e) : - PendingSensitivity(p), event(e) {} - - void - finalize(Sensitivities &s) override - { - s.push_back(new SensitivityEvent(process, event)); - } -}; - -class PendingSensitivityInterface : public PendingSensitivity -{ - private: - const sc_core::sc_interface *interface; - - public: - PendingSensitivityInterface(Process *p, const sc_core::sc_interface *i) : - PendingSensitivity(p), interface(i) - {} - - void - finalize(Sensitivities &s) override - { - s.push_back(new SensitivityEvent(process, - &interface->default_event())); - } -}; - -class PendingSensitivityPort : public PendingSensitivity -{ - private: - const sc_core::sc_port_base *port; - - public: - PendingSensitivityPort(Process *p, const sc_core::sc_port_base *pb) : - PendingSensitivity(p), port(pb) - {} - - void - finalize(Sensitivities &s) override - { - for (int i = 0; i < port->size(); i++) { - const ::sc_core::sc_event *e = - &port->_gem5Interface(i)->default_event(); - s.push_back(new SensitivityEvent(process, e)); - } - } -}; - -class PendingSensitivityExport : public PendingSensitivity -{ - private: - const sc_core::sc_export_base *exp; - - public: - PendingSensitivityExport(Process *p, const sc_core::sc_export_base *exp) : - PendingSensitivity(p), exp(exp) - {} - - void - finalize(Sensitivities &s) override - { - s.push_back(new SensitivityEvent(process, - &exp->get_interface()->default_event())); - } -}; - -class PendingSensitivityFinder : public PendingSensitivity -{ - private: - const sc_core::sc_event_finder *finder; - - public: - PendingSensitivityFinder(Process *p, const sc_core::sc_event_finder *f) : - PendingSensitivity(p), finder(f) - {} - - void - finalize(Sensitivities &s) override - { - const ::sc_core::sc_port_base *port = finder->port(); - int size = port->size(); - for (int i = 0; i < size; i++) { - ::sc_core::sc_interface *interface = port->_gem5Interface(i); - const ::sc_core::sc_event *event = &finder->find_event(interface); - s.push_back(new SensitivityEvent(process, event)); - } - } -}; - -typedef std::vector PendingSensitivities; - - class Process : public ::sc_core::sc_process_b, public ListNode { public: @@ -332,8 +100,13 @@ class Process : public ::sc_core::sc_process_b, public ListNode void run(); - void addStatic(PendingSensitivity *); - void setDynamic(Sensitivity *); + void addStatic(StaticSensitivity *); + void setDynamic(DynamicSensitivity *); + void clearDynamic() { setDynamic(nullptr); } + + ScEvent timeoutEvent; + void setTimeout(::sc_core::sc_time t); + void cancelTimeout(); void satisfySensitivity(Sensitivity *); @@ -349,7 +122,6 @@ class Process : public ::sc_core::sc_process_b, public ListNode bool hasStaticSensitivities() { return !staticSensitivities.empty(); } bool internal() { return _internal; } bool timedOut() { return _timedOut; } - void timedOut(bool to) { _timedOut = to; } bool dontInitialize() { return _dontInitialize; } void dontInitialize(bool di) { _dontInitialize = di; } @@ -357,6 +129,8 @@ class Process : public ::sc_core::sc_process_b, public ListNode void joinWait(::sc_core::sc_join *join) { joinWaiters.push_back(join); } protected: + void timeout(); + Process(const char *name, ProcessFuncWrapper *func, bool internal=false); static Process *_newest; @@ -365,8 +139,11 @@ class Process : public ::sc_core::sc_process_b, public ListNode { popListNode(); delete func; - for (auto s: staticSensitivities) + for (auto s: staticSensitivities) { + s->clear(); delete s; + } + clearDynamic(); } ::sc_core::sc_event _resetEvent; @@ -399,36 +176,14 @@ class Process : public ::sc_core::sc_process_b, public ListNode size_t stackSize; - Sensitivities staticSensitivities; - PendingSensitivities pendingStaticSensitivities; - - Sensitivity *dynamicSensitivity; + StaticSensitivities staticSensitivities; + DynamicSensitivity *dynamicSensitivity; std::unique_ptr<::sc_core::sc_report> _lastReport; std::vector<::sc_core::sc_join *> joinWaiters; }; -inline void -Sensitivity::satisfy(bool timedOut) -{ - process->timedOut(timedOut); - process->satisfySensitivity(this); -} - -inline void -Sensitivity::notify(Event *e) -{ - if (!process->disabled()) - notifyWork(e); -} - -inline const std::string -Sensitivity::name() -{ - return std::string(process->name()) + ".timeout"; -} - } // namespace sc_gem5 #endif //__SYSTEMC_CORE_PROCESS_HH__ diff --git a/src/systemc/core/sc_module.cc b/src/systemc/core/sc_module.cc index e695f7697..3e900f658 100644 --- a/src/systemc/core/sc_module.cc +++ b/src/systemc/core/sc_module.cc @@ -496,35 +496,40 @@ void next_trigger() { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(nullptr); + p->cancelTimeout(); + p->clearDynamic(); } void next_trigger(const sc_event &e) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityEvent(p, &e)); + p->cancelTimeout(); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEvent(p, &e)); } void next_trigger(const sc_event_or_list &eol) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityEventOrList(p, &eol)); + p->cancelTimeout(); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventOrList(p, &eol)); } void next_trigger(const sc_event_and_list &eal) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityEventAndList(p, &eal)); + p->cancelTimeout(); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventAndList(p, &eal)); } void next_trigger(const sc_time &t) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityTimeout(p, t)); + p->setTimeout(t); + p->clearDynamic(); } void @@ -537,7 +542,8 @@ void next_trigger(const sc_time &t, const sc_event &e) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityTimeoutAndEvent(p, t, &e)); + p->setTimeout(t); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEvent(p, &e)); } void @@ -550,8 +556,8 @@ void next_trigger(const sc_time &t, const sc_event_or_list &eol) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic( - new ::sc_gem5::SensitivityTimeoutAndEventOrList(p, t, &eol)); + p->setTimeout(t); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventOrList(p, &eol)); } void @@ -564,8 +570,8 @@ void next_trigger(const sc_time &t, const sc_event_and_list &eal) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic( - new ::sc_gem5::SensitivityTimeoutAndEventAndList(p, t, &eal)); + p->setTimeout(t); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventAndList(p, &eal)); } void @@ -589,7 +595,8 @@ void wait() { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(nullptr); + p->cancelTimeout(); + p->clearDynamic(); sc_gem5::scheduler.yield(); } @@ -608,7 +615,8 @@ void wait(const sc_event &e) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityEvent(p, &e)); + p->cancelTimeout(); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEvent(p, &e)); sc_gem5::scheduler.yield(); } @@ -616,7 +624,8 @@ void wait(const sc_event_or_list &eol) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityEventOrList(p, &eol)); + p->cancelTimeout(); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventOrList(p, &eol)); sc_gem5::scheduler.yield(); } @@ -624,7 +633,8 @@ void wait(const sc_event_and_list &eal) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityEventAndList(p, &eal)); + p->cancelTimeout(); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventAndList(p, &eal)); sc_gem5::scheduler.yield(); } @@ -632,7 +642,8 @@ void wait(const sc_time &t) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityTimeout(p, t)); + p->setTimeout(t); + p->clearDynamic(); sc_gem5::scheduler.yield(); } @@ -646,7 +657,8 @@ void wait(const sc_time &t, const sc_event &e) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic(new ::sc_gem5::SensitivityTimeoutAndEvent(p, t, &e)); + p->setTimeout(t); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEvent(p, &e)); sc_gem5::scheduler.yield(); } @@ -660,8 +672,8 @@ void wait(const sc_time &t, const sc_event_or_list &eol) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic( - new ::sc_gem5::SensitivityTimeoutAndEventOrList(p, t, &eol)); + p->setTimeout(t); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventOrList(p, &eol)); sc_gem5::scheduler.yield(); } @@ -675,8 +687,8 @@ void wait(const sc_time &t, const sc_event_and_list &eal) { sc_gem5::Process *p = sc_gem5::scheduler.current(); - p->setDynamic( - new ::sc_gem5::SensitivityTimeoutAndEventAndList(p, t, &eal)); + p->setTimeout(t); + p->setDynamic(new ::sc_gem5::DynamicSensitivityEventAndList(p, &eal)); sc_gem5::scheduler.yield(); } diff --git a/src/systemc/core/sc_sensitive.cc b/src/systemc/core/sc_sensitive.cc index 25bc1bb08..93b460a4b 100644 --- a/src/systemc/core/sc_sensitive.cc +++ b/src/systemc/core/sc_sensitive.cc @@ -41,7 +41,7 @@ sc_sensitive & sc_sensitive::operator << (const sc_event &e) { currentProcess->addStatic( - new sc_gem5::PendingSensitivityEvent(currentProcess, &e)); + new sc_gem5::StaticSensitivityEvent(currentProcess, &e)); return *this; } @@ -49,7 +49,7 @@ sc_sensitive & sc_sensitive::operator << (const sc_interface &i) { currentProcess->addStatic( - new sc_gem5::PendingSensitivityInterface(currentProcess, &i)); + new sc_gem5::StaticSensitivityInterface(currentProcess, &i)); return *this; } @@ -57,7 +57,7 @@ sc_sensitive & sc_sensitive::operator << (const sc_port_base &b) { currentProcess->addStatic( - new sc_gem5::PendingSensitivityPort(currentProcess, &b)); + new sc_gem5::StaticSensitivityPort(currentProcess, &b)); return *this; } @@ -65,7 +65,7 @@ sc_sensitive & sc_sensitive::operator << (sc_event_finder &f) { currentProcess->addStatic( - new sc_gem5::PendingSensitivityFinder(currentProcess, &f)); + new sc_gem5::StaticSensitivityFinder(currentProcess, &f)); return *this; } diff --git a/src/systemc/core/sc_spawn.cc b/src/systemc/core/sc_spawn.cc index 9e2b4c83a..02f1fa6c9 100644 --- a/src/systemc/core/sc_spawn.cc +++ b/src/systemc/core/sc_spawn.cc @@ -70,19 +70,19 @@ spawnWork(ProcessFuncWrapper *func, const char *name, if (opts) { for (auto e: opts->_events) - proc->addStatic(new PendingSensitivityEvent(proc, e)); + proc->addStatic(new StaticSensitivityEvent(proc, e)); for (auto p: opts->_ports) - proc->addStatic(new PendingSensitivityPort(proc, p)); + proc->addStatic(new StaticSensitivityPort(proc, p)); for (auto e: opts->_exports) - proc->addStatic(new PendingSensitivityExport(proc, e)); + proc->addStatic(new StaticSensitivityExport(proc, e)); for (auto i: opts->_interfaces) - proc->addStatic(new PendingSensitivityInterface(proc, i)); + proc->addStatic(new StaticSensitivityInterface(proc, i)); for (auto f: opts->_finders) - proc->addStatic(new PendingSensitivityFinder(proc, f)); + proc->addStatic(new StaticSensitivityFinder(proc, f)); } if (opts && opts->_dontInitialize && diff --git a/src/systemc/core/sensitivity.cc b/src/systemc/core/sensitivity.cc new file mode 100644 index 000000000..77aacb56a --- /dev/null +++ b/src/systemc/core/sensitivity.cc @@ -0,0 +1,182 @@ +/* + * 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/core/sensitivity.hh" + +#include "systemc/core/event.hh" +#include "systemc/core/scheduler.hh" +#include "systemc/ext/core/sc_export.hh" +#include "systemc/ext/core/sc_interface.hh" +#include "systemc/ext/core/sc_port.hh" + +namespace sc_gem5 +{ + +void +Sensitivity::satisfy() +{ + process->satisfySensitivity(this); +} + +bool +Sensitivity::notify(Event *e) +{ + if (process->disabled()) + return false; + return notifyWork(e); +} + + +void +DynamicSensitivity::addToEvent(const ::sc_core::sc_event *e) +{ + Event::getFromScEvent(e)->addSensitivity(this); +} + +void +DynamicSensitivity::delFromEvent(const ::sc_core::sc_event *e) +{ + Event::getFromScEvent(e)->delSensitivity(this); +} + +void +StaticSensitivity::addToEvent(const ::sc_core::sc_event *e) +{ + Event::getFromScEvent(e)->addSensitivity(this); +} + +void +StaticSensitivity::delFromEvent(const ::sc_core::sc_event *e) +{ + Event::getFromScEvent(e)->delSensitivity(this); +} + +void +StaticSensitivityInterface::finalize() +{ + event = &interface->default_event(); + SensitivityEvent::finalize(); +} + +void +StaticSensitivityPort::finalize() +{ + for (int i = 0; i < port->size(); i++) { + const ::sc_core::sc_event *event = + &port->_gem5Interface(i)->default_event(); + events.insert(event); + addToEvent(event); + } +} + +void +StaticSensitivityExport::finalize() +{ + event = &exp->get_interface()->default_event(); + SensitivityEvent::finalize(); +} + +void +StaticSensitivityFinder::finalize() +{ + const ::sc_core::sc_port_base *port = finder->port(); + int size = port->size(); + for (int i = 0; i < size; i++) { + ::sc_core::sc_interface *interface = port->_gem5Interface(i); + const ::sc_core::sc_event *event = &finder->find_event(interface); + events.insert(event); + addToEvent(event); + } +} + +bool +DynamicSensitivityEventOrList::notifyWork(Event *e) +{ + events.erase(e->sc_event()); + + // All the other events need this deleted from their lists since this + // sensitivity has been satisfied without them triggering. + for (auto le: events) + delFromEvent(le); + + satisfy(); + return true; +} + +DynamicSensitivityEventOrList::DynamicSensitivityEventOrList( + Process *p, const sc_core::sc_event_or_list *eol) : + Sensitivity(p), DynamicSensitivity(p), events(eol->events) +{} + +void +DynamicSensitivityEventOrList::finalize() +{ + for (auto e: events) + addToEvent(e); +} + +void +DynamicSensitivityEventOrList::clear() +{ + for (auto e: events) + delFromEvent(e); +} + +bool +DynamicSensitivityEventAndList::notifyWork(Event *e) +{ + events.erase(e->sc_event()); + + // This sensitivity is satisfied if all events have triggered. + if (events.empty()) + satisfy(); + + return true; +} + +DynamicSensitivityEventAndList::DynamicSensitivityEventAndList( + Process *p, const sc_core::sc_event_and_list *eal) : + Sensitivity(p), DynamicSensitivity(p), events(eal->events) +{} + +void +DynamicSensitivityEventAndList::finalize() +{ + for (auto e: events) + addToEvent(e); +} + +void +DynamicSensitivityEventAndList::clear() +{ + for (auto e: events) + delFromEvent(e); +} + +} // namespace sc_gem5 diff --git a/src/systemc/core/sensitivity.hh b/src/systemc/core/sensitivity.hh new file mode 100644 index 000000000..f032630ec --- /dev/null +++ b/src/systemc/core/sensitivity.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_CORE_SENSITIVITY_HH__ +#define __SYSTEMC_CORE_SENSITIVITY_HH__ + +#include +#include + +#include "sim/eventq.hh" +#include "systemc/core/sched_event.hh" +#include "systemc/ext/core/sc_module.hh" + +namespace sc_core +{ + +class sc_event; +class sc_event_and_list; +class sc_event_or_list; +class sc_event_finder; +class sc_export_base; +class sc_interface; +class sc_port_base; + +} // namespace sc_core + +namespace sc_gem5 +{ + +class Process; +class Event; + +/* + * Common sensitivity interface. + */ + +class Sensitivity +{ + protected: + Process *process; + + Sensitivity(Process *p) : process(p) {} + virtual ~Sensitivity() {} + + virtual void addToEvent(const ::sc_core::sc_event *e) = 0; + virtual void delFromEvent(const ::sc_core::sc_event *e) = 0; + + virtual bool + notifyWork(Event *e) + { + satisfy(); + return true; + } + + public: + virtual void finalize() = 0; + virtual void clear() = 0; + + void satisfy(); + bool notify(Event *e); + + virtual bool dynamic() = 0; +}; + + +/* + * Dynamic vs. static sensitivity. + */ + +class DynamicSensitivity : virtual public Sensitivity +{ + protected: + DynamicSensitivity(Process *p) : Sensitivity(p) {} + + void addToEvent(const ::sc_core::sc_event *e) override; + void delFromEvent(const ::sc_core::sc_event *e) override; + + public: + bool dynamic() override { return true; } +}; + +typedef std::vector DynamicSensitivities; + + +class StaticSensitivity : virtual public Sensitivity +{ + protected: + StaticSensitivity(Process *p) : Sensitivity(p) {} + + void addToEvent(const ::sc_core::sc_event *e) override; + void delFromEvent(const ::sc_core::sc_event *e) override; + + public: + bool dynamic() override { return false; } +}; + +typedef std::vector StaticSensitivities; + + +/* + * Sensitivity to events, which can be static or dynamic. + */ + +class SensitivityEvent : virtual public Sensitivity +{ + protected: + const ::sc_core::sc_event *event; + + SensitivityEvent(Process *p, const ::sc_core::sc_event *e=nullptr) : + Sensitivity(p), event(e) + {} + + public: + void finalize() override { addToEvent(event); } + void clear() override { delFromEvent(event); } +}; + + +/* + * Static sensitivities. + */ + +class StaticSensitivityEvent : + public StaticSensitivity, public SensitivityEvent +{ + public: + StaticSensitivityEvent(Process *p, const sc_core::sc_event *e) : + Sensitivity(p), StaticSensitivity(p), SensitivityEvent(p, e) + {} +}; + +class StaticSensitivityInterface : + public StaticSensitivity, public SensitivityEvent +{ + private: + const sc_core::sc_interface *interface; + + public: + StaticSensitivityInterface(Process *p, const sc_core::sc_interface *i) : + Sensitivity(p), StaticSensitivity(p), SensitivityEvent(p), interface(i) + {} + + void finalize() override; +}; + +class StaticSensitivityPort : public StaticSensitivity +{ + private: + const ::sc_core::sc_port_base *port; + std::set events; + + public: + StaticSensitivityPort(Process *p, const sc_core::sc_port_base *pb) : + Sensitivity(p), StaticSensitivity(p), port(pb) + {} + + void finalize() override; + + void + clear() override + { + for (auto event: events) + delFromEvent(event); + } +}; + +class StaticSensitivityExport : + public StaticSensitivity, public SensitivityEvent +{ + private: + const sc_core::sc_export_base *exp; + + public: + StaticSensitivityExport(Process *p, const sc_core::sc_export_base *exp) : + Sensitivity(p), StaticSensitivity(p), SensitivityEvent(p), exp(exp) + {} + + void finalize() override; +}; + +class StaticSensitivityFinder : public StaticSensitivity +{ + private: + const ::sc_core::sc_event_finder *finder; + std::set events; + + public: + StaticSensitivityFinder(Process *p, const sc_core::sc_event_finder *f) : + Sensitivity(p), StaticSensitivity(p), finder(f) + {} + + void finalize() override; + + void + clear() override + { + for (auto event: events) + delFromEvent(event); + } +}; + + +/* + * Dynamic sensitivities. + */ + +class DynamicSensitivityEvent : + public DynamicSensitivity, public SensitivityEvent +{ + public: + DynamicSensitivityEvent(Process *p, const sc_core::sc_event *e) : + Sensitivity(p), DynamicSensitivity(p), SensitivityEvent(p, e) + {} +}; + +class DynamicSensitivityEventOrList : public DynamicSensitivity +{ + private: + std::set events; + + protected: + bool notifyWork(Event *e) override; + + public: + DynamicSensitivityEventOrList( + Process *p, const sc_core::sc_event_or_list *eol); + + void finalize() override; + void clear() override; +}; + +//XXX This sensitivity can't be reused. To reset it, it has to be deleted and +//recreated. That works for dynamic sensitivities, but not for static. +//Fortunately processes can't be statically sensitive to sc_event_and_lists. +class DynamicSensitivityEventAndList : public DynamicSensitivity +{ + private: + std::set events; + + protected: + bool notifyWork(Event *e) override; + + public: + DynamicSensitivityEventAndList( + Process *p, const sc_core::sc_event_and_list *eal); + + void finalize() override; + void clear() override; +}; + +} // namespace sc_gem5 + +#endif //__SYSTEMC_CORE_SENSITIVITY_HH__ diff --git a/src/systemc/ext/core/sc_event.hh b/src/systemc/ext/core/sc_event.hh index e9748cb95..f70951d6a 100644 --- a/src/systemc/ext/core/sc_event.hh +++ b/src/systemc/ext/core/sc_event.hh @@ -41,8 +41,8 @@ namespace sc_gem5 { class Event; -class SensitivityEventAndList; -class SensitivityEventOrList; +class DynamicSensitivityEventAndList; +class DynamicSensitivityEventOrList; } @@ -116,7 +116,7 @@ class sc_event_and_list private: friend class sc_event_and_expr; - friend class sc_gem5::SensitivityEventAndList; + friend class sc_gem5::DynamicSensitivityEventAndList; explicit sc_event_and_list(bool auto_delete); @@ -148,7 +148,7 @@ class sc_event_or_list private: friend class sc_event_or_expr; - friend class sc_gem5::SensitivityEventOrList; + friend class sc_gem5::DynamicSensitivityEventOrList; explicit sc_event_or_list(bool auto_delete); diff --git a/src/systemc/ext/core/sc_port.hh b/src/systemc/ext/core/sc_port.hh index 88745cc2e..de26f5ae5 100644 --- a/src/systemc/ext/core/sc_port.hh +++ b/src/systemc/ext/core/sc_port.hh @@ -41,8 +41,8 @@ namespace sc_gem5 class BindInfo; class Module; -class PendingSensitivityPort; -class PendingSensitivityFinder; +class StaticSensitivityPort; +class StaticSensitivityFinder; }; @@ -87,8 +87,8 @@ class sc_port_base : public sc_object virtual void end_of_simulation() = 0; private: - friend class ::sc_gem5::PendingSensitivityPort; - friend class ::sc_gem5::PendingSensitivityFinder; + friend class ::sc_gem5::StaticSensitivityPort; + friend class ::sc_gem5::StaticSensitivityFinder; friend class ::sc_gem5::Kernel; void _gem5Finalize(); -- 2.30.2