232 lines
7.2 KiB
C++
232 lines
7.2 KiB
C++
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|
||
|
}
|