diff options
Diffstat (limited to 'src/systemc')
-rw-r--r-- | src/systemc/core/process.cc | 8 | ||||
-rw-r--r-- | src/systemc/core/process.hh | 7 | ||||
-rw-r--r-- | src/systemc/core/process_types.hh | 4 | ||||
-rw-r--r-- | src/systemc/core/sc_main.cc | 34 | ||||
-rw-r--r-- | src/systemc/core/scheduler.cc | 84 | ||||
-rw-r--r-- | src/systemc/core/scheduler.hh | 60 |
6 files changed, 170 insertions, 27 deletions
diff --git a/src/systemc/core/process.cc b/src/systemc/core/process.cc index 63d2ff94b..7ed187fe1 100644 --- a/src/systemc/core/process.cc +++ b/src/systemc/core/process.cc @@ -277,7 +277,6 @@ Process::finalize() void Process::run() { - _running = true; bool reset; do { reset = false; @@ -287,7 +286,7 @@ Process::run() reset = exc.is_reset(); } } while (reset); - _running = false; + _terminated = true; } void @@ -323,9 +322,10 @@ Process::ready() scheduler.ready(this); } -Process::Process(const char *name, ProcessFuncWrapper *func, bool _dynamic) : +Process::Process(const char *name, ProcessFuncWrapper *func, + bool _dynamic, bool needs_start) : ::sc_core::sc_object(name), excWrapper(nullptr), func(func), - _running(false), _dynamic(_dynamic), _isUnwinding(false), + _needsStart(needs_start), _dynamic(_dynamic), _isUnwinding(false), _terminated(false), _suspended(false), _disabled(false), _syncReset(false), refCount(0), stackSize(::Fiber::DefaultStackSize), dynamicSensitivity(nullptr) diff --git a/src/systemc/core/process.hh b/src/systemc/core/process.hh index 579ea602f..7c75d6244 100644 --- a/src/systemc/core/process.hh +++ b/src/systemc/core/process.hh @@ -246,7 +246,7 @@ class Process : public ::sc_core::sc_object, public ListNode { public: virtual ::sc_core::sc_curr_proc_kind procKind() const = 0; - bool running() const { return _running; } + bool needsStart() const { return _needsStart; } bool dynamic() const { return _dynamic; } bool isUnwinding() const { return _isUnwinding; } bool terminated() const { return _terminated; } @@ -298,7 +298,8 @@ class Process : public ::sc_core::sc_object, public ListNode static Process *newest() { return _newest; } protected: - Process(const char *name, ProcessFuncWrapper *func, bool _dynamic); + Process(const char *name, ProcessFuncWrapper *func, bool _dynamic, + bool needs_start); static Process *_newest; @@ -314,7 +315,7 @@ class Process : public ::sc_core::sc_object, public ListNode ProcessFuncWrapper *func; sc_core::sc_curr_proc_kind _procKind; - bool _running; + bool _needsStart; bool _dynamic; bool _isUnwinding; bool _terminated; diff --git a/src/systemc/core/process_types.hh b/src/systemc/core/process_types.hh index 6d13592b6..369fa726e 100644 --- a/src/systemc/core/process_types.hh +++ b/src/systemc/core/process_types.hh @@ -40,7 +40,7 @@ class Method : public Process { public: Method(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) : - Process(name, func, _dynamic) + Process(name, func, _dynamic, true) {} const char *kind() const override { return "sc_method_process"; } @@ -56,7 +56,7 @@ class Thread : public Process { public: Thread(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) : - Process(name, func, _dynamic), ctx(nullptr) + Process(name, func, _dynamic, false), ctx(nullptr) {} ~Thread() { delete ctx; } diff --git a/src/systemc/core/sc_main.cc b/src/systemc/core/sc_main.cc index 0b385e9a0..120bbf9ae 100644 --- a/src/systemc/core/sc_main.cc +++ b/src/systemc/core/sc_main.cc @@ -123,9 +123,6 @@ EmbeddedPyBind embed_("systemc", &systemc_pybind); sc_stop_mode _stop_mode = SC_STOP_FINISH_DELTA; sc_status _status = SC_ELABORATION; -Tick _max_tick = MaxTick; -sc_starvation_policy _starvation = SC_EXIT_ON_STARVATION; - } // anonymous namespace int @@ -143,28 +140,29 @@ sc_argv() void sc_start() { - _max_tick = MaxTick; - _starvation = SC_EXIT_ON_STARVATION; - - // Switch back gem5. - Fiber::primaryFiber()->run(); + Tick now = curEventQueue() ? curEventQueue()->getCurTick() : 0; + sc_start(sc_time::from_value(MaxTick - now), SC_EXIT_ON_STARVATION); } void sc_pause() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + if (_status == SC_RUNNING) + ::sc_gem5::scheduler.schedulePause(); } void sc_start(const sc_time &time, sc_starvation_policy p) { + _status = SC_RUNNING; + Tick now = curEventQueue() ? curEventQueue()->getCurTick() : 0; - _max_tick = now + time.value(); - _starvation = p; + ::sc_gem5::scheduler.start(now + time.value(), p == SC_RUN_TO_TIME); - // Switch back to gem5. - Fiber::primaryFiber()->run(); + if (::sc_gem5::scheduler.paused()) + _status = SC_PAUSED; + else if (::sc_gem5::scheduler.stopped()) + _status = SC_STOPPED; } void @@ -187,7 +185,15 @@ sc_get_stop_mode() void sc_stop() { - warn("%s not implemented.\n", __PRETTY_FUNCTION__); + if (_status == SC_STOPPED) + return; + + if (sc_is_running()) { + bool finish_delta = (_stop_mode == SC_STOP_FINISH_DELTA); + ::sc_gem5::scheduler.scheduleStop(finish_delta); + } else { + //XXX Should stop if in one of the various elaboration callbacks. + } } const sc_time & diff --git a/src/systemc/core/scheduler.cc b/src/systemc/core/scheduler.cc index 230ed0af2..e3d275bb1 100644 --- a/src/systemc/core/scheduler.cc +++ b/src/systemc/core/scheduler.cc @@ -37,7 +37,12 @@ namespace sc_gem5 { Scheduler::Scheduler() : - eq(nullptr), readyEvent(this, false, EventBase::Default_Pri + 1), + eq(nullptr), _pendingCurr(0), _pendingFuture(0), + readyEvent(this, false, ReadyPriority), + pauseEvent(this, false, PausePriority), + stopEvent(this, false, StopPriority), + scMain(nullptr), _started(false), _paused(false), _stopped(false), + maxTickEvent(this, false, MaxTickPriority), _numCycles(0), _current(nullptr), initReady(false) {} @@ -54,6 +59,9 @@ Scheduler::prepareForInit() p->ready(); } + if (_started) + eq->schedule(&maxTickEvent, maxTick); + initReady = true; } @@ -98,9 +106,8 @@ Scheduler::yield() // Switch to whatever Fiber is supposed to run this process. All // Fibers which aren't running should be parked at this line. _current->fiber()->run(); - // If the current process hasn't been started yet, start it. This - // should always be true for methods, but may not be true for threads. - if (_current && !_current->running()) + // If the current process needs to be manually started, start it. + if (_current && _current->needsStart()) _current->run(); } } @@ -164,6 +171,75 @@ Scheduler::update() } } +void +Scheduler::pause() +{ + _paused = true; + scMain->run(); +} + +void +Scheduler::stop() +{ + _stopped = true; + scMain->run(); +} + +void +Scheduler::start(Tick max_tick, bool run_to_time) +{ + // We should be running from sc_main. Keep track of that Fiber to return + // to later. + scMain = Fiber::currentFiber(); + + _started = true; + _paused = false; + _stopped = false; + + maxTick = max_tick; + + if (initReady) + eq->schedule(&maxTickEvent, maxTick); + + // Return to gem5 to let it run events, etc. + Fiber::primaryFiber()->run(); + + if (pauseEvent.scheduled()) + eq->deschedule(&pauseEvent); + if (stopEvent.scheduled()) + eq->deschedule(&stopEvent); + if (maxTickEvent.scheduled()) + eq->deschedule(&maxTickEvent); +} + +void +Scheduler::schedulePause() +{ + if (pauseEvent.scheduled()) + return; + + eq->schedule(&pauseEvent, eq->getCurTick()); +} + +void +Scheduler::scheduleStop(bool finish_delta) +{ + if (stopEvent.scheduled()) + return; + + if (!finish_delta) { + // If we're not supposed to finish the delta cycle, flush the list + // of ready processes and scheduled updates. + Process *p; + while ((p = readyList.getNext())) + p->popListNode(); + Channel *c; + while ((c = updateList.getNext())) + c->popListNode(); + } + eq->schedule(&stopEvent, eq->getCurTick()); +} + Scheduler scheduler; } // namespace sc_gem5 diff --git a/src/systemc/core/scheduler.hh b/src/systemc/core/scheduler.hh index aa8ec9aa4..5db5556ae 100644 --- a/src/systemc/core/scheduler.hh +++ b/src/systemc/core/scheduler.hh @@ -32,11 +32,14 @@ #include <vector> +#include "base/logging.hh" #include "sim/eventq.hh" #include "systemc/core/channel.hh" #include "systemc/core/list.hh" #include "systemc/core/process.hh" +class Fiber; + namespace sc_gem5 { @@ -105,6 +108,32 @@ typedef NodeList<Channel> ChannelList; * 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. + * + * PAUSE/STOP + * + * To inject a pause from sc_pause which should happen after the current delta + * cycle's delta notification phase, an event is scheduled with a lower than + * normal priority, but higher than the readyEvent. That ensures that any + * delta notifications which are scheduled with normal priority will happen + * first, since those are part of the current delta cycle. Then the pause + * event will happen before the next readyEvent which would start the next + * delta cycle. All of these events are scheduled for the current time, and so + * would happen before any timed notifications went off. + * + * To inject a stop from sc_stop, the delta cycles should stop before even the + * delta notifications have happened, but after the evaluate and update phases. + * For that, a stop event with slightly higher than normal priority will be + * scheduled so that it happens before any of the delta notification events + * which are at normal priority. + * + * MAX RUN TIME + * + * When sc_start is called, it's possible to pass in a maximum time the + * simulation should run to, at which point sc_pause is implicitly called. + * That's implemented by scheduling an event at the max time with a priority + * which is lower than all the others so that it happens only if time would + * advance. When that event triggers, it calls the same function as the pause + * event. */ class Scheduler @@ -156,13 +185,44 @@ class Scheduler // Run scheduled channel updates. void update(); + void setScMainFiber(Fiber *sc_main) { scMain = sc_main; } + + void start(Tick max_tick, bool run_to_time); + + void schedulePause(); + void scheduleStop(bool finish_delta); + + bool paused() { return _paused; } + bool stopped() { return _stopped; } + private: + typedef const EventBase::Priority Priority; + static Priority DefaultPriority = EventBase::Default_Pri; + + static Priority StopPriority = DefaultPriority - 1; + static Priority PausePriority = DefaultPriority + 1; + static Priority ReadyPriority = DefaultPriority + 2; + static Priority MaxTickPriority = DefaultPriority + 3; + EventQueue *eq; void runReady(); EventWrapper<Scheduler, &Scheduler::runReady> readyEvent; void scheduleReadyEvent(); + void pause(); + void stop(); + EventWrapper<Scheduler, &Scheduler::pause> pauseEvent; + EventWrapper<Scheduler, &Scheduler::stop> stopEvent; + Fiber *scMain; + + bool _started; + bool _paused; + bool _stopped; + + Tick maxTick; + EventWrapper<Scheduler, &Scheduler::pause> maxTickEvent; + uint64_t _numCycles; Process *_current; |