diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/systemc/core/SConscript | 1 | ||||
-rw-r--r-- | src/systemc/core/channel.cc | 50 | ||||
-rw-r--r-- | src/systemc/core/channel.hh | 58 | ||||
-rw-r--r-- | src/systemc/core/kernel.cc | 16 | ||||
-rw-r--r-- | src/systemc/core/sc_prim.cc | 124 | ||||
-rw-r--r-- | src/systemc/core/scheduler.cc | 77 | ||||
-rw-r--r-- | src/systemc/core/scheduler.hh | 108 | ||||
-rw-r--r-- | src/systemc/ext/core/sc_prim.hh | 14 |
8 files changed, 339 insertions, 109 deletions
diff --git a/src/systemc/core/SConscript b/src/systemc/core/SConscript index 045300478..8fd5f7af9 100644 --- a/src/systemc/core/SConscript +++ b/src/systemc/core/SConscript @@ -30,6 +30,7 @@ Import('*') if env['USE_SYSTEMC']: SimObject('SystemC.py') + Source('channel.cc') Source('kernel.cc') Source('module.cc') Source('object.cc') diff --git a/src/systemc/core/channel.cc b/src/systemc/core/channel.cc new file mode 100644 index 000000000..4a862b8aa --- /dev/null +++ b/src/systemc/core/channel.cc @@ -0,0 +1,50 @@ +/* + * 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/channel.hh" + +#include "systemc/core/scheduler.hh" + +namespace sc_gem5 +{ + +void +Channel::requestUpdate() +{ + scheduler.requestUpdate(this); +} + +void +Channel::asyncRequestUpdate() +{ + //TODO This should probably not request an update directly. + scheduler.requestUpdate(this); +} + +} // namespace sc_gem5 diff --git a/src/systemc/core/channel.hh b/src/systemc/core/channel.hh new file mode 100644 index 000000000..7ce437572 --- /dev/null +++ b/src/systemc/core/channel.hh @@ -0,0 +1,58 @@ +/* + * 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_CHANNEL_HH__ +#define __SYSTEMC_CORE_CHANNEL_HH__ + +#include "systemc/core/list.hh" +#include "systemc/ext/core/sc_prim.hh" + +namespace sc_gem5 +{ + +class Channel : public ListNode +{ + public: + Channel(sc_core::sc_prim_channel *_sc_chan) : _sc_chan(_sc_chan) {} + + virtual ~Channel() {} + + void requestUpdate(); + void asyncRequestUpdate(); + void update() { _sc_chan->update(); } + + sc_core::sc_prim_channel *sc_chan() { return _sc_chan; } + + private: + sc_core::sc_prim_channel *_sc_chan; +}; + +} // namespace sc_gem5 + +#endif //__SYSTEMC_CORE_CHANNEL_HH__ diff --git a/src/systemc/core/kernel.cc b/src/systemc/core/kernel.cc index 82281c085..e93236541 100644 --- a/src/systemc/core/kernel.cc +++ b/src/systemc/core/kernel.cc @@ -33,18 +33,30 @@ namespace SystemC { -Kernel::Kernel(Params *params) : SimObject(params), t0Event(this) {} +Kernel::Kernel(Params *params) : + SimObject(params), t0Event(this, false, EventBase::Default_Pri - 1) {} void Kernel::startup() { schedule(t0Event, curTick()); + // Install ourselves as the scheduler's event manager. + ::sc_gem5::scheduler.setEventQueue(eventQueue()); + // Run update once before the event queue starts. + ::sc_gem5::scheduler.update(); } void Kernel::t0Handler() { - ::sc_gem5::scheduler.initialize(); + // Now that the event queue has started, mark all the processes that + // need to be initialized as ready to run. + // + // This event has greater priority than delta notifications and so will + // happen before them, honoring the ordering for the initialization phase + // in the spec. The delta phase will happen at normal priority, and then + // the event which runs the processes which is at a lower priority. + ::sc_gem5::scheduler.initToReady(); } } // namespace SystemC diff --git a/src/systemc/core/sc_prim.cc b/src/systemc/core/sc_prim.cc index 4b5cf1780..91befa836 100644 --- a/src/systemc/core/sc_prim.cc +++ b/src/systemc/core/sc_prim.cc @@ -28,110 +28,106 @@ */ #include "base/logging.hh" +#include "systemc/core/channel.hh" #include "systemc/ext/core/sc_prim.hh" namespace sc_core { -const char * -sc_prim_channel::kind() const -{ - warn("%s not implemented.\n", __PRETTY_FUNCTION__); - return ""; -} +sc_prim_channel::sc_prim_channel() : + _gem5_channel(new sc_gem5::Channel(this)) +{} -sc_prim_channel::sc_prim_channel() -{ - warn("%s not implemented.\n", __PRETTY_FUNCTION__); -} +sc_prim_channel::sc_prim_channel(const char *_name) : + sc_object(_name), _gem5_channel(new sc_gem5::Channel(this)) +{} -sc_prim_channel::sc_prim_channel(const char *) -{ - warn("%s not implemented.\n", __PRETTY_FUNCTION__); -} +sc_prim_channel::~sc_prim_channel() { delete _gem5_channel; } void sc_prim_channel::request_update() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + _gem5_channel->requestUpdate(); } void sc_prim_channel::async_request_update() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + _gem5_channel->asyncRequestUpdate(); } void sc_prim_channel::next_trigger() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(); } void -sc_prim_channel::next_trigger(const sc_event &) +sc_prim_channel::next_trigger(const sc_event &e) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(e); } void -sc_prim_channel::next_trigger(const sc_event_or_list &) +sc_prim_channel::next_trigger(const sc_event_or_list &eol) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(eol); } void -sc_prim_channel::next_trigger(const sc_event_and_list &) +sc_prim_channel::next_trigger(const sc_event_and_list &eal) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(eal); } void -sc_prim_channel::next_trigger(const sc_time &) +sc_prim_channel::next_trigger(const sc_time &t) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(t); } void -sc_prim_channel::next_trigger(double, sc_time_unit) +sc_prim_channel::next_trigger(double d, sc_time_unit u) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(d, u); } void -sc_prim_channel::next_trigger(const sc_time &, const sc_event &) +sc_prim_channel::next_trigger(const sc_time &t, const sc_event &e) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(t, e); } void -sc_prim_channel::next_trigger(double, sc_time_unit, const sc_event &) +sc_prim_channel::next_trigger(double d, sc_time_unit u, const sc_event &e) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(d, u, e); } void -sc_prim_channel::next_trigger(const sc_time &, const sc_event_or_list &) +sc_prim_channel::next_trigger(const sc_time &t, const sc_event_or_list &eol) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(t, eol); } void -sc_prim_channel::next_trigger(double, sc_time_unit, const sc_event_or_list &) +sc_prim_channel::next_trigger( + double d, sc_time_unit u, const sc_event_or_list &eol) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(d, u, eol); } void -sc_prim_channel::next_trigger(const sc_time &, const sc_event_and_list &) +sc_prim_channel::next_trigger(const sc_time &t, const sc_event_and_list &eal) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(t, eal); } void -sc_prim_channel::next_trigger(double, sc_time_unit, const sc_event_and_list &) +sc_prim_channel::next_trigger( + double d, sc_time_unit u, const sc_event_and_list &eal) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::next_trigger(d, u, eal); } bool @@ -144,79 +140,79 @@ sc_prim_channel::timed_out() void sc_prim_channel::wait() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(); } void -sc_prim_channel::wait(int) +sc_prim_channel::wait(int i) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(i); } void -sc_prim_channel::wait(const sc_event &) +sc_prim_channel::wait(const sc_event &e) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(e); } void -sc_prim_channel::wait(const sc_event_or_list &) +sc_prim_channel::wait(const sc_event_or_list &eol) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(eol); } void -sc_prim_channel::wait(const sc_event_and_list &) +sc_prim_channel::wait(const sc_event_and_list &eal) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(eal); } void -sc_prim_channel::wait(const sc_time &) +sc_prim_channel::wait(const sc_time &t) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(t); } void -sc_prim_channel::wait(double, sc_time_unit) +sc_prim_channel::wait(double d, sc_time_unit u) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(d, u); } void -sc_prim_channel::wait(const sc_time &, const sc_event &) +sc_prim_channel::wait(const sc_time &t, const sc_event &e) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(t, e); } void -sc_prim_channel::wait(double, sc_time_unit, const sc_event &) +sc_prim_channel::wait(double d, sc_time_unit u, const sc_event &e) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(d, u, e); } void -sc_prim_channel::wait(const sc_time &, const sc_event_or_list &) +sc_prim_channel::wait(const sc_time &t, const sc_event_or_list &eol) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(t, eol); } void -sc_prim_channel::wait(double, sc_time_unit, const sc_event_or_list &) +sc_prim_channel::wait(double d, sc_time_unit u, const sc_event_or_list &eol) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(d, u, eol); } void -sc_prim_channel::wait(const sc_time &, const sc_event_and_list &) +sc_prim_channel::wait(const sc_time &t, const sc_event_and_list &eal) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(t, eal); } void -sc_prim_channel::wait(double, sc_time_unit, const sc_event_and_list &) +sc_prim_channel::wait(double d, sc_time_unit u, const sc_event_and_list &eal) { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + ::sc_core::wait(d, u, eal); } } // namespace sc_core diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc index 41c64f876..17e7dc43e 100644 --- a/src/systemc/core/scheduler.cc +++ b/src/systemc/core/scheduler.cc @@ -30,31 +30,22 @@ #include "systemc/core/scheduler.hh" #include "base/fiber.hh" +#include "base/logging.hh" +#include "sim/eventq.hh" namespace sc_gem5 { -Scheduler::Scheduler() : _numCycles(0), _current(nullptr) {} +Scheduler::Scheduler() : + eq(nullptr), readyEvent(this, false, EventBase::Default_Pri + 1), + _numCycles(0), _current(nullptr) +{} void -Scheduler::initialize() +Scheduler::initToReady() { - update(); - while (!initList.empty()) ready(initList.getNext()); - - delta(); -} - -void -Scheduler::runCycles() -{ - while (!readyList.empty()) { - evaluate(); - update(); - delta(); - } } void @@ -77,24 +68,62 @@ Scheduler::yield() } void -Scheduler::evaluate() +Scheduler::ready(Process *p) { - if (!readyList.empty()) - _numCycles++; + // Clump methods together to minimize context switching. + if (p->procKind() == ::sc_core::SC_METHOD_PROC_) + readyList.pushFirst(p); + else + readyList.pushLast(p); - do { - yield(); - } while (!readyList.empty()); + scheduleReadyEvent(); } void -Scheduler::update() +Scheduler::requestUpdate(Channel *c) { + updateList.pushLast(c); + scheduleReadyEvent(); } void -Scheduler::delta() +Scheduler::scheduleReadyEvent() { + // Schedule the evaluate and update phases. + if (!readyEvent.scheduled()) { + panic_if(!eq, "Need to schedule ready, but no event manager.\n"); + eq->schedule(&readyEvent, eq->getCurTick()); + } +} + +void +Scheduler::runReady() +{ + bool empty = readyList.empty(); + + // The evaluation phase. + do { + yield(); + } while (!readyList.empty()); + + if (!empty) + _numCycles++; + + // The update phase. + update(); + + // The delta phase will happen naturally through the event queue. +} + +void +Scheduler::update() +{ + Channel *channel = updateList.getNext(); + while (channel) { + channel->popListNode(); + channel->update(); + channel = updateList.getNext(); + } } Scheduler scheduler; diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh index a7216231a..e1ad21a57 100644 --- a/src/systemc/core/scheduler.hh +++ b/src/systemc/core/scheduler.hh @@ -30,6 +30,8 @@ #ifndef __SYSTEMC_CORE_SCHEDULER_HH__ #define __SYSTEMC_CORE_SCHEDULER_HH__ +#include "sim/eventq.hh" +#include "systemc/core/channel.hh" #include "systemc/core/list.hh" #include "systemc/core/process.hh" @@ -37,20 +39,84 @@ namespace sc_gem5 { typedef NodeList<Process> ProcessList; +typedef NodeList<Channel> ChannelList; + +/* + * The scheduler supports three different mechanisms, the initialization phase, + * delta cycles, and timed notifications. + * + * INITIALIZATION PHASE + * + * The initialization phase has three parts: + * 1. Run requested channel updates. + * 2. Make processes which need to initialize runnable (methods and threads + * which didn't have dont_initialize called on them). + * 3. Process delta notifications. + * + * First, the Kernel SimObject calls the update() method during its startup() + * callback which handles the requested channel updates. The Kernel also + * schedules an event to be run at time 0 with a slightly elevated priority + * so that it happens before any "normal" event. + * + * When that t0 event happens, it calls the schedulers initToReady method + * which performs step 2 above. That indirectly causes the scheduler's + * readyEvent to be scheduled with slightly lowered priority, ensuring it + * happens after any "normal" event. + * + * Because delta notifications are scheduled at the standard priority, all + * of those events will happen next, performing step 3 above. Once they finish, + * if the readyEvent was scheduled above, there shouldn't be any higher + * priority events in front of it. When it runs, it will start the first + * evaluate phase of the first delta cycle. + * + * DELTA CYCLE + * + * A delta cycle has three phases within it. + * 1. The evaluate phase where runnable processes are allowed to run. + * 2. The update phase where requested channel updates hapen. + * 3. The delta notification phase where delta notifications happen. + * + * The readyEvent runs the first two steps of the delta cycle. It first goes + * through the list of runnable processes and executes them until the set is + * empty, and then immediately runs the update phase. Since these are all part + * of the same event, there's no chance for other events to intervene and + * break the required order above. + * + * During the update phase above, the spec forbids any action which would make + * a process runnable. That means that once the update phase finishes, the set + * of runnable processes will be empty. There may, however, have been some + * delta notifications/timeouts which will have been scheduled during either + * the evaluate or update phase above. Because those are scheduled at the + * normal priority, they will now happen together until there aren't any + * delta events left. + * + * If any processes became runnable during the delta notification phase, the + * readyEvent will have been scheduled and will have been waiting patiently + * behind the delta notification events. That will now run, effectively + * starting the next delta cycle. + * + * TIMED NOTIFICATION PHASE + * + * If no processes became runnable, the event queue will continue to process + * events until it comes across a timed notification, aka a notification + * scheduled to happen in the future. Like delta notification events, those + * will all happen together since the readyEvent priority is lower, + * potentially marking new processes as ready. Once these events finish, the + * readyEvent may run, starting the next delta cycle. + */ class Scheduler { public: Scheduler(); + const std::string name() const { return "systemc_scheduler"; } + uint64_t numCycles() { return _numCycles; } Process *current() { return _current; } - // Run the initialization phase. - void initialize(); - - // Run delta cycles until time needs to advance. - void runCycles(); + // Mark processes that need to be initialized as ready. + void initToReady(); // Put a process on the list of processes to be initialized. void init(Process *p) { initList.pushLast(p); } @@ -59,15 +125,10 @@ class Scheduler void yield(); // Put a process on the ready list. - void - ready(Process *p) - { - // Clump methods together to minimize context switching. - if (p->procKind() == ::sc_core::SC_METHOD_PROC_) - readyList.pushFirst(p); - else - readyList.pushLast(p); - } + void ready(Process *p); + + // Schedule an update for a given channel. + void requestUpdate(Channel *c); // Run the given process immediately, preempting whatever may be running. void @@ -81,7 +142,22 @@ class Scheduler yield(); } + // Set an event queue for scheduling events. + void setEventQueue(EventQueue *_eq) { eq = _eq; } + + // Retrieve the event queue. + EventQueue &eventQueue() const { return *eq; } + + // Run scheduled channel updates. + void update(); + private: + EventQueue *eq; + + void runReady(); + EventWrapper<Scheduler, &Scheduler::runReady> readyEvent; + void scheduleReadyEvent(); + uint64_t _numCycles; Process *_current; @@ -89,9 +165,7 @@ class Scheduler ProcessList initList; ProcessList readyList; - void evaluate(); - void update(); - void delta(); + ChannelList updateList; }; extern Scheduler scheduler; diff --git a/src/systemc/ext/core/sc_prim.hh b/src/systemc/ext/core/sc_prim.hh index 2348f453d..106489280 100644 --- a/src/systemc/ext/core/sc_prim.hh +++ b/src/systemc/ext/core/sc_prim.hh @@ -33,6 +33,13 @@ #include "sc_object.hh" #include "sc_time.hh" +namespace sc_gem5 +{ + +class Channel; + +} // namespace sc_gem5 + namespace sc_core { @@ -43,12 +50,12 @@ class sc_event_or_list; class sc_prim_channel : public sc_object { public: - virtual const char *kind() const; + virtual const char *kind() const { return "sc_prim_channel"; } protected: sc_prim_channel(); explicit sc_prim_channel(const char *); - virtual ~sc_prim_channel() {} + virtual ~sc_prim_channel(); void request_update(); void async_request_update(); @@ -93,6 +100,9 @@ class sc_prim_channel : public sc_object // Disabled sc_prim_channel(const sc_prim_channel &); sc_prim_channel &operator = (const sc_prim_channel &); + + friend class sc_gem5::Channel; + sc_gem5::Channel *_gem5_channel; }; } // namespace sc_core |