summaryrefslogtreecommitdiff
path: root/util/systemc/sc_module.cc
diff options
context:
space:
mode:
authorAndrew Bardsley <Andrew.Bardsley@arm.com>2014-12-02 06:08:09 -0500
committerAndrew Bardsley <Andrew.Bardsley@arm.com>2014-12-02 06:08:09 -0500
commite5e5b80690f736c65c9b51ef96660637210f3938 (patch)
tree4c2f6422209fd55e2c97bcb48689c5091c000072 /util/systemc/sc_module.cc
parent05bba75cdc346184da7ff40958673da980a06df2 (diff)
downloadgem5-e5e5b80690f736c65c9b51ef96660637210f3938.tar.xz
config: Fix to SystemC example's event handling
This patch fixes checkpoint restore in the SystemC hosting example by handling early PollEvent events correctly before any EventQueue events are posted. The SystemC event queue handler (SCEventQueue) reports an error if the event loop is entered with no Events posted. It is possible for this to happen after instantiate due to PollEvent events. This patch separates out `external' events into a different handler in sc_module.cc to prevent the error from occurring. This fix also improves the event handling of asynchronous events by: 1) Making asynchronous events 'catch up' gem5 time to SystemC time to avoid the appearance that events have been lost while servicing an asynchronous event that schedules an event loop exit event 2) Add an in_simulate data member to Module to allow the event loop to check whether events should be processed or deferred until the next time Module::simulate is entered 3) Cancel pending events around the entry/exit of the event loop in Module::simulate 4) Moving the state initialisation of the example entirely into run to correct a problem with early events in checkpoint restore. It is still possible to schedule asynchronous events (and talk PollQueue actions) while simulate is not running. This behaviour may stil cause some problems.
Diffstat (limited to 'util/systemc/sc_module.cc')
-rw-r--r--util/systemc/sc_module.cc81
1 files changed, 73 insertions, 8 deletions
diff --git a/util/systemc/sc_module.cc b/util/systemc/sc_module.cc
index d9e049607..a47df8194 100644
--- a/util/systemc/sc_module.cc
+++ b/util/systemc/sc_module.cc
@@ -76,10 +76,14 @@ setTickFrequency()
::setClockFrequency(1000000000000);
}
-Module::Module(sc_core::sc_module_name name) : sc_core::sc_module(name)
+Module::Module(sc_core::sc_module_name name) : sc_core::sc_module(name),
+ in_simulate(false)
{
SC_METHOD(eventLoop);
sensitive << eventLoopEnterEvent;
+ dont_initialize();
+
+ SC_METHOD(serviceExternalEvent);
sensitive << externalSchedulingEvent;
dont_initialize();
}
@@ -95,12 +99,38 @@ Module::SCEventQueue::wakeup(Tick when)
void
Module::setupEventQueues(Module &module)
{
+ fatal_if(mainEventQueue.size() != 0,
+ "Gem5SystemC::Module::setupEventQueues must be called"
+ " before any gem5 event queues are set up");
+
numMainEventQueues = 1;
mainEventQueue.push_back(new SCEventQueue("events", module));
curEventQueue(getEventQueue(0));
}
void
+Module::catchup()
+{
+ EventQueue *eventq = getEventQueue(0);
+ Tick systemc_time = sc_core::sc_time_stamp().value();
+ Tick gem5_time = curTick();
+
+ /* gem5 time *must* lag SystemC as SystemC is the master */
+ fatal_if(gem5_time > systemc_time, "gem5 time must lag SystemC time"
+ " gem5: %d SystemC: %d", gem5_time, systemc_time);
+
+ eventq->setCurTick(systemc_time);
+
+ if (!eventq->empty()) {
+ Tick next_event_time M5_VAR_USED = eventq->nextTick();
+
+ fatal_if(gem5_time > next_event_time,
+ "Missed an event at time %d gem5: %d, SystemC: %d",
+ next_event_time, gem5_time, systemc_time);
+ }
+}
+
+void
Module::notify(sc_core::sc_time time_from_now)
{
externalSchedulingEvent.notify(time_from_now);
@@ -109,8 +139,17 @@ Module::notify(sc_core::sc_time time_from_now)
void
Module::serviceAsyncEvent()
{
+ EventQueue *eventq = getEventQueue(0);
+
assert(async_event);
+ /* Catch up gem5 time with SystemC time so that any event here won't
+ * be in the past relative to the current time */
+ Tick systemc_time = sc_core::sc_time_stamp().value();
+
+ /* Move time on to match SystemC */
+ catchup();
+
async_event = false;
if (async_statdump || async_statreset) {
Stats::schedStatEvent(async_statdump, async_statreset);
@@ -133,22 +172,37 @@ Module::serviceAsyncEvent()
}
void
+Module::serviceExternalEvent()
+{
+ EventQueue *eventq = getEventQueue(0);
+
+ if (!in_simulate && !async_event)
+ warn("Gem5SystemC external event received while not in simulate");
+
+ if (async_event)
+ serviceAsyncEvent();
+
+ if (in_simulate && !eventq->empty())
+ eventLoop();
+}
+
+void
Module::eventLoop()
{
EventQueue *eventq = getEventQueue(0);
+ fatal_if(!in_simulate, "Gem5SystemC event loop entered while"
+ " outside Gem5SystemC::Module::simulate");
+
if (async_event)
serviceAsyncEvent();
while (!eventq->empty()) {
Tick next_event_time = eventq->nextTick();
- Tick systemc_time = sc_core::sc_time_stamp().value();
-
- /* gem5 time *must* lag SystemC as SystemC is the master */
- assert(curTick() <= systemc_time);
/* Move time on to match SystemC */
- eventq->setCurTick(systemc_time);
+ catchup();
+
Tick gem5_time = curTick();
/* Woken up early */
@@ -171,6 +225,8 @@ Module::eventLoop()
return;
} else if (gem5_time > next_event_time) {
+ Tick systemc_time = sc_core::sc_time_stamp().value();
+
/* Missed event, for some reason the above test didn't work
* or an event was scheduled in the past */
fatal("Missed an event at time %d gem5: %d, SystemC: %d",
@@ -180,7 +236,7 @@ Module::eventLoop()
exitEvent = eventq->serviceOne();
if (exitEvent) {
- eventLoopExitEvent.notify();
+ eventLoopExitEvent.notify(sc_core::SC_ZERO_TIME);
return;
}
}
@@ -192,7 +248,7 @@ Module::eventLoop()
GlobalSimLoopExitEvent *
Module::simulate(Tick num_cycles)
{
- inform("Entering event queue @ %d. Starting simulation...\n", curTick());
+ inform("Entering event queue @ %d. Starting simulation...", curTick());
if (num_cycles < MaxTick - curTick())
num_cycles = curTick() + num_cycles;
@@ -204,6 +260,11 @@ Module::simulate(Tick num_cycles)
exitEvent = NULL;
+ /* Cancel any outstanding events */
+ eventLoopExitEvent.cancel();
+ externalSchedulingEvent.cancel();
+
+ in_simulate = true;
eventLoopEnterEvent.notify(sc_core::SC_ZERO_TIME);
/* Wait for event queue to exit, guarded by exitEvent just incase
@@ -212,6 +273,10 @@ Module::simulate(Tick num_cycles)
if (!exitEvent)
wait(eventLoopExitEvent);
+ /* Cancel any outstanding event loop entries */
+ eventLoopEnterEvent.cancel();
+ in_simulate = false;
+
/* Locate the global exit event */
BaseGlobalEvent *global_event = exitEvent->globalEvent();
assert(global_event != NULL);