summaryrefslogtreecommitdiff
path: root/src/systemc/core/scheduler.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemc/core/scheduler.hh')
-rw-r--r--src/systemc/core/scheduler.hh108
1 files changed, 91 insertions, 17 deletions
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;