diff options
Diffstat (limited to 'util/systemc/sc_module.cc')
-rw-r--r-- | util/systemc/sc_module.cc | 231 |
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; +} + +} |