summaryrefslogtreecommitdiff
path: root/util/systemc/sc_module.cc
diff options
context:
space:
mode:
Diffstat (limited to 'util/systemc/sc_module.cc')
-rw-r--r--util/systemc/sc_module.cc231
1 files changed, 231 insertions, 0 deletions
diff --git a/util/systemc/sc_module.cc b/util/systemc/sc_module.cc
new file mode 100644
index 000000000..d9e049607
--- /dev/null
+++ b/util/systemc/sc_module.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2013 Advanced Micro Devices, Inc.
+ * Copyright (c) 2013 Mark D. Hill and David A. Wood
+ * All rights reserved.
+ *
+ * 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: Nathan Binkert
+ * Steve Reinhardt
+ * Andrew Bardsley
+ */
+
+/**
+ * @file
+ *
+ * Defines an sc_module type to wrap a gem5 simulation. The 'evaluate'
+ * thread on that module implements the gem5 event loop.
+ *
+ * This currently only supports a single event queue and strictly
+ * cooperatively threaded SystemC threads and so there should be at
+ * most one Gem5Module instantiated in any simulation.
+ */
+
+#include "base/pollevent.hh"
+#include "base/trace.hh"
+#include "debug/Event.hh"
+#include "sim/async.hh"
+#include "sim/core.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_exit.hh"
+#include "sim/stat_control.hh"
+#include "sc_module.hh"
+
+namespace Gem5SystemC
+{
+
+/** There are assumptions throughout Gem5SystemC file that a tick is 1ps.
+ * Make this the case */
+void
+setTickFrequency()
+{
+ ::setClockFrequency(1000000000000);
+}
+
+Module::Module(sc_core::sc_module_name name) : sc_core::sc_module(name)
+{
+ SC_METHOD(eventLoop);
+ sensitive << eventLoopEnterEvent;
+ sensitive << externalSchedulingEvent;
+ dont_initialize();
+}
+
+void
+Module::SCEventQueue::wakeup(Tick when)
+{
+ DPRINTF(Event, "waking up SCEventQueue\n");
+ /* Don't bother to use 'when' for now */
+ module.notify();
+}
+
+void
+Module::setupEventQueues(Module &module)
+{
+ numMainEventQueues = 1;
+ mainEventQueue.push_back(new SCEventQueue("events", module));
+ curEventQueue(getEventQueue(0));
+}
+
+void
+Module::notify(sc_core::sc_time time_from_now)
+{
+ externalSchedulingEvent.notify(time_from_now);
+}
+
+void
+Module::serviceAsyncEvent()
+{
+ assert(async_event);
+
+ async_event = false;
+ if (async_statdump || async_statreset) {
+ Stats::schedStatEvent(async_statdump, async_statreset);
+ async_statdump = false;
+ async_statreset = false;
+ }
+
+ if (async_exit) {
+ async_exit = false;
+ exitSimLoop("user interrupt received");
+ }
+
+ if (async_io) {
+ async_io = false;
+ pollQueue.service();
+ }
+
+ if (async_exception)
+ fatal("received async_exception, shouldn't be possible");
+}
+
+void
+Module::eventLoop()
+{
+ EventQueue *eventq = getEventQueue(0);
+
+ 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);
+ Tick gem5_time = curTick();
+
+ /* Woken up early */
+ if (wait_exit_time > sc_core::sc_time_stamp().value()) {
+ DPRINTF(Event, "Woken up early\n");
+ wait_exit_time = sc_core::sc_time_stamp().value();
+ }
+
+ if (gem5_time < next_event_time) {
+ Tick wait_period = next_event_time - gem5_time;
+ wait_exit_time = gem5_time + wait_period;
+
+ DPRINTF(Event, "Waiting for %d ticks for next gem5 event\n",
+ wait_period);
+
+ /* The next event is scheduled in the future, wait until
+ * then or until externalSchedulingEvent */
+ eventLoopEnterEvent.notify(sc_core::sc_time(
+ sc_dt::uint64(wait_period), 0));
+
+ return;
+ } else if (gem5_time > next_event_time) {
+ /* 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",
+ next_event_time, gem5_time, systemc_time);
+ } else {
+ /* Service an event */
+ exitEvent = eventq->serviceOne();
+
+ if (exitEvent) {
+ eventLoopExitEvent.notify();
+ return;
+ }
+ }
+ }
+
+ fatal("Ran out of events without seeing exit event");
+}
+
+GlobalSimLoopExitEvent *
+Module::simulate(Tick num_cycles)
+{
+ inform("Entering event queue @ %d. Starting simulation...\n", curTick());
+
+ if (num_cycles < MaxTick - curTick())
+ num_cycles = curTick() + num_cycles;
+ else /* counter would roll over or be set to MaxTick anyhow */
+ num_cycles = MaxTick;
+
+ GlobalEvent *limit_event = new GlobalSimLoopExitEvent(num_cycles,
+ "simulate() limit reached", 0, 0);
+
+ exitEvent = NULL;
+
+ eventLoopEnterEvent.notify(sc_core::SC_ZERO_TIME);
+
+ /* Wait for event queue to exit, guarded by exitEvent just incase
+ * it already has exited and we don't want to completely rely
+ * on notify semantics */
+ if (!exitEvent)
+ wait(eventLoopExitEvent);
+
+ /* Locate the global exit event */
+ BaseGlobalEvent *global_event = exitEvent->globalEvent();
+ assert(global_event != NULL);
+
+ GlobalSimLoopExitEvent *global_exit_event =
+ dynamic_cast<GlobalSimLoopExitEvent *>(global_event);
+ assert(global_exit_event != NULL);
+
+ if (global_exit_event != limit_event) {
+ limit_event->deschedule();
+ delete limit_event;
+ }
+
+ return global_exit_event;
+}
+
+}