From 743a1b5cdd8e607f2e1bb5ad182047c512eae3f8 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Wed, 18 Jul 2018 20:59:56 -0700 Subject: [PATCH] systemc: Implement pending activity related functions Track the number of notifications/timeouts that are scheduled at any given time. This lets us implement sc_pending_activity_at_current_time, sc_pending_activity_at_future_time, and sc_time_to_pending_activity. Change-Id: Ia3fcd29bdbfe1a6c77eb52ce4836982d4705263c Reviewed-on: https://gem5-review.googlesource.com/12032 Reviewed-by: Gabe Black Maintainer: Gabe Black --- src/systemc/core/event.cc | 24 +++++++----- src/systemc/core/event.hh | 3 +- src/systemc/core/process.cc | 15 ++++++-- src/systemc/core/process.hh | 8 ++-- src/systemc/core/sc_main.cc | 15 +++----- src/systemc/core/scheduler.cc | 3 +- src/systemc/core/scheduler.hh | 72 ++++++++++++++++++++++++++++++++++- 7 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/systemc/core/event.cc b/src/systemc/core/event.cc index 5008074f6..1623cf9e8 100644 --- a/src/systemc/core/event.cc +++ b/src/systemc/core/event.cc @@ -43,7 +43,7 @@ namespace sc_gem5 Event::Event(sc_core::sc_event *_sc_event) : Event(_sc_event, "") {} Event::Event(sc_core::sc_event *_sc_event, const char *_basename) : - _sc_event(_sc_event), _basename(_basename), delayedNotify(this) + _sc_event(_sc_event), _basename(_basename), delayedNotifyEvent(this) { Module *p = currentModule(); @@ -120,29 +120,35 @@ Event::notify() s->notify(this); } +void +Event::delayedNotify() +{ + scheduler.eventHappened(); + notify(); +} + void Event::notify(const sc_core::sc_time &t) { //XXX We're assuming the systemc time resolution is in ps. - Tick new_tick = t.value() * SimClock::Int::ps + - scheduler.eventQueue().getCurTick(); - if (delayedNotify.scheduled()) { - Tick old_tick = delayedNotify.when(); + Tick new_tick = t.value() * SimClock::Int::ps + scheduler.getCurTick(); + if (delayedNotifyEvent.scheduled()) { + Tick old_tick = delayedNotifyEvent.when(); if (new_tick >= old_tick) return; - scheduler.eventQueue().deschedule(&delayedNotify); + scheduler.deschedule(&delayedNotifyEvent); } - scheduler.eventQueue().schedule(&delayedNotify, new_tick); + scheduler.schedule(&delayedNotifyEvent, new_tick); } void Event::cancel() { - if (delayedNotify.scheduled()) - scheduler.eventQueue().deschedule(&delayedNotify); + if (delayedNotifyEvent.scheduled()) + scheduler.deschedule(&delayedNotifyEvent); } bool diff --git a/src/systemc/core/event.hh b/src/systemc/core/event.hh index a9d318382..6d2f46d42 100644 --- a/src/systemc/core/event.hh +++ b/src/systemc/core/event.hh @@ -105,7 +105,8 @@ class Event sc_core::sc_object *parent; EventsIt parentIt; - EventWrapper delayedNotify; + void delayedNotify(); + EventWrapper delayedNotifyEvent; mutable std::set sensitivities; }; diff --git a/src/systemc/core/process.cc b/src/systemc/core/process.cc index 7ed187fe1..ad297a23c 100644 --- a/src/systemc/core/process.cc +++ b/src/systemc/core/process.cc @@ -37,16 +37,23 @@ namespace sc_gem5 { SensitivityTimeout::SensitivityTimeout(Process *p, ::sc_core::sc_time t) : - Sensitivity(p), timeoutEvent(this), timeout(t) + Sensitivity(p), timeoutEvent(this), time(t) { - Tick when = scheduler.eventQueue().getCurTick() + timeout.value(); - scheduler.eventQueue().schedule(&timeoutEvent, when); + Tick when = scheduler.getCurTick() + time.value(); + scheduler.schedule(&timeoutEvent, when); } SensitivityTimeout::~SensitivityTimeout() { if (timeoutEvent.scheduled()) - scheduler.eventQueue().deschedule(&timeoutEvent); + scheduler.deschedule(&timeoutEvent); +} + +void +SensitivityTimeout::timeout() +{ + scheduler.eventHappened(); + notify(); } SensitivityEvent::SensitivityEvent( diff --git a/src/systemc/core/process.hh b/src/systemc/core/process.hh index 7c75d6244..afdbb3798 100644 --- a/src/systemc/core/process.hh +++ b/src/systemc/core/process.hh @@ -66,8 +66,10 @@ class Sensitivity class SensitivityTimeout : virtual public Sensitivity { private: - EventWrapper timeoutEvent; - ::sc_core::sc_time timeout; + void timeout(); + EventWrapper timeoutEvent; + ::sc_core::sc_time time; public: SensitivityTimeout(Process *p, ::sc_core::sc_time t); @@ -98,7 +100,7 @@ class SensitivityEventAndList : virtual public Sensitivity Process *p, const ::sc_core::sc_event_and_list *list); ~SensitivityEventAndList(); - virtual void notifyWork(Event *e) override; + void notifyWork(Event *e) override; }; class SensitivityEventOrList : virtual public Sensitivity diff --git a/src/systemc/core/sc_main.cc b/src/systemc/core/sc_main.cc index 120bbf9ae..103b3032f 100644 --- a/src/systemc/core/sc_main.cc +++ b/src/systemc/core/sc_main.cc @@ -140,7 +140,7 @@ sc_argv() void sc_start() { - Tick now = curEventQueue() ? curEventQueue()->getCurTick() : 0; + Tick now = ::sc_gem5::scheduler.getCurTick(); sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION); } @@ -156,7 +156,7 @@ sc_start(const sc_time &time, sc_starvation_policy p) { _status = SC_RUNNING; - Tick now = curEventQueue() ? curEventQueue()->getCurTick() : 0; + Tick now = ::sc_gem5::scheduler.getCurTick(); ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME); if (::sc_gem5::scheduler.paused()) @@ -200,7 +200,7 @@ const sc_time & sc_time_stamp() { static sc_time tstamp; - Tick tick = sc_gem5::scheduler.eventQueue().getCurTick(); + Tick tick = ::sc_gem5::scheduler.getCurTick(); //XXX We're assuming the systemc time resolution is in ps. tstamp = sc_time::from_value(tick / SimClock::Int::ps); return tstamp; @@ -221,15 +221,13 @@ sc_is_running() bool sc_pending_activity_at_current_time() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); - return false; + return ::sc_gem5::scheduler.pendingCurr(); } bool sc_pending_activity_at_future_time() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); - return false; + return ::sc_gem5::scheduler.pendingFuture(); } bool @@ -242,8 +240,7 @@ sc_pending_activity() sc_time sc_time_to_pending_activity() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); - return sc_time(); + return sc_time::from_value(::sc_gem5::scheduler.timeToPending()); } sc_status diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc index e3d275bb1..eab6f482c 100644 --- a/src/systemc/core/scheduler.cc +++ b/src/systemc/core/scheduler.cc @@ -37,8 +37,7 @@ namespace sc_gem5 { Scheduler::Scheduler() : - eq(nullptr), _pendingCurr(0), _pendingFuture(0), - readyEvent(this, false, ReadyPriority), + eq(nullptr), readyEvent(this, false, ReadyPriority), pauseEvent(this, false, PausePriority), stopEvent(this, false, StopPriority), scMain(nullptr), _started(false), _paused(false), _stopped(false), diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh index 5db5556ae..3ac7f419f 100644 --- a/src/systemc/core/scheduler.hh +++ b/src/systemc/core/scheduler.hh @@ -179,8 +179,75 @@ class Scheduler // Set an event queue for scheduling events. void setEventQueue(EventQueue *_eq) { eq = _eq; } - // Retrieve the event queue. - EventQueue &eventQueue() const { return *eq; } + // Get the current time according to gem5. + Tick getCurTick() { return eq ? eq->getCurTick() : 0; } + + // For scheduling delayed/timed notifications/timeouts. + void + schedule(::Event *event, Tick tick) + { + pendingTicks[tick]++; + eq->schedule(event, tick); + } + + // For descheduling delayed/timed notifications/timeouts. + void + deschedule(::Event *event) + { + auto it = pendingTicks.find(event->when()); + if (--it->second == 0) + pendingTicks.erase(it); + eq->deschedule(event); + } + + // Tell the scheduler than an event fired for bookkeeping purposes. + void + eventHappened() + { + auto it = pendingTicks.begin(); + if (--it->second == 0) + pendingTicks.erase(it); + } + + // Pending activity ignores gem5 activity, much like how a systemc + // simulation wouldn't know about asynchronous external events (socket IO + // for instance) that might happen before time advances in a pure + // systemc simulation. Also the spec lists what specific types of pending + // activity needs to be counted, which obviously doesn't include gem5 + // events. + + // Return whether there's pending systemc activity at this time. + bool + pendingCurr() + { + if (!readyList.empty() || !updateList.empty()) + return true; + return pendingTicks.size() && + pendingTicks.begin()->first == getCurTick(); + } + + // Return whether there are pending timed notifications or timeouts. + bool + pendingFuture() + { + switch (pendingTicks.size()) { + case 0: return false; + case 1: return pendingTicks.begin()->first > getCurTick(); + default: return true; + } + } + + // Return how many ticks there are until the first pending event, if any. + Tick + timeToPending() + { + if (!readyList.empty() || !updateList.empty()) + return 0; + else if (pendingTicks.size()) + return pendingTicks.begin()->first - getCurTick(); + else + return MaxTick - getCurTick(); + } // Run scheduled channel updates. void update(); @@ -205,6 +272,7 @@ class Scheduler static Priority MaxTickPriority = DefaultPriority + 3; EventQueue *eq; + std::map pendingTicks; void runReady(); EventWrapper readyEvent; -- 2.30.2